diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 8b8e4a760eb9b..7be13ad34a66d 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -103,17 +103,20 @@ end has_offset_axes(A, B, ...) Return `true` if the indices of `A` start with something other than 1 along any axis. -If multiple arguments are passed, equivalent to `has_offset_axes(A) | has_offset_axes(B) | ...`. +If multiple arguments are passed, equivalent to `has_offset_axes(A) || has_offset_axes(B) || ...`. See also [`require_one_based_indexing`](@ref). """ +has_offset_axes() = false has_offset_axes(A) = _any_tuple(x->Int(first(x))::Int != 1, false, axes(A)...) has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges) -# Use `_any_tuple` to avoid unneeded invoke. -# note: this could call `any` directly if the compiler can infer it -has_offset_axes(As...) = _any_tuple(has_offset_axes, false, As...) has_offset_axes(::Colon) = false has_offset_axes(::Array) = false +# note: this could call `any` directly if the compiler can infer it. We don't use _any_tuple +# here because it stops full elision in some cases (#49332) and we don't need handling of +# `missing` (has_offset_axes(A) always returns a Bool) +has_offset_axes(A, As...) = has_offset_axes(A) || has_offset_axes(As...) + """ require_one_based_indexing(A::AbstractArray) diff --git a/base/threadingconstructs.jl b/base/threadingconstructs.jl index a5a1294be049b..e202bb0acb317 100644 --- a/base/threadingconstructs.jl +++ b/base/threadingconstructs.jl @@ -44,8 +44,9 @@ maxthreadid() = Int(Core.Intrinsics.atomic_pointerref(cglobal(:jl_n_threads, Cin """ Threads.nthreads(:default | :interactive) -> Int -Get the current number of threads within the specified thread pool. The threads in default -have id numbers `1:nthreads(:default)`. +Get the current number of threads within the specified thread pool. The threads in `:interactive` +have id numbers `1:nthreads(:interactive)`, and the threads in `:default` have id numbers in +`nthreads(:interactive) .+ (1:nthreads(:default))`. See also `BLAS.get_num_threads` and `BLAS.set_num_threads` in the [`LinearAlgebra`](@ref man-linalg) standard library, and `nprocs()` in the [`Distributed`](@ref man-distributed) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 20353d25ff9d3..e8291b1081df2 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -406,13 +406,13 @@ transpose(A::UnitLowerTriangular) = UnitUpperTriangular(transpose(A.data)) transpose(A::UnitUpperTriangular) = UnitLowerTriangular(transpose(A.data)) transpose!(A::LowerTriangular) = UpperTriangular(copytri!(A.data, 'L', false, true)) -transpose!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L', false, true)) +transpose!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L', false, false)) transpose!(A::UpperTriangular) = LowerTriangular(copytri!(A.data, 'U', false, true)) -transpose!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U', false, true)) +transpose!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U', false, false)) adjoint!(A::LowerTriangular) = UpperTriangular(copytri!(A.data, 'L' , true, true)) -adjoint!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L' , true, true)) +adjoint!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L' , true, false)) adjoint!(A::UpperTriangular) = LowerTriangular(copytri!(A.data, 'U' , true, true)) -adjoint!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U' , true, true)) +adjoint!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U' , true, false)) diag(A::LowerTriangular) = diag(A.data) diag(A::UnitLowerTriangular) = fill(oneunit(eltype(A)), size(A,1)) @@ -471,7 +471,7 @@ end function _triscale!(A::UpperTriangular, B::UpperTriangular, c::Number, _add) n = checksquare(B) - iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta) + iszero(_add.alpha) && return _rmul_or_fill!(A, _add.beta) for j = 1:n for i = 1:j @inbounds _modify!(_add, B.data[i,j] * c, A.data, (i,j)) @@ -481,8 +481,8 @@ function _triscale!(A::UpperTriangular, B::UpperTriangular, c::Number, _add) end function _triscale!(A::UpperTriangular, c::Number, B::UpperTriangular, _add) n = checksquare(B) - iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta) - for j = 1:n + iszero(_add.alpha) && return _rmul_or_fill!(A, _add.beta) +for j = 1:n for i = 1:j @inbounds _modify!(_add, c * B.data[i,j], A.data, (i,j)) end @@ -491,7 +491,7 @@ function _triscale!(A::UpperTriangular, c::Number, B::UpperTriangular, _add) end function _triscale!(A::UpperOrUnitUpperTriangular, B::UnitUpperTriangular, c::Number, _add) n = checksquare(B) - iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta) + iszero(_add.alpha) && return _rmul_or_fill!(A, _add.beta) for j = 1:n @inbounds _modify!(_add, c, A, (j,j)) for i = 1:(j - 1) @@ -502,7 +502,7 @@ function _triscale!(A::UpperOrUnitUpperTriangular, B::UnitUpperTriangular, c::Nu end function _triscale!(A::UpperOrUnitUpperTriangular, c::Number, B::UnitUpperTriangular, _add) n = checksquare(B) - iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta) + iszero(_add.alpha) && return _rmul_or_fill!(A, _add.beta) for j = 1:n @inbounds _modify!(_add, c, A, (j,j)) for i = 1:(j - 1) @@ -513,7 +513,7 @@ function _triscale!(A::UpperOrUnitUpperTriangular, c::Number, B::UnitUpperTriang end function _triscale!(A::LowerTriangular, B::LowerTriangular, c::Number, _add) n = checksquare(B) - iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta) + iszero(_add.alpha) && return _rmul_or_fill!(A, _add.beta) for j = 1:n for i = j:n @inbounds _modify!(_add, B.data[i,j] * c, A.data, (i,j)) @@ -523,8 +523,8 @@ function _triscale!(A::LowerTriangular, B::LowerTriangular, c::Number, _add) end function _triscale!(A::LowerTriangular, c::Number, B::LowerTriangular, _add) n = checksquare(B) - iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta) - for j = 1:n + iszero(_add.alpha) && return _rmul_or_fill!(A, _add.beta) + for j = 1:n for i = j:n @inbounds _modify!(_add, c * B.data[i,j], A.data, (i,j)) end @@ -533,7 +533,7 @@ function _triscale!(A::LowerTriangular, c::Number, B::LowerTriangular, _add) end function _triscale!(A::LowerOrUnitLowerTriangular, B::UnitLowerTriangular, c::Number, _add) n = checksquare(B) - iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta) + iszero(_add.alpha) && return _rmul_or_fill!(A, _add.beta) for j = 1:n @inbounds _modify!(_add, c, A, (j,j)) for i = (j + 1):n @@ -544,7 +544,7 @@ function _triscale!(A::LowerOrUnitLowerTriangular, B::UnitLowerTriangular, c::Nu end function _triscale!(A::LowerOrUnitLowerTriangular, c::Number, B::UnitLowerTriangular, _add) n = checksquare(B) - iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta) + iszero(_add.alpha) && return _rmul_or_fill!(A, _add.beta) for j = 1:n @inbounds _modify!(_add, c, A, (j,j)) for i = (j + 1):n diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index aaf433c95b7b0..759f89f6f7220 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -18,7 +18,7 @@ debug && println("Test basic type functionality") @test LowerTriangular(randn(3, 3)) |> t -> [size(t, i) for i = 1:3] == [size(Matrix(t), i) for i = 1:3] # The following test block tries to call all methods in base/linalg/triangular.jl in order for a combination of input element types. Keep the ordering when adding code. -for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFloat}, Int) +@testset for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFloat}, Int) # Begin loop for first Triangular matrix for (t1, uplo1) in ((UpperTriangular, :U), (UnitUpperTriangular, :U), @@ -239,6 +239,11 @@ for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFlo A2tmp = unitt(A1) mul!(A1tmp, cr, A2tmp) @test A1tmp == cr * A2tmp + + A1tmp .= A1 + @test mul!(A1tmp, A2tmp, cr, 0, 2) == 2A1 + A1tmp .= A1 + @test mul!(A1tmp, cr, A2tmp, 0, 2) == 2A1 else A1tmp = copy(A1) rmul!(A1tmp, ci) @@ -866,4 +871,12 @@ end end end +@testset "transpose triangular diagonal" begin + M = Matrix{BigFloat}(undef, 2, 2); + M[1,2] = 3; + U = UnitUpperTriangular(M) + Ut = transpose(U) + @test transpose!(U) == Ut +end + end # module TestTriangular diff --git a/stdlib/Mmap/src/Mmap.jl b/stdlib/Mmap/src/Mmap.jl index 629f53e8371ed..9dd02d5aa9d04 100644 --- a/stdlib/Mmap/src/Mmap.jl +++ b/stdlib/Mmap/src/Mmap.jl @@ -208,18 +208,43 @@ function mmap(io::IO, mmaplen = (offset - offset_page) + len file_desc = gethandle(io) + szfile = convert(Csize_t, len + offset) + requestedSizeLarger = false + if !(io isa Mmap.Anonymous) + @static if !Sys.isapple() + requestedSizeLarger = szfile > filesize(io) + end + end # platform-specific mmapping @static if Sys.isunix() prot, flags, iswrite = settings(file_desc, shared) - iswrite && grow && grow!(io, offset, len) + if requestedSizeLarger + if iswrite + if grow + grow!(io, offset, len) + else + throw(ArgumentError("requested size $szfile larger than file size $(filesize(io)), but requested not to grow")) + end + else + throw(ArgumentError("unable to increase file size to $szfile due to read-only permissions")) + end + end + @static if Sys.isapple() + iswrite && grow && grow!(io, offset, len) + end # mmap the file ptr = ccall(:jl_mmap, Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t, Cint, Cint, RawFD, Int64), C_NULL, mmaplen, prot, flags, file_desc, offset_page) systemerror("memory mapping failed", reinterpret(Int, ptr) == -1) else name, readonly, create = settings(io) - szfile = convert(Csize_t, len + offset) - readonly && szfile > filesize(io) && throw(ArgumentError("unable to increase file size to $szfile due to read-only permissions")) + if requestedSizeLarger + if readonly + throw(ArgumentError("unable to increase file size to $szfile due to read-only permissions")) + elseif !grow + throw(ArgumentError("requested size $szfile larger than file size $(filesize(io)), but requested not to grow")) + end + end handle = create ? ccall(:CreateFileMappingW, stdcall, Ptr{Cvoid}, (OS_HANDLE, Ptr{Cvoid}, DWORD, DWORD, DWORD, Cwstring), file_desc, C_NULL, readonly ? PAGE_READONLY : PAGE_READWRITE, szfile >> 32, szfile & typemax(UInt32), name) : ccall(:OpenFileMappingW, stdcall, Ptr{Cvoid}, (DWORD, Cint, Cwstring), diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 729334feed7c9..58382e9c10d75 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -980,7 +980,10 @@ function project_deps_get_completion_candidates(pkgstarts::String, project_file: return Completion[PackageCompletion(name) for name in loading_candidates] end -function complete_identifiers!(suggestions::Vector{Completion}, @nospecialize(ffunc::Function), context_module::Module, string::String, name::String, pos::Int, dotpos::Int, startpos::Int, comp_keywords=false) +function complete_identifiers!(suggestions::Vector{Completion}, @nospecialize(ffunc), + context_module::Module, string::String, name::String, + pos::Int, dotpos::Int, startpos::Int; + comp_keywords=false) ex = nothing if comp_keywords append!(suggestions, complete_keyword(name)) @@ -1022,10 +1025,41 @@ function complete_identifiers!(suggestions::Vector{Completion}, @nospecialize(ff if something(findlast(in(non_identifier_chars), s), 0) < something(findlast(isequal('.'), s), 0) lookup_name, name = rsplit(s, ".", limit=2) name = String(name) - ex = Meta.parse(lookup_name, raise=false, depwarn=false) end isexpr(ex, :incomplete) && (ex = nothing) + elseif isexpr(ex, (:using, :import)) + arg1 = ex.args[1] + if isexpr(arg1, :.) + # We come here for cases like: + # - `string`: "using Mod1.Mod2.M" + # - `ex`: :(using Mod1.Mod2) + # - `name`: "M" + # Now we transform `ex` to `:(Mod1.Mod2)` to allow `complete_symbol` to + # complete for inner modules whose name starts with `M`. + # Note that `ffunc` is set to `module_filter` within `completions` + ex = nothing + firstdot = true + for arg = arg1.args + if arg === :. + # override `context_module` if multiple `.` accessors are used + if firstdot + firstdot = false + else + context_module = parentmodule(context_module) + end + elseif arg isa Symbol + if ex === nothing + ex = arg + else + ex = Expr(:., out, QuoteNode(arg)) + end + else # invalid expression + ex = nothing + break + end + end + end elseif isexpr(ex, :call) && length(ex.args) > 1 isinfix = s[end] != ')' # A complete call expression that does not finish with ')' is an infix call. @@ -1106,8 +1140,9 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif ok && return ret startpos = first(varrange) + 4 dotpos = something(findprev(isequal('.'), string, first(varrange)-1), 0) - return complete_identifiers!(Completion[], ffunc, context_module, string, - string[startpos:pos], pos, dotpos, startpos) + name = string[startpos:pos] + return complete_identifiers!(Completion[], ffunc, context_module, string, name, pos, + dotpos, startpos) elseif inc_tag === :cmd # TODO: should this call shell_completions instead of partially reimplementing it? let m = match(r"[\t\n\r\"`><=*?|]| (?!\\)", reverse(partial)) # fuzzy shell_parse in reverse @@ -1255,16 +1290,20 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif end end end - ffunc = (mod,x)->(Base.isbindingresolved(mod, x) && isdefined(mod, x) && isa(getfield(mod, x), Module)) + ffunc = module_filter comp_keywords = false end startpos == 0 && (pos = -1) dotpos < startpos && (dotpos = startpos - 1) - return complete_identifiers!(suggestions, ffunc, context_module, string, - name, pos, dotpos, startpos, comp_keywords) + return complete_identifiers!(suggestions, ffunc, context_module, string, name, pos, + dotpos, startpos; + comp_keywords) end +module_filter(mod::Module, x::Symbol) = + Base.isbindingresolved(mod, x) && isdefined(mod, x) && isa(getglobal(mod, x), Module) + function shell_completions(string, pos) # First parse everything up to the current position scs = string[1:pos] diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 56a96b5a1534c..ae29812c5f43e 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -1939,3 +1939,47 @@ let s = "@issue51827 Base.ac" @test res @test "acquire" in c end + +# JuliaLang/julia#52922 +let s = "using Base.Th" + c, r, res = test_complete_context(s) + @test res + @test "Threads" in c +end +let s = "using Base." + c, r, res = test_complete_context(s) + @test res + @test "BinaryPlatforms" in c +end +# test cases with the `.` accessor +module Issue52922 +module Inner1 +module Inner12 end +end +module Inner2 end +end +let s = "using .Iss" + c, r, res = test_complete_context(s) + @test res + @test "Issue52922" in c +end +let s = "using .Issue52922.Inn" + c, r, res = test_complete_context(s) + @test res + @test "Inner1" in c +end +let s = "using .Inner1.Inn" + c, r, res = test_complete_context(s, Issue52922) + @test res + @test "Inner12" in c +end +let s = "using ..Issue52922.Inn" + c, r, res = test_complete_context(s, Issue52922.Inner1) + @test res + @test "Inner2" in c +end +let s = "using ...Issue52922.Inn" + c, r, res = test_complete_context(s, Issue52922.Inner1.Inner12) + @test res + @test "Inner2" in c +end diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 8a74f90f2d553..6a60dac2e81e1 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -1825,13 +1825,17 @@ end @testset "type-based offset axes check" begin a = randn(ComplexF64, 10) + b = randn(ComplexF64, 4, 4, 4, 4) ta = reinterpret(Float64, a) tb = reinterpret(Float64, view(a, 1:2:10)) tc = reinterpret(Float64, reshape(view(a, 1:3:10), 2, 2, 1)) + td = view(b, :, :, 1, 1) # Issue #44040 @test IRUtils.fully_eliminated(Base.require_one_based_indexing, Base.typesof(ta, tc)) @test IRUtils.fully_eliminated(Base.require_one_based_indexing, Base.typesof(tc, tc)) @test IRUtils.fully_eliminated(Base.require_one_based_indexing, Base.typesof(ta, tc, tb)) + # Issue #49332 + @test IRUtils.fully_eliminated(Base.require_one_based_indexing, Base.typesof(td, td, td)) # Ranges && CartesianIndices @test IRUtils.fully_eliminated(Base.require_one_based_indexing, Base.typesof(1:10, Base.OneTo(10), 1.0:2.0, LinRange(1.0, 2.0, 2), 1:2:10, CartesianIndices((1:2:10, 1:2:10)))) # Remind us to call `any` in `Base.has_offset_axes` once our compiler is ready.