From b0f607a80715268e5be1f2fa6215e7c5e021dfd0 Mon Sep 17 00:00:00 2001 From: Michael Goerz Date: Mon, 4 Mar 2024 15:12:06 -0500 Subject: [PATCH 01/13] Add inventory writing via DocumenterInventoryWritingBackport (cherry picked from commit 2d1442fc29507e2d152f5f1ef34296eb41cffad2) --- doc/Manifest.toml | 60 +++++++++++++++++++++++++++++++++++++++++++---- doc/Project.toml | 1 + doc/make.jl | 1 + 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/doc/Manifest.toml b/doc/Manifest.toml index cf50a1d41ddbd..be49a18729b80 100644 --- a/doc/Manifest.toml +++ b/doc/Manifest.toml @@ -1,17 +1,26 @@ # This file is machine-generated - editing it directly is not advised -julia_version = "1.9.0-DEV" +julia_version = "1.10.2" manifest_format = "2.0" -project_hash = "e0c77beb18dc1f6cce661ebd60658c0c1a77390f" +project_hash = "94441cf327e3c2e23c216d2e7b11c5c833d323b9" [[deps.ANSIColoredPrinters]] git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" version = "0.0.1" +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + [[deps.Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" +[[deps.CodecZlib]] +deps = ["TranscodingStreams", "Zlib_jll"] +git-tree-sha1 = "59939d8a997469ee05c4b4944560a820f9ba0d73" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.4" + [[deps.Dates]] deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" @@ -28,6 +37,12 @@ git-tree-sha1 = "6030186b00a38e9d0434518627426570aac2ef95" uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" version = "0.27.23" +[[deps.DocumenterInventoryWritingBackport]] +deps = ["CodecZlib", "Documenter", "TOML"] +git-tree-sha1 = "1b89024e375353961bb98b9818b44a4e38961cc4" +uuid = "195adf08-069f-4855-af3e-8933a2cdae94" +version = "0.1.0" + [[deps.IOCapture]] deps = ["Logging", "Random"] git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a" @@ -45,9 +60,22 @@ uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" version = "0.21.3" [[deps.LibGit2]] -deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" +[[deps.LibGit2_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" +version = "1.6.4+0" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.11.0+1" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + [[deps.Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" @@ -55,6 +83,11 @@ uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+1" + [[deps.Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" @@ -77,7 +110,7 @@ deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [[deps.Random]] -deps = ["SHA", "Serialization"] +deps = ["SHA"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [[deps.SHA]] @@ -90,9 +123,28 @@ uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" [[deps.Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + [[deps.Test]] deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +[[deps.TranscodingStreams]] +git-tree-sha1 = "3caa21522e7efac1ba21834a03734c57b4611c7e" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.10.4" +weakdeps = ["Random", "Test"] + + [deps.TranscodingStreams.extensions] + TestExt = ["Test", "Random"] + [[deps.Unicode]] uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" diff --git a/doc/Project.toml b/doc/Project.toml index dfa65cd107d06..2f1addd369506 100644 --- a/doc/Project.toml +++ b/doc/Project.toml @@ -1,2 +1,3 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +DocumenterInventoryWritingBackport = "195adf08-069f-4855-af3e-8933a2cdae94" diff --git a/doc/make.jl b/doc/make.jl index 6bbc94b925b60..917c3989bc254 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -8,6 +8,7 @@ using Pkg Pkg.instantiate() using Documenter +using DocumenterInventoryWritingBackport baremodule GenStdLib end From 525b3a2d2b20259bcfe61bac658c684c7e85fa36 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Sat, 13 Apr 2024 22:07:01 +0200 Subject: [PATCH 02/13] Overload `Base.literal_pow` for `AbstractQ` (#54010) (cherry picked from commit b9aeafa171e13609b3d47f8a1d75d83c0148a991) --- stdlib/LinearAlgebra/src/abstractq.jl | 4 ++++ stdlib/LinearAlgebra/test/abstractq.jl | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/stdlib/LinearAlgebra/src/abstractq.jl b/stdlib/LinearAlgebra/src/abstractq.jl index b0d53320f4aa3..fd5324c769f09 100644 --- a/stdlib/LinearAlgebra/src/abstractq.jl +++ b/stdlib/LinearAlgebra/src/abstractq.jl @@ -18,6 +18,10 @@ transpose(Q::AbstractQ{<:Real}) = AdjointQ(Q) transpose(Q::AbstractQ) = error("transpose not implemented for $(typeof(Q)). Consider using adjoint instead of transpose.") adjoint(adjQ::AdjointQ) = adjQ.Q +(^)(Q::AbstractQ, p::Integer) = p < 0 ? power_by_squaring(inv(Q), -p) : power_by_squaring(Q, p) +@inline Base.literal_pow(::typeof(^), Q::AbstractQ, ::Val{1}) = Q +@inline Base.literal_pow(::typeof(^), Q::AbstractQ, ::Val{-1}) = inv(Q) + # promotion with AbstractMatrix, at least for equal eltypes promote_rule(::Type{<:AbstractMatrix{T}}, ::Type{<:AbstractQ{T}}) where {T} = (@inline; Union{AbstractMatrix{T},AbstractQ{T}}) diff --git a/stdlib/LinearAlgebra/test/abstractq.jl b/stdlib/LinearAlgebra/test/abstractq.jl index 19b872d685668..0eb88324e8c20 100644 --- a/stdlib/LinearAlgebra/test/abstractq.jl +++ b/stdlib/LinearAlgebra/test/abstractq.jl @@ -39,6 +39,12 @@ n = 5 @test Q'*I ≈ Q.Q'*I rtol=2eps(real(T)) @test I*Q ≈ Q.Q*I rtol=2eps(real(T)) @test I*Q' ≈ I*Q.Q' rtol=2eps(real(T)) + @test Q^3 ≈ Q*Q*Q + @test Q^2 ≈ Q*Q + @test Q^1 == Q + @test Q^(-1) == Q' + @test (Q')^(-1) == Q + @test (Q')^2 ≈ Q'*Q' @test abs(det(Q)) ≈ 1 @test logabsdet(Q)[1] ≈ 0 atol=2n*eps(real(T)) y = rand(T, n) From 58cf81ea7bb79401533795ac90f83e817c705bd3 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Mon, 22 Apr 2024 14:47:08 +0200 Subject: [PATCH 03/13] Fix `make install` from tarballs (#54143) This reverts part of 67b8ac0 (https://github.com/JuliaLang/julia/pull/47596#discussion_r1128658139). That change broke `make install` from tarballs due to building docs again, which fails as there's no git repo (and also requires Internet access to download UnicodeData.txt. Fixes #54037. (cherry picked from commit d6dda7c58552f0a8dfb7fb6d5441f69abdd1e99f) --- Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ba96b5c71697c..3991ced0f679b 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,10 @@ $(foreach link,base $(JULIAHOME)/test,$(eval $(call symlink_target,$(link),$$(bu julia_flisp.boot.inc.phony: julia-deps @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/src julia_flisp.boot.inc.phony +# Build the HTML docs (skipped if already exists, notably in tarballs) +$(BUILDROOT)/doc/_build/html/en/index.html: $(shell find $(BUILDROOT)/base $(BUILDROOT)/doc \( -path $(BUILDROOT)/doc/_build -o -path $(BUILDROOT)/doc/deps -o -name *_constants.jl -o -name *_h.jl -o -name version_git.jl \) -prune -o -type f -print) + @$(MAKE) docs + julia-symlink: julia-cli-$(JULIA_BUILD_MODE) ifeq ($(OS),WINNT) echo '@"%~dp0/'"$$(echo '$(call rel_path,$(BUILDROOT),$(JULIA_EXECUTABLE))')"'" %*' | tr / '\\' > $(BUILDROOT)/julia.bat @@ -265,7 +269,7 @@ define stringreplace endef -install: $(build_depsbindir)/stringreplace docs +install: $(build_depsbindir)/stringreplace $(BUILDROOT)/doc/_build/html/en/index.html @$(MAKE) $(QUIET_MAKE) $(JULIA_BUILD_MODE) @for subdir in $(bindir) $(datarootdir)/julia/stdlib/$(VERSDIR) $(docdir) $(man1dir) $(includedir)/julia $(libdir) $(private_libdir) $(sysconfdir) $(private_libexecdir); do \ mkdir -p $(DESTDIR)$$subdir; \ @@ -523,7 +527,7 @@ app: darwinframework: $(MAKE) -C $(JULIAHOME)/contrib/mac/framework -light-source-dist.tmp: docs +light-source-dist.tmp: $(BUILDROOT)/doc/_build/html/en/index.html ifneq ($(BUILDROOT),$(JULIAHOME)) $(error make light-source-dist does not work in out-of-tree builds) endif From 3577557f8076796220ffe23de93aaba3710da22e Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 23 Apr 2024 10:38:41 +0530 Subject: [PATCH 04/13] LinearAlgebra: Correct zero element in `_generic_matvecmul!` for block adj/trans (#54151) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following issue on master, where the zero element is computed incorrectly (but subsequent terms are computed correctly): ```julia julia> using LinearAlgebra julia> x = [1 2 3; 4 5 6]; julia> A = reshape([x,2x,3x,4x],2,2); julia> b = fill(x, 2); julia> A' * b ERROR: DimensionMismatch: matrix A has axes (Base.OneTo(2),Base.OneTo(3)), matrix B has axes (Base.OneTo(2),Base.OneTo(3)) Stacktrace: [1] _generic_matmatmul!(C::Matrix{Int64}, A::Matrix{Int64}, B::Matrix{Int64}, _add::LinearAlgebra.MulAddMul{true, true, Bool, Bool}) @ LinearAlgebra ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:849 [2] generic_matmatmul! @ ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:834 [inlined] [3] _mul! @ ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:287 [inlined] [4] mul! @ ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:285 [inlined] [5] mul! @ ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:253 [inlined] [6] * @ ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:114 [inlined] [7] _generic_matvecmul!(C::Vector{Matrix{…}}, tA::Char, A::Matrix{Matrix{…}}, B::Vector{Matrix{…}}, _add::LinearAlgebra.MulAddMul{true, true, Bool, Bool}) @ LinearAlgebra ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:797 [8] generic_matvecmul! @ ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:755 [inlined] [9] _mul! @ ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:73 [inlined] [10] mul! @ ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:70 [inlined] [11] mul! @ ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:253 [inlined] [12] *(A::Adjoint{Adjoint{Int64, Matrix{Int64}}, Matrix{Matrix{Int64}}}, x::Vector{Matrix{Int64}}) @ LinearAlgebra ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/LinearAlgebra/src/matmul.jl:60 [13] top-level scope @ REPL[10]:1 Some type information was truncated. Use `show(err)` to see complete types. ``` After this PR, ```julia julia> A' * b 2-element Vector{Matrix{Int64}}: [51 66 81; 66 87 108; 81 108 135] [119 154 189; 154 203 252; 189 252 315] ``` (cherry picked from commit 2b878f009a8771bacc1a71c20b337940c1e9009e) --- stdlib/LinearAlgebra/src/matmul.jl | 6 ++++-- stdlib/LinearAlgebra/test/matmul.jl | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 018ad20e538c8..5994c95851827 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -711,7 +711,8 @@ function _generic_matvecmul!(C::AbstractVector, tA, A::AbstractVecOrMat, B::Abst else for k = 1:mA aoffs = (k-1)*Astride - s = zero(A[aoffs + 1]*B[1] + A[aoffs + 1]*B[1]) + firstterm = transpose(A[aoffs + 1])*B[1] + s = zero(firstterm + firstterm) for i = 1:nA s += transpose(A[aoffs+i]) * B[i] end @@ -726,7 +727,8 @@ function _generic_matvecmul!(C::AbstractVector, tA, A::AbstractVecOrMat, B::Abst else for k = 1:mA aoffs = (k-1)*Astride - s = zero(A[aoffs + 1]*B[1] + A[aoffs + 1]*B[1]) + firstterm = A[aoffs + 1]'B[1] + s = zero(firstterm + firstterm) for i = 1:nA s += A[aoffs + i]'B[i] end diff --git a/stdlib/LinearAlgebra/test/matmul.jl b/stdlib/LinearAlgebra/test/matmul.jl index 86606654e911a..0c6e421b3968b 100644 --- a/stdlib/LinearAlgebra/test/matmul.jl +++ b/stdlib/LinearAlgebra/test/matmul.jl @@ -209,6 +209,18 @@ end end end +@testset "generic_matvecmul for vectors of matrices" begin + x = [1 2 3; 4 5 6] + A = reshape([x,2x,3x,4x],2,2) + b = [x, 2x] + for f in (adjoint, transpose) + c = f(A) * b + for i in eachindex(c) + @test c[i] == sum(f(A)[i, j] * b[j] for j in eachindex(b)) + end + end +end + @testset "generic_matmatmul for matrices of vectors" begin B = Matrix{Vector{Int}}(undef, 2, 2) B[1, 1] = [1, 2] From 1de708b88f997f758a7d98c1cee6153dca4469f5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 25 Apr 2024 08:31:13 -0400 Subject: [PATCH 05/13] set MAX_OS_WRITE on unix (#54233) Fixes #54225 (cherry picked from commit b35d3083e10b2161dfcd33a5546fbdbd88d8b25c) --- base/stream.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/stream.jl b/base/stream.jl index 22af8d59359f3..1635f3c5ad22a 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -122,7 +122,7 @@ const DEFAULT_READ_BUFFER_SZ = 10485760 # 10 MB if Sys.iswindows() const MAX_OS_WRITE = UInt(0x1FF0_0000) # 511 MB (determined semi-empirically, limited to 31 MB on XP) else - const MAX_OS_WRITE = UInt(typemax(Csize_t)) + const MAX_OS_WRITE = UInt(0x7FFF_0000) # almost 2 GB (both macOS and linux have this kernel restriction, although only macOS documents it) end From f752249335177d5d15b6d71d568cbc7049aec4a2 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 26 Apr 2024 13:50:30 -0300 Subject: [PATCH 06/13] fix typo in gc_mark_memory8 when chunking a large array (#54251) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Should fix https://github.com/JuliaLang/julia/issues/54247. - Before: ``` Julia Version 1.12.0-DEV.410 Commit 0735854ab3* (2024-04-25 14:35 UTC) Platform Info: OS: macOS (arm64-apple-darwin23.4.0) CPU: 12 × Apple M2 Max WORD_SIZE: 64 LLVM: libLLVM-16.0.6 (ORCJIT, apple-m2) Threads: 8 default, 0 interactive, 4 GC (on 8 virtual cores) ***** Vector ***** serial: 0.607365 seconds (3 allocations: 381.470 MiB, 0.22% gc time) serial: 0.597241 seconds (3 allocations: 381.470 MiB, 1.18% gc time) serial: 0.589679 seconds (3 allocations: 381.470 MiB, 1.21% gc time) serial: 0.581607 seconds (3 allocations: 381.470 MiB, 0.97% gc time) serial: 0.578147 seconds (3 allocations: 381.470 MiB, 0.96% gc time) serial: 0.577399 seconds (3 allocations: 381.470 MiB, 0.94% gc time) serial: 0.564742 seconds (3 allocations: 381.470 MiB, 0.93% gc time) serial: 0.591733 seconds (3 allocations: 381.470 MiB, 0.90% gc time) serial: 0.565088 seconds (3 allocations: 381.470 MiB, 0.97% gc time) serial: 0.556800 seconds (3 allocations: 381.470 MiB, 0.94% gc time) parallel: 0.563600 seconds (3.33 k allocations: 381.640 MiB, 0.10% gc time, 0.94% compilation time) parallel: 0.564652 seconds (9 allocations: 381.470 MiB, 1.02% gc time) parallel: 0.581996 seconds (9 allocations: 381.470 MiB, 0.95% gc time) parallel: 0.576503 seconds (9 allocations: 381.470 MiB, 0.90% gc time) parallel: 0.565595 seconds (9 allocations: 381.470 MiB, 0.94% gc time) parallel: 0.575850 seconds (9 allocations: 381.470 MiB, 0.95% gc time) parallel: 0.604621 seconds (9 allocations: 381.470 MiB, 0.91% gc time) parallel: 0.578168 seconds (9 allocations: 381.470 MiB, 0.91% gc time) parallel: 0.600408 seconds (9 allocations: 381.470 MiB, 0.92% gc time) parallel: 0.576794 seconds (9 allocations: 381.470 MiB, 0.95% gc time) ***** Astruct ***** serial: 0.659020 seconds (3 allocations: 762.940 MiB, 0.18% gc time) serial: 0.674630 seconds (3 allocations: 762.940 MiB, 1.63% gc time) serial: 0.670532 seconds (3 allocations: 762.940 MiB, 1.86% gc time) serial: 0.682483 seconds (3 allocations: 762.940 MiB, 1.57% gc time) serial: 0.673673 seconds (3 allocations: 762.940 MiB, 1.62% gc time) serial: 0.652506 seconds (3 allocations: 762.940 MiB, 1.72% gc time) serial: 0.667336 seconds (3 allocations: 762.940 MiB, 1.69% gc time) serial: 0.659686 seconds (3 allocations: 762.940 MiB, 1.76% gc time) serial: 0.673387 seconds (3 allocations: 762.940 MiB, 1.73% gc time) serial: 0.668930 seconds (3 allocations: 762.940 MiB, 1.67% gc time) parallel: 0.646382 seconds (3.42 k allocations: 763.114 MiB, 0.09% gc time, 0.77% compilation time) parallel: 0.665347 seconds (9 allocations: 762.940 MiB, 1.70% gc time) parallel: 0.676490 seconds (9 allocations: 762.940 MiB, 1.84% gc time) parallel: 22.732728 seconds (9 allocations: 762.940 MiB, 97.12% gc time) parallel: 22.668091 seconds (9 allocations: 762.940 MiB, 97.15% gc time) parallel: 0.629117 seconds (9 allocations: 762.940 MiB) parallel: 22.948883 seconds (9 allocations: 762.940 MiB, 97.26% gc time) parallel: 0.629834 seconds (9 allocations: 762.940 MiB) parallel: 1.108239 seconds (9 allocations: 762.940 MiB, 42.54% gc time) parallel: 0.648325 seconds (9 allocations: 762.940 MiB) ``` - After: ``` Julia Version 1.12.0-DEV.410 Commit 0735854ab3* (2024-04-25 14:35 UTC) Platform Info: OS: macOS (arm64-apple-darwin23.4.0) CPU: 12 × Apple M2 Max WORD_SIZE: 64 LLVM: libLLVM-16.0.6 (ORCJIT, apple-m2) Threads: 8 default, 0 interactive, 4 GC (on 8 virtual cores) ***** Vector ***** serial: 0.600418 seconds (3 allocations: 381.470 MiB, 0.20% gc time) serial: 0.613808 seconds (3 allocations: 381.470 MiB, 1.17% gc time) serial: 0.596335 seconds (3 allocations: 381.470 MiB, 1.21% gc time) serial: 0.589423 seconds (3 allocations: 381.470 MiB, 0.92% gc time) serial: 0.621845 seconds (3 allocations: 381.470 MiB, 0.89% gc time) serial: 0.580239 seconds (3 allocations: 381.470 MiB, 0.94% gc time) serial: 0.604881 seconds (3 allocations: 381.470 MiB, 0.90% gc time) serial: 0.581353 seconds (3 allocations: 381.470 MiB, 0.95% gc time) serial: 0.603317 seconds (3 allocations: 381.470 MiB, 0.89% gc time) serial: 0.599634 seconds (3 allocations: 381.470 MiB, 0.90% gc time) parallel: 0.589694 seconds (3.33 k allocations: 381.640 MiB, 0.10% gc time, 1.01% compilation time) parallel: 0.600812 seconds (9 allocations: 381.470 MiB, 0.98% gc time) parallel: 0.610956 seconds (9 allocations: 381.470 MiB, 5.13% gc time) parallel: 0.677189 seconds (9 allocations: 381.470 MiB, 14.26% gc time) parallel: 0.571583 seconds (9 allocations: 381.470 MiB, 1.80% gc time) parallel: 0.742617 seconds (9 allocations: 381.470 MiB, 17.81% gc time) parallel: 0.624541 seconds (9 allocations: 381.470 MiB, 5.02% gc time) parallel: 0.723963 seconds (9 allocations: 381.470 MiB, 14.03% gc time) parallel: 0.609618 seconds (9 allocations: 381.470 MiB) parallel: 0.708227 seconds (9 allocations: 381.470 MiB, 16.29% gc time) ***** Astruct ***** serial: 0.627853 seconds (3 allocations: 762.940 MiB) serial: 0.647795 seconds (3 allocations: 762.940 MiB, 2.14% gc time) serial: 0.640387 seconds (3 allocations: 762.940 MiB, 1.91% gc time) serial: 0.698194 seconds (3 allocations: 762.940 MiB, 1.73% gc time) serial: 0.673018 seconds (3 allocations: 762.940 MiB, 1.68% gc time) serial: 0.641571 seconds (3 allocations: 762.940 MiB, 1.79% gc time) serial: 0.669718 seconds (3 allocations: 762.940 MiB, 1.65% gc time) serial: 0.661993 seconds (3 allocations: 762.940 MiB, 1.73% gc time) serial: 0.661846 seconds (3 allocations: 762.940 MiB, 1.85% gc time) serial: 0.661637 seconds (3 allocations: 762.940 MiB, 1.73% gc time) parallel: 0.645750 seconds (3.42 k allocations: 763.114 MiB, 0.09% gc time, 0.83% compilation time) parallel: 0.653331 seconds (9 allocations: 762.940 MiB, 1.92% gc time) parallel: 0.673813 seconds (9 allocations: 762.940 MiB, 1.80% gc time) parallel: 0.720503 seconds (9 allocations: 762.940 MiB, 9.40% gc time) parallel: 0.889651 seconds (9 allocations: 762.940 MiB, 25.33% gc time) parallel: 0.644618 seconds (9 allocations: 762.940 MiB, 2.26% gc time) parallel: 0.919954 seconds (9 allocations: 762.940 MiB, 28.99% gc time) parallel: 0.750246 seconds (9 allocations: 762.940 MiB, 9.03% gc time) parallel: 0.767282 seconds (9 allocations: 762.940 MiB, 10.55% gc time) parallel: 0.899596 seconds (9 allocations: 762.940 MiB, 25.69% gc time) ``` (cherry picked from commit dc0a4779a8fa9e4150e246fcf46c36b3acce1ce9) --- src/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 0a456eced511e..d577c42d4859b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -2052,7 +2052,7 @@ STATIC_INLINE void gc_mark_array8(jl_ptls_t ptls, jl_value_t *ary8_parent, jl_va pushed_chunk = 1; } } - for (; ary8_begin < ary8_end; ary8_begin += elsize) { + for (; ary8_begin < scan_end; ary8_begin += elsize) { for (uint8_t *pindex = elem_begin; pindex < elem_end; pindex++) { jl_value_t **slot = &ary8_begin[*pindex]; new_obj = *slot; From 1b21830d2c6eea88338a56b3bc7424b41eafc0fd Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Tue, 7 May 2024 11:26:34 +0800 Subject: [PATCH 07/13] typeintersect: fix another stack overflow caused by circular constraints (#54363) The added MWE has been broken since 1.8. The intersect result still looks quite unsoundness, but at least stack overflow get fixed. close #54356 (cherry picked from commit e47fedd49369eaeafd2dc3d3a3ebf89db80586ce) --- src/subtype.c | 24 +++++++++++++----------- test/subtype.jl | 13 ++++++++++--- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/subtype.c b/src/subtype.c index 10d2f19ae3209..16ec800b5c8f2 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -1301,6 +1301,8 @@ static int subtype_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, in return ans; } +static int try_subtype_by_bounds(jl_value_t *a, jl_value_t *b, jl_stenv_t *e); + // `param` means we are currently looking at a parameter of a type constructor // (as opposed to being outside any type constructor, or comparing variable bounds). // this is used to record the positions where type variables occur for the @@ -1351,7 +1353,8 @@ static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param) if (yy) record_var_occurrence(yy, e, param); if (yr) { record_var_occurrence(xx, e, param); - return subtype(xx->lb, yy->ub, e, 0); + int trysub = e->intersection ? try_subtype_by_bounds(xx->lb, yy->ub, e) : 0; + return trysub || subtype(xx->lb, yy->ub, e, 0); } return var_lt((jl_tvar_t*)x, y, e, param); } @@ -2483,7 +2486,7 @@ static jl_value_t *bound_var_below(jl_tvar_t *tv, jl_varbinding_t *bb, jl_stenv_ static int subtype_by_bounds(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) JL_NOTSAFEPOINT; -// similar to `subtype_by_bounds`, used to avoid stack-overflow caused by circulation constraints. +// similar to `subtype_by_bounds`, used to avoid stack-overflow caused by circular constraints. static int try_subtype_by_bounds(jl_value_t *a, jl_value_t *b, jl_stenv_t *e) { if (jl_is_uniontype(a)) @@ -2492,22 +2495,21 @@ static int try_subtype_by_bounds(jl_value_t *a, jl_value_t *b, jl_stenv_t *e) else if (jl_is_uniontype(b)) return try_subtype_by_bounds(a, ((jl_uniontype_t *)b)->a, e) || try_subtype_by_bounds(a, ((jl_uniontype_t *)b)->b, e); - else if (jl_egal(a, b)) + else if (a == jl_bottom_type || b == (jl_value_t *)jl_any_type || obviously_egal(a, b)) return 1; else if (!jl_is_typevar(b)) return 0; - jl_varbinding_t *vb = e->vars; - while (vb != NULL) { - if (subtype_by_bounds(b, (jl_value_t *)vb->var, e) && obviously_in_union(a, vb->ub)) - return 1; - vb = vb->prev; - } - return 0; + else if (jl_is_typevar(a) && subtype_by_bounds(a, b, e)) + return 1; + // check if `Union{a, ...} <: b`. + jl_varbinding_t *vb = lookup(e, (jl_tvar_t *)b); + jl_value_t *blb = vb ? vb->lb : ((jl_tvar_t *)b)->lb; + return obviously_in_union(a, blb); } static int try_subtype_in_env(jl_value_t *a, jl_value_t *b, jl_stenv_t *e) { - if (a == jl_bottom_type || b == (jl_value_t *)jl_any_type || try_subtype_by_bounds(a, b, e)) + if (try_subtype_by_bounds(a, b, e)) return 1; jl_savedenv_t se; save_env(e, &se, 1); diff --git a/test/subtype.jl b/test/subtype.jl index 3245e0583cda8..fffe5a3031fed 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -2327,9 +2327,10 @@ T46784{B<:Val, M<:AbstractMatrix} = Tuple{<:Union{B, <:Val{<:B}}, M, Union{Abstr #issue 36185 let S = Tuple{Type{T},Array{Union{T,Missing},N}} where {T,N}, T = Tuple{Type{T},Array{Union{T,Nothing},N}} where {T,N} - @testintersect(S, T, !Union{}) - @test_broken typeintersect(S, T) != S - @test_broken typeintersect(T, S) != T + I = typeintersect(S, T) + @test I == typeintersect(T, S) != Union{} + @test_broken I <: S + @test_broken I <: T end #issue 46736 @@ -2597,3 +2598,9 @@ let S = Type{T53371{A, B, C, D, E}} where {A, B<:R53371{A}, C<:R53371{A}, D<:R53 T = Type{T53371{A, B, C, D, E} where {A, B<:R53371{A}, C<:R53371{A}, D<:R53371{A}, E<:R53371{A}}} @test !(S <: T) end + +#issue 54356 +let S = Tuple{Val{Val{Union{Val{A2}, A2}}}, Val{Val{Union{Val{A2}, Val{A4}, A4}}}} where {A2, A4<:Union{Val{A2}, A2}}, + T = Tuple{Vararg{Val{V}}} where {V} + @testintersect(S, T, !Union{}) +end From e1b209931c68b01278e761e07062091fa259bb29 Mon Sep 17 00:00:00 2001 From: Florian Date: Fri, 17 May 2024 20:24:09 +0200 Subject: [PATCH 08/13] Fix an off-by-one error in interpreter's `do_invoke` (#54443) --- src/interpreter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interpreter.c b/src/interpreter.c index d84a1381fccad..570fda51a989b 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -135,10 +135,10 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state JL_GC_PUSHARGS(argv, nargs - 1); size_t i; for (i = 1; i < nargs; i++) - argv[i] = eval_value(args[i], s); + argv[i-1] = eval_value(args[i], s); jl_method_instance_t *meth = (jl_method_instance_t*)args[0]; assert(jl_is_method_instance(meth)); - jl_value_t *result = jl_invoke(argv[1], &argv[2], nargs - 2, meth); + jl_value_t *result = jl_invoke(argv[0], nargs == 2 ? NULL : &argv[1], nargs - 2, meth); JL_GC_POP(); return result; } From 94bef5df035198caf96af0d71bbeaed4b3d8219e Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Wed, 22 May 2024 12:24:23 -0600 Subject: [PATCH 09/13] Make TestLogger thread-safe (introduce a lock) (#54497) Fixes https://github.com/JuliaLang/julia/issues/54439. - Lock around concurrent accesses to .logs, .message_limits, and .shouldlog_args. - Copy the vector out of the logger at the end, to shield against dangling Tasks. Before: ```julia julia> Threads.nthreads() 8 julia> function foo(n) @info "Doing foo with n=$n" @sync for i=1:n Threads.@spawn @info "Iteration $i" end 42 end foo (generic function with 1 method) julia> for _ in 1:1000 @test_logs (:info,"Doing foo with n=10000") match_mode=:any foo(10_000) end julia+RAI(56155,0x1f5157ac0) malloc: double free for ptr 0x128248000 julia+RAI(56155,0x1f5157ac0) malloc: *** set a breakpoint in malloc_error_break to debug [56155] signal (6): Abort trap: 6 in expression starting at REPL[8]:1 signal (6) thread (1) __pthread_kill at /usr/lib/system/libsystem_kernel.dylib (unknown line) Allocations: 54370881 (Pool: 54363911; Big: 6970); GC: 119 [1] 56154 abort julia -tauto ``` After: ```julia julia> Threads.nthreads() 8 julia> function foo(n) @info "Doing foo with n=$n" @sync for i=1:n Threads.@spawn @info "Iteration $i" end 42 end foo (generic function with 1 method) julia> for _ in 1:1000 @test_logs (:info,"Doing foo with n=10000") match_mode=:any foo(10_000) end ``` (no crash) :) (cherry picked from commit 0437210b2834146396f1dac75c062932bd8f471a) --- stdlib/Test/src/logging.jl | 42 +++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/stdlib/Test/src/logging.jl b/stdlib/Test/src/logging.jl index 7b3838903ce10..8df7b016a8944 100644 --- a/stdlib/Test/src/logging.jl +++ b/stdlib/Test/src/logging.jl @@ -2,6 +2,7 @@ using Logging: Logging, AbstractLogger, LogLevel, Info, with_logger import Base: occursin +using Base: @lock #------------------------------------------------------------------------------- """ @@ -35,11 +36,15 @@ struct Ignored ; end #------------------------------------------------------------------------------- # Logger with extra test-related state mutable struct TestLogger <: AbstractLogger - logs::Vector{LogRecord} + lock::ReentrantLock + logs::Vector{LogRecord} # Guarded by lock. min_level::LogLevel catch_exceptions::Bool - shouldlog_args - message_limits::Dict{Any,Int} + # Note: shouldlog_args only maintains the info for the most recent log message, which + # may not be meaningful in a multithreaded program. See: + # https://github.com/JuliaLang/julia/pull/54497#discussion_r1603691606 + shouldlog_args # Guarded by lock. + message_limits::Dict{Any,Int} # Guarded by lock. respect_maxlog::Bool end @@ -80,15 +85,17 @@ Test Passed ``` """ TestLogger(; min_level=Info, catch_exceptions=false, respect_maxlog=true) = - TestLogger(LogRecord[], min_level, catch_exceptions, nothing, Dict{Any, Int}(), respect_maxlog) + TestLogger(ReentrantLock(), LogRecord[], min_level, catch_exceptions, nothing, Dict{Any, Int}(), respect_maxlog) Logging.min_enabled_level(logger::TestLogger) = logger.min_level function Logging.shouldlog(logger::TestLogger, level, _module, group, id) - if get(logger.message_limits, id, 1) > 0 - logger.shouldlog_args = (level, _module, group, id) - true - else - false + @lock logger.lock begin + if get(logger.message_limits, id, 1) > 0 + logger.shouldlog_args = (level, _module, group, id) + return true + else + return false + end end end @@ -98,12 +105,17 @@ function Logging.handle_message(logger::TestLogger, level, msg, _module, if logger.respect_maxlog maxlog = get(kwargs, :maxlog, nothing) if maxlog isa Core.BuiltinInts - remaining = get!(logger.message_limits, id, Int(maxlog)::Int) - logger.message_limits[id] = remaining - 1 - remaining > 0 || return + @lock logger.lock begin + remaining = get!(logger.message_limits, id, Int(maxlog)::Int) + logger.message_limits[id] = remaining - 1 + remaining > 0 || return + end end end - push!(logger.logs, LogRecord(level, msg, _module, group, id, file, line, kwargs)) + r = LogRecord(level, msg, _module, group, id, file, line, kwargs) + @lock logger.lock begin + push!(logger.logs, r) + end end # Catch exceptions for the test logger only if specified @@ -112,7 +124,9 @@ Logging.catch_exceptions(logger::TestLogger) = logger.catch_exceptions function collect_test_logs(f; kwargs...) logger = TestLogger(; kwargs...) value = with_logger(f, logger) - logger.logs, value + @lock logger.lock begin + return copy(logger.logs), value + end end From 7eeeb56a83cb9810f5124e50ae553ca718fd26f1 Mon Sep 17 00:00:00 2001 From: Tianyi Pu <44583944+putianyi889@users.noreply.github.com> Date: Fri, 24 May 2024 23:55:33 +0100 Subject: [PATCH 10/13] Add a missing doc (#53796) (cherry picked from commit 0c65f6ffde9b555b0fd04c54411e287b63ff98a4) --- doc/src/base/math.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/base/math.md b/doc/src/base/math.md index 62368424629c6..1b6b415b1d616 100644 --- a/doc/src/base/math.md +++ b/doc/src/base/math.md @@ -70,6 +70,7 @@ Base.Math.tand Base.Math.sincosd Base.Math.sinpi Base.Math.cospi +Base.Math.tanpi Base.Math.sincospi Base.sinh(::Number) Base.cosh(::Number) From 007d8ded0900ed626304ae99abe7366257ac1892 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 28 May 2024 11:34:27 -0300 Subject: [PATCH 11/13] Set storage class of julia globals to dllimport on windows to avoid auto-import weirdness (#54572) Fixes https://github.com/JuliaLang/julia/issues/54550 on 1.10. Master will require a similar but different PR. Co-authored-by: Keno Fischer Co-authored-by: Cody Tapscott <84105208+topolarity@users.noreply.github.com> --- Make.inc | 2 +- base/linking.jl | 2 +- cli/Makefile | 3 +-- src/aotcompile.cpp | 18 +++++++++++------- src/codegen.cpp | 8 ++++---- src/staticdata.c | 6 +++--- sysimage.mk | 2 +- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/Make.inc b/Make.inc index 021508e620cd1..85ef1efded2f9 100644 --- a/Make.inc +++ b/Make.inc @@ -1365,7 +1365,7 @@ ifeq ($(OS), WINNT) HAVE_SSP := 1 OSLIBS += -Wl,--export-all-symbols -Wl,--version-script=$(BUILDROOT)/src/julia.expmap \ $(NO_WHOLE_ARCHIVE) -lpsapi -lkernel32 -lws2_32 -liphlpapi -lwinmm -ldbghelp -luserenv -lsecur32 -latomic -JLDFLAGS += -Wl,--stack,8388608 +JLDFLAGS += -Wl,--stack,8388608 --disable-auto-import --disable-runtime-pseudo-reloc ifeq ($(ARCH),i686) JLDFLAGS += -Wl,--large-address-aware endif diff --git a/base/linking.jl b/base/linking.jl index 2d68ea730c0fb..4bf0198962346 100644 --- a/base/linking.jl +++ b/base/linking.jl @@ -110,7 +110,7 @@ function ld() # LLD supports mingw style linking flavor = "gnu" m = Sys.ARCH == :x86_64 ? "i386pep" : "i386pe" - default_args = `-m $m -Bdynamic --enable-auto-image-base --allow-multiple-definition` + default_args = `-m $m -Bdynamic --enable-auto-image-base --allow-multiple-definition --disable-auto-import --disable-runtime-pseudo-reloc` elseif Sys.isapple() flavor = "darwin" arch = Sys.ARCH == :aarch64 ? :arm64 : Sys.ARCH diff --git a/cli/Makefile b/cli/Makefile index 911e8ff54e246..e269e9205f496 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -17,8 +17,7 @@ LOADER_CFLAGS += -DGLIBCXX_LEAST_VERSION_SYMBOL=\"$(shell echo "$(CSL_NEXT_GLIBC endif ifeq ($(OS),WINNT) -LOADER_LDFLAGS += -municode -mconsole -nostdlib --disable-auto-import \ - --disable-runtime-pseudo-reloc -lntdll -lkernel32 -lpsapi +LOADER_LDFLAGS += -municode -mconsole -nostdlib -lntdll -lkernel32 -lpsapi else ifeq ($(OS),Linux) LOADER_LDFLAGS += -Wl,--no-as-needed -ldl -lpthread -rdynamic -lc -Wl,--as-needed else ifeq ($(OS),FreeBSD) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index e2a2fb20b419f..7b3d80061413b 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -1166,6 +1166,8 @@ static void materializePreserved(Module &M, Partition &partition) { GV.setInitializer(nullptr); GV.setLinkage(GlobalValue::ExternalLinkage); GV.setVisibility(GlobalValue::HiddenVisibility); + if (GV.getDLLStorageClass() != GlobalValue::DLLStorageClassTypes::DefaultStorageClass) + continue; // Don't mess with exported or imported globals GV.setDSOLocal(true); } @@ -1645,6 +1647,7 @@ void jl_dump_native_impl(void *native_code, if (jl_small_typeof_copy) { jl_small_typeof_copy->setVisibility(GlobalValue::HiddenVisibility); jl_small_typeof_copy->setDSOLocal(true); + jl_small_typeof_copy->setDLLStorageClass(GlobalValue::DLLStorageClassTypes::DefaultStorageClass); } } @@ -1673,16 +1676,17 @@ void jl_dump_native_impl(void *native_code, // reflect the address of the jl_RTLD_DEFAULT_handle variable // back to the caller, so that we can check for consistency issues GlobalValue *jlRTLD_DEFAULT_var = jl_emit_RTLD_DEFAULT_var(&metadataM); - addComdat(new GlobalVariable(metadataM, - jlRTLD_DEFAULT_var->getType(), - true, - GlobalVariable::ExternalLinkage, - jlRTLD_DEFAULT_var, - "jl_RTLD_DEFAULT_handle_pointer"), TheTriple); - Type *T_size = DL.getIntPtrType(Context); Type *T_psize = T_size->getPointerTo(); + auto FT = FunctionType::get(Type::getInt8Ty(Context)->getPointerTo()->getPointerTo(), {}, false); + auto F = Function::Create(FT, Function::ExternalLinkage, "get_jl_RTLD_DEFAULT_handle_addr", metadataM); + llvm::IRBuilder<> builder(BasicBlock::Create(Context, "top", F)); + builder.CreateRet(jlRTLD_DEFAULT_var); + F->setLinkage(GlobalValue::ExternalLinkage); + if (TheTriple.isOSBinFormatCOFF()) + F->setDLLStorageClass(GlobalValue::DLLStorageClassTypes::DLLExportStorageClass); + if (TheTriple.isOSWindows()) { // Windows expect that the function `_DllMainStartup` is present in an dll. // Normal compilers use something like Zig's crtdll.c instead we provide a diff --git a/src/codegen.cpp b/src/codegen.cpp index dd3376c334a37..4019f6d7e32d1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -493,9 +493,12 @@ struct JuliaVariable { if (GlobalValue *V = m->getNamedValue(name)) return cast(V); auto T_size = m->getDataLayout().getIntPtrType(m->getContext()); - return new GlobalVariable(*m, _type(T_size), + auto var = new GlobalVariable(*m, _type(T_size), isconst, GlobalVariable::ExternalLinkage, NULL, name); + if (Triple(m->getTargetTriple()).isOSWindows()) + var->setDLLStorageClass(GlobalValue::DLLStorageClassTypes::DLLImportStorageClass); // Cross-library imports must be explicit for COFF (Windows) + return var; } GlobalVariable *realize(jl_codectx_t &ctx); }; @@ -1786,9 +1789,6 @@ static inline GlobalVariable *prepare_global_in(Module *M, GlobalVariable *G) G->isConstant(), GlobalVariable::ExternalLinkage, nullptr, G->getName(), nullptr, G->getThreadLocalMode()); proto->copyAttributesFrom(G); - // DLLImport only needs to be set for the shadow module - // it just gets annoying in the JIT - proto->setDLLStorageClass(GlobalValue::DefaultStorageClass); return proto; } return cast(local); diff --git a/src/staticdata.c b/src/staticdata.c index c130c2e7569fe..a55342604f21d 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -2838,9 +2838,9 @@ JL_DLLEXPORT void jl_preload_sysimg_so(const char *fname) // Allow passing in a module handle directly, rather than a path JL_DLLEXPORT void jl_set_sysimg_so(void *handle) { - void* *jl_RTLD_DEFAULT_handle_pointer; - int symbol_found = jl_dlsym(handle, "jl_RTLD_DEFAULT_handle_pointer", (void **)&jl_RTLD_DEFAULT_handle_pointer, 0); - if (!symbol_found || (void*)&jl_RTLD_DEFAULT_handle != *jl_RTLD_DEFAULT_handle_pointer) + void** (*get_jl_RTLD_DEFAULT_handle_addr)(void) = NULL; + int symbol_found = jl_dlsym(handle, "get_jl_RTLD_DEFAULT_handle_addr", (void **)&get_jl_RTLD_DEFAULT_handle_addr, 0); + if (!symbol_found || (void*)&jl_RTLD_DEFAULT_handle != (get_jl_RTLD_DEFAULT_handle_addr())) jl_error("System image file failed consistency check: maybe opened the wrong version?"); if (jl_options.cpu_target == NULL) jl_options.cpu_target = "native"; diff --git a/sysimage.mk b/sysimage.mk index 993ee9a990058..0d2c9aff126e4 100644 --- a/sysimage.mk +++ b/sysimage.mk @@ -16,7 +16,7 @@ $(build_private_libdir)/%.$(SHLIB_EXT): $(build_private_libdir)/%-o.a @$(call PRINT_LINK, $(CXX) $(LDFLAGS) -shared $(fPIC) -L$(build_private_libdir) -L$(build_libdir) -L$(build_shlibdir) -o $@ \ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) \ $(if $(findstring -debug,$(notdir $@)),-ljulia-internal-debug -ljulia-debug,-ljulia-internal -ljulia) \ - $$([ $(OS) = WINNT ] && echo '' -lssp)) + $$([ $(OS) = WINNT ] && echo '' -lssp --disable-auto-import --disable-runtime-pseudo-reloc)) @$(INSTALL_NAME_CMD)$(notdir $@) $@ @$(DSYMUTIL) $@ From c81d02cf41ea0e3aa3d46acb9ac468110d0fb1b3 Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Thu, 16 May 2024 19:46:49 +0800 Subject: [PATCH 12/13] typeintersect: conservative typevar subtitution during `finish_unionall` (#54465) (cherry picked from commit a946631240cc085c883e38b6a69c4ae01c715414) --- src/builtins.c | 6 +- src/gf.c | 4 +- src/jltypes.c | 295 ++++++++++++++++++++++++++++++------------- src/julia_internal.h | 3 +- src/subtype.c | 41 +++--- test/subtype.jl | 17 +++ 6 files changed, 245 insertions(+), 121 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index e4bc75bdcd28d..2fd57059f8ac2 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1365,11 +1365,11 @@ JL_CALLABLE(jl_f_apply_type) jl_vararg_t *vm = (jl_vararg_t*)args[0]; if (!vm->T) { JL_NARGS(apply_type, 2, 3); - return (jl_value_t*)jl_wrap_vararg(args[1], nargs == 3 ? args[2] : NULL, 1); + return (jl_value_t*)jl_wrap_vararg(args[1], nargs == 3 ? args[2] : NULL, 1, 0); } else if (!vm->N) { JL_NARGS(apply_type, 2, 2); - return (jl_value_t*)jl_wrap_vararg(vm->T, args[1], 1); + return (jl_value_t*)jl_wrap_vararg(vm->T, args[1], 1, 0); } } else if (jl_is_unionall(args[0])) { @@ -2060,7 +2060,7 @@ void jl_init_primitives(void) JL_GC_DISABLED add_builtin("Tuple", (jl_value_t*)jl_anytuple_type); add_builtin("TypeofVararg", (jl_value_t*)jl_vararg_type); add_builtin("SimpleVector", (jl_value_t*)jl_simplevector_type); - add_builtin("Vararg", (jl_value_t*)jl_wrap_vararg(NULL, NULL, 0)); + add_builtin("Vararg", (jl_value_t*)jl_wrap_vararg(NULL, NULL, 0, 0)); add_builtin("Module", (jl_value_t*)jl_module_type); add_builtin("MethodTable", (jl_value_t*)jl_methtable_type); diff --git a/src/gf.c b/src/gf.c index 186f8787cf519..5a9f18ffad9f2 100644 --- a/src/gf.c +++ b/src/gf.c @@ -735,7 +735,7 @@ static jl_value_t *inst_varargp_in_env(jl_value_t *decl, jl_svec_t *sparams) vm = T_has_tv ? jl_type_unionall(v, T) : T; if (N_has_tv) N = NULL; - vm = (jl_value_t*)jl_wrap_vararg(vm, N, 1); // this cannot throw for these inputs + vm = (jl_value_t*)jl_wrap_vararg(vm, N, 1, 0); // this cannot throw for these inputs } sp++; decl = ((jl_unionall_t*)decl)->body; @@ -984,7 +984,7 @@ static void jl_compilation_sig( // avoid Vararg{Type{Type{...}}} if (jl_is_type_type(type_i) && jl_is_type_type(jl_tparam0(type_i))) type_i = (jl_value_t*)jl_type_type; - type_i = (jl_value_t*)jl_wrap_vararg(type_i, (jl_value_t*)NULL, 1); // this cannot throw for these inputs + type_i = (jl_value_t*)jl_wrap_vararg(type_i, (jl_value_t*)NULL, 1, 0); // this cannot throw for these inputs } else { type_i = inst_varargp_in_env(decl, sparams); diff --git a/src/jltypes.c b/src/jltypes.c index e3089c650eda8..b39997ada2dd8 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -847,14 +847,14 @@ JL_DLLEXPORT jl_value_t *jl_type_unionall(jl_tvar_t *v, jl_value_t *body) if (T_has_tv) { jl_value_t *wrapped = jl_type_unionall(v, vm->T); JL_GC_PUSH1(&wrapped); - wrapped = (jl_value_t*)jl_wrap_vararg(wrapped, vm->N, 1); + wrapped = (jl_value_t*)jl_wrap_vararg(wrapped, vm->N, 1, 0); JL_GC_POP(); return wrapped; } else { assert(N_has_tv); assert(vm->N == (jl_value_t*)v); - return (jl_value_t*)jl_wrap_vararg(vm->T, NULL, 1); + return (jl_value_t*)jl_wrap_vararg(vm->T, NULL, 1, 0); } } if (!jl_is_type(body) && !jl_is_typevar(body)) @@ -1317,7 +1317,7 @@ struct _jl_typestack_t; typedef struct _jl_typestack_t jl_typestack_t; static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, - jl_typestack_t *stack, jl_typeenv_t *env, int check); + jl_typestack_t *stack, jl_typeenv_t *env, int check, int nothrow); // Build an environment mapping a TypeName's parameters to parameter values. // This is the environment needed for instantiating a type's supertype and field types. @@ -1325,7 +1325,7 @@ static jl_value_t *inst_datatype_env(jl_value_t *dt, jl_svec_t *p, jl_value_t ** jl_typestack_t *stack, jl_typeenv_t *env, int c) { if (jl_is_datatype(dt)) - return inst_datatype_inner((jl_datatype_t*)dt, p, iparams, ntp, stack, env, 1); + return inst_datatype_inner((jl_datatype_t*)dt, p, iparams, ntp, stack, env, 1, 0); assert(jl_is_unionall(dt)); jl_unionall_t *ua = (jl_unionall_t*)dt; jl_typeenv_t e = { ua->var, iparams[c], env }; @@ -1432,12 +1432,12 @@ jl_datatype_t *jl_apply_cmpswap_type(jl_value_t *ty) } // used to expand an NTuple to a flat representation -static jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *v) +static jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *v, int check, int nothrow) { jl_value_t *p = NULL; JL_GC_PUSH1(&p); p = (jl_value_t*)jl_svec_fill(n, v); - p = jl_apply_tuple_type((jl_svec_t*)p); + p = inst_datatype_inner(jl_anytuple_type, (jl_svec_t*)p, jl_svec_data(p), n, NULL, NULL, check, nothrow); JL_GC_POP(); return p; } @@ -1447,13 +1447,13 @@ JL_EXTENSION struct _jl_typestack_t { struct _jl_typestack_t *prev; }; -static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check); +static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow); static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack); JL_DLLEXPORT jl_value_t *jl_instantiate_unionall(jl_unionall_t *u, jl_value_t *p) { jl_typeenv_t env = { u->var, p, NULL }; - return inst_type_w_(u->body, &env, NULL, 1); + return inst_type_w_(u->body, &env, NULL, 1, 0); } jl_unionall_t *jl_rename_unionall(jl_unionall_t *u) @@ -1462,18 +1462,27 @@ jl_unionall_t *jl_rename_unionall(jl_unionall_t *u) jl_value_t *t = NULL; JL_GC_PUSH2(&v, &t); jl_typeenv_t env = { u->var, (jl_value_t *)v, NULL }; - t = inst_type_w_(u->body, &env, NULL, 0); + t = inst_type_w_(u->body, &env, NULL, 0, 0); t = jl_new_struct(jl_unionall_type, v, t); JL_GC_POP(); return (jl_unionall_t*)t; } +jl_value_t *jl_substitute_var_nothrow(jl_value_t *t, jl_tvar_t *var, jl_value_t *val) +{ + if (val == (jl_value_t*)var) + return t; + int nothrow = jl_is_typevar(val) ? 0 : 1; + jl_typeenv_t env = { var, val, NULL }; + return inst_type_w_(t, &env, NULL, 1, nothrow); +} + jl_value_t *jl_substitute_var(jl_value_t *t, jl_tvar_t *var, jl_value_t *val) { if (val == (jl_value_t*)var) return t; jl_typeenv_t env = { var, val, NULL }; - return inst_type_w_(t, &env, NULL, 1); + return inst_type_w_(t, &env, NULL, 1, 0); } jl_value_t *jl_unwrap_unionall(jl_value_t *v) @@ -1839,7 +1848,7 @@ jl_value_t *normalize_unionalls(jl_value_t *t) static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals, jl_typeenv_t *prev, jl_typestack_t *stack); static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, - jl_typestack_t *stack, jl_typeenv_t *env, int check) + jl_typestack_t *stack, jl_typeenv_t *env, int check, int nothrow) { jl_typestack_t top; jl_typename_t *tn = dt->name; @@ -1870,8 +1879,11 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value break; } } - if (pi == jl_bottom_type) + if (pi == jl_bottom_type) { + if (nothrow) + return NULL; jl_errorf("Tuple field type cannot be Union{}"); + } if (cacheable && !jl_is_concrete_type(pi)) cacheable = 0; } @@ -1931,7 +1943,13 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value // for whether this is even valid if (check && !istuple) { assert(ntp > 0); - check_datatype_parameters(tn, iparams, ntp); + JL_TRY { + check_datatype_parameters(tn, iparams, ntp); + } + JL_CATCH { + if (!nothrow) jl_rethrow(); + return NULL; + } } else if (ntp == 0 && jl_emptytuple_type != NULL) { // empty tuple type case @@ -1958,7 +1976,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value if (nt == 0 || !jl_has_free_typevars(va0)) { if (ntp == 1) { JL_GC_POP(); - return jl_tupletype_fill(nt, va0); + return jl_tupletype_fill(nt, va0, 0, 0); } size_t i, l; p = jl_alloc_svec(ntp - 1 + nt); @@ -1967,7 +1985,9 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value l = ntp - 1 + nt; for (; i < l; i++) jl_svecset(p, i, va0); - jl_value_t *ndt = jl_apply_tuple_type(p); + size_t np = jl_svec_len(p); + jl_value_t **pp = jl_svec_data(p); + jl_value_t *ndt = inst_datatype_inner(jl_anytuple_type, p, pp, np, NULL, NULL, check, nothrow); JL_GC_POP(); return ndt; } @@ -2046,6 +2066,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value ndt->parameters = p; jl_gc_wb(ndt, ndt->parameters); ndt->types = NULL; // to be filled in below + int invalid = 0; if (istuple) { ndt->types = p; // TODO: this may need to filter out certain types } @@ -2053,26 +2074,41 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value jl_value_t *names_tup = jl_svecref(p, 0); jl_value_t *values_tt = jl_svecref(p, 1); if (!jl_has_free_typevars(names_tup) && !jl_has_free_typevars(values_tt)) { - if (!jl_is_tuple(names_tup)) - jl_type_error_rt("NamedTuple", "names", (jl_value_t*)jl_anytuple_type, names_tup); + if (!jl_is_tuple(names_tup)) { + if (!nothrow) + jl_type_error_rt("NamedTuple", "names", (jl_value_t*)jl_anytuple_type, names_tup); + invalid = 1; + } size_t nf = jl_nfields(names_tup); for (size_t i = 0; i < nf; i++) { jl_value_t *ni = jl_fieldref(names_tup, i); - if (!jl_is_symbol(ni)) - jl_type_error_rt("NamedTuple", "name", (jl_value_t*)jl_symbol_type, ni); + if (!jl_is_symbol(ni)) { + if (!nothrow) + jl_type_error_rt("NamedTuple", "name", (jl_value_t*)jl_symbol_type, ni); + invalid = 1; break; + } for (size_t j = 0; j < i; j++) { - if (ni == jl_fieldref_noalloc(names_tup, j)) - jl_errorf("duplicate field name in NamedTuple: \"%s\" is not unique", jl_symbol_name((jl_sym_t*)ni)); + if (ni == jl_fieldref_noalloc(names_tup, j)) { + if (!nothrow) + jl_errorf("duplicate field name in NamedTuple: \"%s\" is not unique", jl_symbol_name((jl_sym_t*)ni)); + invalid = 1; break; + } } + if (invalid) break; } if (values_tt == jl_bottom_type && nf > 0) { ndt->types = jl_svec_fill(nf, jl_bottom_type); } else { - if (!jl_is_datatype(values_tt)) + if (!jl_is_datatype(values_tt)) { + // should have been checked within `check_datatype_parameters`. jl_error("NamedTuple field type must be a tuple datatype"); - if (jl_is_va_tuple((jl_datatype_t*)values_tt) || jl_nparams(values_tt) != nf) - jl_error("NamedTuple names and field types must have matching lengths"); + } + if (jl_is_va_tuple((jl_datatype_t*)values_tt) || jl_nparams(values_tt) != nf) { + if (!nothrow) + jl_error("NamedTuple names and field types must have matching lengths"); + invalid = 1; + } ndt->types = ((jl_datatype_t*)values_tt)->parameters; } jl_gc_wb(ndt, ndt->types); @@ -2082,6 +2118,12 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value } } + if (nothrow && invalid) { + if (cacheable) + JL_UNLOCK(&typecache_lock); + JL_GC_POP(); + return NULL; + } jl_datatype_t *primarydt = ((jl_datatype_t*)jl_unwrap_unionall(tn->wrapper)); jl_precompute_memoized_dt(ndt, cacheable); if (primarydt->layout) @@ -2091,7 +2133,14 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value ndt->super = jl_any_type; } else if (dt->super) { - ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)dt->super, env, stack, check); + jl_value_t *super = inst_type_w_((jl_value_t*)dt->super, env, stack, check, nothrow); + if (nothrow && super == NULL) { + if (cacheable) + JL_UNLOCK(&typecache_lock); + JL_GC_POP(); + return NULL; + } + ndt->super = (jl_datatype_t *)super; jl_gc_wb(ndt, ndt->super); } jl_svec_t *ftypes = dt->types; @@ -2139,7 +2188,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value static jl_value_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params) { - return inst_datatype_inner(jl_anytuple_type, params, p, np, NULL, NULL, 1); + return inst_datatype_inner(jl_anytuple_type, params, p, np, NULL, NULL, 1, 0); } JL_DLLEXPORT jl_value_t *jl_apply_tuple_type(jl_svec_t *params) @@ -2178,7 +2227,7 @@ jl_tupletype_t *jl_inst_arg_tuple_type(jl_value_t *arg1, jl_value_t **args, size } jl_svecset(params, i, ai); } - tt = (jl_datatype_t*)inst_datatype_inner(jl_anytuple_type, params, jl_svec_data(params), nargs, NULL, NULL, 1); + tt = (jl_datatype_t*)inst_datatype_inner(jl_anytuple_type, params, jl_svec_data(params), nargs, NULL, NULL, 1, 0); JL_GC_POP(); } return tt; @@ -2193,7 +2242,7 @@ static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *s for (i = 0; i < lp; i++) { jl_value_t *pi = jl_svecref(p, i); JL_TRY { - pi = inst_type_w_(pi, env, stack, 1); + pi = inst_type_w_(pi, env, stack, 1, 0); if (!jl_is_type(pi) && !jl_is_typevar(pi)) { pi = jl_bottom_type; } @@ -2207,7 +2256,7 @@ static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *s return np; } -static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check) +static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow) { jl_datatype_t *tt = (jl_datatype_t*)t; jl_svec_t *tp = tt->parameters; @@ -2231,9 +2280,11 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ } if (T != NULL && N != NULL && jl_is_long(N)) { ssize_t nt = jl_unbox_long(N); - if (nt < 0) - jl_errorf("size or dimension is negative: %zd", nt); - return jl_tupletype_fill(nt, T); + if (nt >= 0) + return jl_tupletype_fill(nt, T, check, nothrow); + if (nothrow) + return NULL; + jl_errorf("Vararg length is negative: %zd", nt); } } jl_value_t **iparams; @@ -2245,23 +2296,31 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ iparams[0] = (jl_value_t*)ip_heap; iparams = jl_svec_data(ip_heap); } - int bound = 0; - int i; + int i, bound = 0; for (i = 0; i < ntp; i++) { jl_value_t *elt = jl_svecref(tp, i); - jl_value_t *pi = inst_type_w_(elt, env, stack, check); + jl_value_t *pi = inst_type_w_(elt, env, stack, check, nothrow); + if (pi == NULL) { + if (i == ntp-1 && jl_is_vararg(elt)) { + t = NULL; + break; + } + else { + pi = jl_bottom_type; + } + } iparams[i] = pi; if (ip_heap) jl_gc_wb(ip_heap, pi); bound |= (pi != elt); } - if (bound) - t = inst_datatype_inner(tt, ip_heap, iparams, ntp, stack, env, check); + if (t != NULL && bound) + t = inst_datatype_inner(tt, ip_heap, iparams, ntp, stack, env, check, nothrow); JL_GC_POP(); return t; } -static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check) +static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow) { size_t i; if (jl_is_typevar(t)) { @@ -2281,42 +2340,71 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t jl_value_t *var = NULL; jl_value_t *newbody = NULL; JL_GC_PUSH3(&lb, &var, &newbody); - lb = inst_type_w_(ua->var->lb, env, stack, check); - var = inst_type_w_(ua->var->ub, env, stack, check); - if (lb != ua->var->lb || var != ua->var->ub) { - var = (jl_value_t*)jl_new_typevar(ua->var->name, lb, var); - } - else { - var = (jl_value_t*)ua->var; + JL_TRY { + lb = inst_type_w_(ua->var->lb, env, stack, check, 0); } - jl_typeenv_t newenv = { ua->var, var, env }; - newbody = inst_type_w_(ua->body, &newenv, stack, check); - if (newbody == (jl_value_t*)jl_emptytuple_type) { - // NTuple{0} => Tuple{} can make a typevar disappear - t = (jl_value_t*)jl_emptytuple_type; + JL_CATCH { + if (!nothrow) jl_rethrow(); + t = NULL; + } + if (t != NULL) { + var = inst_type_w_(ua->var->ub, env, stack, check, nothrow); + if (var == NULL) { + if (lb == jl_bottom_type) + var = jl_bottom_type; + else + t = NULL; + } + else if (lb != ua->var->lb || var != ua->var->ub) { + var = (jl_value_t*)jl_new_typevar(ua->var->name, lb, var); + } + else { + var = (jl_value_t*)ua->var; + } } - else if (newbody != ua->body || var != (jl_value_t*)ua->var) { - // if t's parameters are not bound in the environment, return it uncopied (#9378) - t = jl_new_struct(jl_unionall_type, var, newbody); + if (t != NULL) { + jl_typeenv_t newenv = { ua->var, var, env }; + newbody = inst_type_w_(ua->body, &newenv, stack, check, nothrow); + if (newbody == NULL) { + t = NULL; + } + else if (newbody == (jl_value_t*)jl_emptytuple_type) { + // NTuple{0} => Tuple{} can make a typevar disappear + t = (jl_value_t*)jl_emptytuple_type; + } + else if (nothrow && !jl_has_typevar(newbody, (jl_tvar_t *)var)) { + t = newbody; + } + else if (newbody != ua->body || var != (jl_value_t*)ua->var) { + // if t's parameters are not bound in the environment, return it uncopied (#9378) + t = jl_new_struct(jl_unionall_type, var, newbody); + } } JL_GC_POP(); return t; } if (jl_is_uniontype(t)) { jl_uniontype_t *u = (jl_uniontype_t*)t; - jl_value_t *a = inst_type_w_(u->a, env, stack, check); + jl_value_t *a = inst_type_w_(u->a, env, stack, check, nothrow); jl_value_t *b = NULL; JL_GC_PUSH2(&a, &b); - b = inst_type_w_(u->b, env, stack, check); + b = inst_type_w_(u->b, env, stack, check, nothrow); if (a != u->a || b != u->b) { - if (check) { - jl_value_t *uargs[2] = {a, b}; - t = jl_type_union(uargs, 2); - } - else { + if (!check) { // fast path for `jl_rename_unionall`. t = jl_new_struct(jl_uniontype_type, a, b); } + else if (nothrow && a == NULL) { + t = b; + } + else if (nothrow && b == NULL) { + t = a; + } + else { + assert(a != NULL && b != NULL); + jl_value_t *uargs[2] = {a, b}; + t = jl_type_union(uargs, 2); + } } JL_GC_POP(); return t; @@ -2327,12 +2415,15 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t jl_value_t *N = NULL; JL_GC_PUSH2(&T, &N); if (v->T) { - T = inst_type_w_(v->T, env, stack, check); - if (v->N) - N = inst_type_w_(v->N, env, stack, check); + T = inst_type_w_(v->T, env, stack, check, nothrow); + if (T == NULL) + T = jl_bottom_type; + if (v->N) // This branch should never throw. + N = inst_type_w_(v->N, env, stack, check, 0); } if (T != v->T || N != v->N) { - t = (jl_value_t*)jl_wrap_vararg(T, N, check); + // `Vararg` is special, we'd better handle inner error at Tuple level. + t = (jl_value_t*)jl_wrap_vararg(T, N, check, nothrow); } JL_GC_POP(); return t; @@ -2345,20 +2436,27 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t return t; jl_typename_t *tn = tt->name; if (tn == jl_tuple_typename) - return inst_tuple_w_(t, env, stack, check); + return inst_tuple_w_(t, env, stack, check, nothrow); size_t ntp = jl_svec_len(tp); jl_value_t **iparams; JL_GC_PUSHARGS(iparams, ntp); int bound = 0; for (i = 0; i < ntp; i++) { jl_value_t *elt = jl_svecref(tp, i); - jl_value_t *pi = inst_type_w_(elt, env, stack, check); - iparams[i] = pi; - bound |= (pi != elt); + JL_TRY { + jl_value_t *pi = inst_type_w_(elt, env, stack, check, 0); + iparams[i] = pi; + bound |= (pi != elt); + } + JL_CATCH { + if (!nothrow) jl_rethrow(); + t = NULL; + } + if (t == NULL) break; } // if t's parameters are not bound in the environment, return it uncopied (#9378) - if (bound) - t = inst_datatype_inner(tt, NULL, iparams, ntp, stack, env, check); + if (t != NULL && bound) + t = inst_datatype_inner(tt, NULL, iparams, ntp, stack, env, check, nothrow); JL_GC_POP(); return t; } @@ -2369,7 +2467,7 @@ static jl_value_t *instantiate_with(jl_value_t *t, jl_value_t **env, size_t n, j jl_typeenv_t en = { (jl_tvar_t*)env[0], env[1], te }; return instantiate_with(t, &env[2], n-1, &en ); } - return inst_type_w_(t, te, NULL, 1); + return inst_type_w_(t, te, NULL, 1, 0); } jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n) @@ -2383,7 +2481,7 @@ static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *en if (jl_is_unionall(env->body)) return _jl_instantiate_type_in_env(ty, (jl_unionall_t*)env->body, vals + 1, &en, stack); else - return inst_type_w_(ty, &en, stack, 1); + return inst_type_w_(ty, &en, stack, 1, 0); } JL_DLLEXPORT jl_value_t *jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals) @@ -2405,8 +2503,10 @@ jl_datatype_t *jl_wrap_Type(jl_value_t *t) return (jl_datatype_t*)jl_instantiate_unionall(jl_type_type, t); } -jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check) +jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check, int nothrow) { + int valid = 1; + jl_vararg_t *vm = NULL; jl_task_t *ct = jl_current_task; JL_GC_PUSH1(&t); if (check) { @@ -2417,31 +2517,44 @@ jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check) // values and not the bounds of variables. /* jl_tvar_t *N = (jl_tvar_t*)n; - if (!(N->lb == jl_bottom_type && N->ub == (jl_value_t*)jl_any_type)) - jl_error("TypeVar in Vararg length must have bounds Union{} and Any"); + if (valid && !(N->lb == jl_bottom_type && N->ub == (jl_value_t*)jl_any_type)) { + if (!nothrow) + jl_error("TypeVar in Vararg length must have bounds Union{} and Any"); + invalid = 1; + } */ } - else if (!jl_is_long(n)) { - jl_type_error_rt("Vararg", "count", (jl_value_t*)jl_long_type, n); + else if (valid && !jl_is_long(n)) { + if (!nothrow) + jl_type_error_rt("Vararg", "count", (jl_value_t*)jl_long_type, n); + valid = 0; } - else if (jl_unbox_long(n) < 0) { - jl_errorf("Vararg length is negative: %zd", jl_unbox_long(n)); + else if (valid && jl_unbox_long(n) < 0) { + if (!nothrow) + jl_errorf("Vararg length is negative: %zd", jl_unbox_long(n)); + valid = 0; } } if (t) { - if (!jl_valid_type_param(t)) { - jl_type_error_rt("Vararg", "type", (jl_value_t*)jl_type_type, t); + if (valid && !jl_valid_type_param(t)) { + if (!nothrow) + jl_type_error_rt("Vararg", "type", (jl_value_t*)jl_type_type, t); + valid = 0; + } + if (valid) { + t = normalize_unionalls(t); + jl_value_t *tw = extract_wrapper(t); + if (tw && t != tw && jl_types_equal(t, tw)) + t = tw; } - t = normalize_unionalls(t); - jl_value_t *tw = extract_wrapper(t); - if (tw && t != tw && jl_types_equal(t, tw)) - t = tw; } } - jl_vararg_t *vm = (jl_vararg_t *)jl_gc_alloc(ct->ptls, sizeof(jl_vararg_t), jl_vararg_type); - jl_set_typetagof(vm, jl_vararg_tag, 0); - vm->T = t; - vm->N = n; + if (valid) { + vm = (jl_vararg_t *)jl_gc_alloc(ct->ptls, sizeof(jl_vararg_t), jl_vararg_type); + jl_set_typetagof(vm, jl_vararg_tag, 0); + vm->T = t; + vm->N = n; + } JL_GC_POP(); return vm; } @@ -2502,7 +2615,7 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) // can throw! for (i = 0; i < n; i++) env[i].val = jl_svecref(ndt->parameters, i); - ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)t->super, &env[n - 1], &top, 1); + ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)t->super, &env[n - 1], &top, 1, 0); jl_gc_wb(ndt, ndt->super); } @@ -2725,7 +2838,7 @@ void jl_init_types(void) JL_GC_DISABLED // It seems like we probably usually end up needing the box for kinds (often used in an Any context), so force it to exist jl_vararg_type->name->mayinlinealloc = 0; - jl_svec_t *anytuple_params = jl_svec(1, jl_wrap_vararg((jl_value_t*)jl_any_type, (jl_value_t*)NULL, 0)); + jl_svec_t *anytuple_params = jl_svec(1, jl_wrap_vararg((jl_value_t*)jl_any_type, (jl_value_t*)NULL, 0, 0)); jl_anytuple_type = jl_new_datatype(jl_symbol("Tuple"), core, jl_any_type, anytuple_params, jl_emptysvec, anytuple_params, jl_emptysvec, 0, 0, 0); jl_tuple_typename = jl_anytuple_type->name; diff --git a/src/julia_internal.h b/src/julia_internal.h index 85ce95b65613d..5bd101d35d20c 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -711,6 +711,7 @@ JL_DLLEXPORT int jl_type_morespecific_no_subtype(jl_value_t *a, jl_value_t *b); jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n); JL_DLLEXPORT jl_value_t *jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals); jl_value_t *jl_substitute_var(jl_value_t *t, jl_tvar_t *var, jl_value_t *val); +jl_value_t *jl_substitute_var_nothrow(jl_value_t *t, jl_tvar_t *var, jl_value_t *val); jl_unionall_t *jl_rename_unionall(jl_unionall_t *u); JL_DLLEXPORT jl_value_t *jl_unwrap_unionall(jl_value_t *v JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_rewrap_unionall(jl_value_t *t, jl_value_t *u); @@ -723,7 +724,7 @@ jl_datatype_t *jl_new_abstracttype(jl_value_t *name, jl_module_t *module, jl_datatype_t *jl_new_uninitialized_datatype(void); void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable); JL_DLLEXPORT jl_datatype_t *jl_wrap_Type(jl_value_t *t); // x -> Type{x} -jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check); +jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check, int nothrow); void jl_reinstantiate_inner_types(jl_datatype_t *t); jl_datatype_t *jl_lookup_cache_type_(jl_datatype_t *type); void jl_cache_type_(jl_datatype_t *type); diff --git a/src/subtype.c b/src/subtype.c index 16ec800b5c8f2..c9ad92fff94d7 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -963,7 +963,7 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8 if (R && ans && e->envidx < e->envsz) { jl_value_t *val; if (vb.intvalued && vb.lb == (jl_value_t*)jl_any_type) - val = (jl_value_t*)jl_wrap_vararg(NULL, NULL, 0); // special token result that represents N::Int in the envout + val = (jl_value_t*)jl_wrap_vararg(NULL, NULL, 0, 0); // special token result that represents N::Int in the envout else if (!vb.occurs_inv && vb.lb != jl_bottom_type) val = is_leaf_bound(vb.lb) ? vb.lb : (jl_value_t*)jl_new_typevar(u->var->name, jl_bottom_type, vb.lb); else if (vb.lb == vb.ub) @@ -2770,12 +2770,9 @@ static jl_value_t *omit_bad_union(jl_value_t *u, jl_tvar_t *t) res = jl_bottom_type; } else if (obviously_egal(var->lb, ub)) { - JL_TRY { - res = jl_substitute_var(body, var, ub); - } - JL_CATCH { + res = jl_substitute_var_nothrow(body, var, ub); + if (res == NULL) res = jl_bottom_type; - } } else { if (ub != var->ub) { @@ -2964,12 +2961,9 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind } if (varval) { if (ub_has_dep) { // inner substitution has been handled - JL_TRY { - btemp->ub = jl_substitute_var(btemp->ub, vb->var, varval); - } - JL_CATCH { + btemp->ub = jl_substitute_var_nothrow(btemp->ub, vb->var, varval); + if (btemp->ub == NULL) res = jl_bottom_type; - } } } else if (btemp->ub == (jl_value_t*)vb->var) { @@ -3002,18 +2996,17 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind // if `v` still occurs, re-wrap body in `UnionAll v` or eliminate the UnionAll if (jl_has_typevar(res, vb->var)) { if (varval) { - JL_TRY { - // you can construct `T{x} where x` even if T's parameter is actually - // limited. in that case we might get an invalid instantiation here. - res = jl_substitute_var(res, vb->var, varval); - // simplify chains of UnionAlls where bounds become equal - while (jl_is_unionall(res) && obviously_egal(((jl_unionall_t*)res)->var->lb, - ((jl_unionall_t*)res)->var->ub)) - res = jl_instantiate_unionall((jl_unionall_t*)res, ((jl_unionall_t*)res)->var->lb); + // you can construct `T{x} where x` even if T's parameter is actually + // limited. in that case we might get an invalid instantiation here. + res = jl_substitute_var_nothrow(res, vb->var, varval); + // simplify chains of UnionAlls where bounds become equal + while (res != NULL && jl_is_unionall(res) && obviously_egal(((jl_unionall_t*)res)->var->lb, + ((jl_unionall_t*)res)->var->ub)) { + jl_unionall_t * ures = (jl_unionall_t *)res; + res = jl_substitute_var_nothrow(ures->body, ures->var, ures->var->lb); } - JL_CATCH { + if (res == NULL) res = jl_bottom_type; - } } else { if (newvar != vb->var) @@ -3273,7 +3266,7 @@ static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, ssize_t ii = (jl_value_t*)vmy; else { JL_GC_PUSH1(&ii); - ii = (jl_value_t*)jl_wrap_vararg(ii, NULL, 1); + ii = (jl_value_t*)jl_wrap_vararg(ii, NULL, 1, 0); JL_GC_POP(); } return ii; @@ -3314,7 +3307,7 @@ static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, ssize_t else if (yp2 && obviously_egal(yp1, ii) && obviously_egal(yp2, i2)) ii = (jl_value_t*)vmy; else - ii = (jl_value_t*)jl_wrap_vararg(ii, i2, 1); + ii = (jl_value_t*)jl_wrap_vararg(ii, i2, 1, 0); JL_GC_POP(); return ii; } @@ -4515,7 +4508,7 @@ static jl_value_t *insert_nondiagonal(jl_value_t *type, jl_varbinding_t *troot, JL_GC_PUSH2(&newt, &n); newt = insert_nondiagonal(t, troot, widen2ub); if (t != newt) - type = (jl_value_t *)jl_wrap_vararg(newt, n, 0); + type = (jl_value_t *)jl_wrap_vararg(newt, n, 0, 0); JL_GC_POP(); } else if (jl_is_datatype(type)) { diff --git a/test/subtype.jl b/test/subtype.jl index fffe5a3031fed..d222a35d2e6c9 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -2604,3 +2604,20 @@ let S = Tuple{Val{Val{Union{Val{A2}, A2}}}, Val{Val{Union{Val{A2}, Val{A4}, A4}} T = Tuple{Vararg{Val{V}}} where {V} @testintersect(S, T, !Union{}) end + +#issue 54356 +abstract type A54356{T<:Real} end +struct B54356{T} <: A54356{T} end +let S = Tuple{Val, Val{T}} where {T}, R = Tuple{Val{Val{T}}, Val{T}} where {T} + # general parameters check + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, Complex{B}}}, S{1}, R{1}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, B54356{B}}}, S{1}, R{1}) + # extra check for Vararg + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NTuple{B,Any}}}, S{-1}, R{-1}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, Tuple{Any,Vararg{Any,B}}}}, S{-1}, R{-1}) + # extra check for NamedTuple + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NamedTuple{B,Tuple{Int}}}}, S{1}, R{1}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NamedTuple{B,Tuple{Int}}}}, S{(1,)}, R{(1,)}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NamedTuple{(:a),B}}}, S{NTuple{2,Int}}, R{NTuple{2,Int}}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NamedTuple{B,Tuple{Int,Int}}}}, S{(:a,:a)}, R{(:a,:a)}) +end From 7ebe20315f05041f68f7f99cd8491480ea5c0906 Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Sun, 19 May 2024 13:10:05 +0800 Subject: [PATCH 13/13] typeintersect: followup cleanup for the nothrow path of type instantiation (#54514) (cherry picked from commit af545b90c5657e0e210aa638542052e16ca90fef) --- src/jltypes.c | 109 ++++++++++++++++++++++++++----------------- src/julia_internal.h | 2 +- src/subtype.c | 12 +++-- test/subtype.jl | 21 ++++++++- 4 files changed, 94 insertions(+), 50 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index b39997ada2dd8..dd26d1df06625 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -1468,11 +1468,11 @@ jl_unionall_t *jl_rename_unionall(jl_unionall_t *u) return (jl_unionall_t*)t; } -jl_value_t *jl_substitute_var_nothrow(jl_value_t *t, jl_tvar_t *var, jl_value_t *val) +jl_value_t *jl_substitute_var_nothrow(jl_value_t *t, jl_tvar_t *var, jl_value_t *val, int nothrow) { if (val == (jl_value_t*)var) return t; - int nothrow = jl_is_typevar(val) ? 0 : 1; + nothrow = jl_is_typevar(val) ? 0 : nothrow; jl_typeenv_t env = { var, val, NULL }; return inst_type_w_(t, &env, NULL, 1, nothrow); } @@ -1694,7 +1694,7 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable) dt->hash = typekey_hash(dt->name, jl_svec_data(dt->parameters), l, cacheable); } -static void check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, size_t np) +static int check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, size_t np, int nothrow) { jl_value_t *wrapper = tn->wrapper; jl_value_t **bounds; @@ -1712,6 +1712,10 @@ static void check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, si assert(jl_is_unionall(wrapper)); jl_tvar_t *tv = ((jl_unionall_t*)wrapper)->var; if (!within_typevar(params[i], bounds[2*i], bounds[2*i+1])) { + if (nothrow) { + JL_GC_POP(); + return 1; + } if (tv->lb != bounds[2*i] || tv->ub != bounds[2*i+1]) // pass a new version of `tv` containing the instantiated bounds tv = jl_new_typevar(tv->name, bounds[2*i], bounds[2*i+1]); @@ -1721,12 +1725,26 @@ static void check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, si int j; for (j = 2*i + 2; j < 2*np; j++) { jl_value_t *bj = bounds[j]; - if (bj != (jl_value_t*)jl_any_type && bj != jl_bottom_type) - bounds[j] = jl_substitute_var(bj, tv, params[i]); + if (bj != (jl_value_t*)jl_any_type && bj != jl_bottom_type) { + int isub = j & 1; + // use different nothrow level for lb and ub substitution. + // TODO: This assuming the top instantiation could only start with + // `nothrow == 2` or `nothrow == 0`. If `nothrow` is initially set to 1 + // then we might miss some inner error, perhaps the normal path should + // also follow this rule? + jl_value_t *nb = jl_substitute_var_nothrow(bj, tv, params[i], nothrow ? (isub ? 2 : 1) : 0 ); + if (nb == NULL) { + assert(nothrow); + JL_GC_POP(); + return 1; + } + bounds[j] = nb; + } } wrapper = ((jl_unionall_t*)wrapper)->body; } JL_GC_POP(); + return 0; } jl_value_t *extract_wrapper(jl_value_t *t JL_PROPAGATES_ROOT) JL_GLOBALLY_ROOTED @@ -1943,13 +1961,8 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value // for whether this is even valid if (check && !istuple) { assert(ntp > 0); - JL_TRY { - check_datatype_parameters(tn, iparams, ntp); - } - JL_CATCH { - if (!nothrow) jl_rethrow(); + if (check_datatype_parameters(tn, iparams, ntp, nothrow)) return NULL; - } } else if (ntp == 0 && jl_emptytuple_type != NULL) { // empty tuple type case @@ -2301,7 +2314,8 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ jl_value_t *elt = jl_svecref(tp, i); jl_value_t *pi = inst_type_w_(elt, env, stack, check, nothrow); if (pi == NULL) { - if (i == ntp-1 && jl_is_vararg(elt)) { + assert(nothrow); + if (nothrow == 1 || (i == ntp-1 && jl_is_vararg(elt))) { t = NULL; break; } @@ -2320,6 +2334,10 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ return t; } +// `nothrow` means that when type checking fails, the type instantiation should +// return `NULL` instead of immediately throwing an error. If `nothrow` == 2 then +// we further assume that the imprecise instantiation for non invariant parameters +// is acceptable, and inner error (`NULL`) would be ignored. static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow) { size_t i; @@ -2340,11 +2358,10 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t jl_value_t *var = NULL; jl_value_t *newbody = NULL; JL_GC_PUSH3(&lb, &var, &newbody); - JL_TRY { - lb = inst_type_w_(ua->var->lb, env, stack, check, 0); - } - JL_CATCH { - if (!nothrow) jl_rethrow(); + // set nothrow <= 1 to ensure lb's accuracy. + lb = inst_type_w_(ua->var->lb, env, stack, check, nothrow ? 1 : 0); + if (lb == NULL) { + assert(nothrow); t = NULL; } if (t != NULL) { @@ -2368,11 +2385,9 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t if (newbody == NULL) { t = NULL; } - else if (newbody == (jl_value_t*)jl_emptytuple_type) { - // NTuple{0} => Tuple{} can make a typevar disappear - t = (jl_value_t*)jl_emptytuple_type; - } - else if (nothrow && !jl_has_typevar(newbody, (jl_tvar_t *)var)) { + else if (!jl_has_typevar(newbody, (jl_tvar_t *)var)) { + // inner instantiation might make a typevar disappear, e.g. + // NTuple{0,T} => Tuple{} t = newbody; } else if (newbody != ua->body || var != (jl_value_t*)ua->var) { @@ -2389,16 +2404,21 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t jl_value_t *b = NULL; JL_GC_PUSH2(&a, &b); b = inst_type_w_(u->b, env, stack, check, nothrow); + if (nothrow) { + // ensure jl_type_union nothrow. + if (a && !(jl_is_typevar(a) || jl_is_type(a))) + a = NULL; + if (b && !(jl_is_typevar(b) || jl_is_type(b))) + b = NULL; + } if (a != u->a || b != u->b) { if (!check) { // fast path for `jl_rename_unionall`. t = jl_new_struct(jl_uniontype_type, a, b); } - else if (nothrow && a == NULL) { - t = b; - } - else if (nothrow && b == NULL) { - t = a; + else if (a == NULL || b == NULL) { + assert(nothrow); + t = nothrow == 1 ? NULL : a == NULL ? b : a; } else { assert(a != NULL && b != NULL); @@ -2416,15 +2436,21 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t JL_GC_PUSH2(&T, &N); if (v->T) { T = inst_type_w_(v->T, env, stack, check, nothrow); - if (T == NULL) - T = jl_bottom_type; - if (v->N) // This branch should never throw. - N = inst_type_w_(v->N, env, stack, check, 0); + if (T == NULL) { + if (nothrow == 2) + T = jl_bottom_type; + else + t = NULL; + } + if (t && v->N) { + // set nothrow <= 1 to ensure invariant parameter's accuracy. + N = inst_type_w_(v->N, env, stack, check, nothrow ? 1 : 0); + if (N == NULL) + t = NULL; + } } - if (T != v->T || N != v->N) { - // `Vararg` is special, we'd better handle inner error at Tuple level. + if (t && (T != v->T || N != v->N)) t = (jl_value_t*)jl_wrap_vararg(T, N, check, nothrow); - } JL_GC_POP(); return t; } @@ -2443,16 +2469,15 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t int bound = 0; for (i = 0; i < ntp; i++) { jl_value_t *elt = jl_svecref(tp, i); - JL_TRY { - jl_value_t *pi = inst_type_w_(elt, env, stack, check, 0); - iparams[i] = pi; - bound |= (pi != elt); - } - JL_CATCH { - if (!nothrow) jl_rethrow(); + // set nothrow <= 1 to ensure invariant parameter's accuracy. + jl_value_t *pi = inst_type_w_(elt, env, stack, check, nothrow ? 1 : 0); + if (pi == NULL) { + assert(nothrow); t = NULL; + break; } - if (t == NULL) break; + iparams[i] = pi; + bound |= (pi != elt); } // if t's parameters are not bound in the environment, return it uncopied (#9378) if (t != NULL && bound) diff --git a/src/julia_internal.h b/src/julia_internal.h index 5bd101d35d20c..ca8038c3f3f20 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -711,7 +711,7 @@ JL_DLLEXPORT int jl_type_morespecific_no_subtype(jl_value_t *a, jl_value_t *b); jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n); JL_DLLEXPORT jl_value_t *jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals); jl_value_t *jl_substitute_var(jl_value_t *t, jl_tvar_t *var, jl_value_t *val); -jl_value_t *jl_substitute_var_nothrow(jl_value_t *t, jl_tvar_t *var, jl_value_t *val); +jl_value_t *jl_substitute_var_nothrow(jl_value_t *t, jl_tvar_t *var, jl_value_t *val, int nothrow); jl_unionall_t *jl_rename_unionall(jl_unionall_t *u); JL_DLLEXPORT jl_value_t *jl_unwrap_unionall(jl_value_t *v JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_rewrap_unionall(jl_value_t *t, jl_value_t *u); diff --git a/src/subtype.c b/src/subtype.c index c9ad92fff94d7..8a1ea03fdd6fd 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -2770,7 +2770,7 @@ static jl_value_t *omit_bad_union(jl_value_t *u, jl_tvar_t *t) res = jl_bottom_type; } else if (obviously_egal(var->lb, ub)) { - res = jl_substitute_var_nothrow(body, var, ub); + res = jl_substitute_var_nothrow(body, var, ub, 2); if (res == NULL) res = jl_bottom_type; } @@ -2961,9 +2961,11 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind } if (varval) { if (ub_has_dep) { // inner substitution has been handled - btemp->ub = jl_substitute_var_nothrow(btemp->ub, vb->var, varval); - if (btemp->ub == NULL) + jl_value_t *bub = jl_substitute_var_nothrow(btemp->ub, vb->var, varval, 2); + if (bub == NULL) res = jl_bottom_type; + else + btemp->ub = bub; } } else if (btemp->ub == (jl_value_t*)vb->var) { @@ -2998,12 +3000,12 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind if (varval) { // you can construct `T{x} where x` even if T's parameter is actually // limited. in that case we might get an invalid instantiation here. - res = jl_substitute_var_nothrow(res, vb->var, varval); + res = jl_substitute_var_nothrow(res, vb->var, varval, 2); // simplify chains of UnionAlls where bounds become equal while (res != NULL && jl_is_unionall(res) && obviously_egal(((jl_unionall_t*)res)->var->lb, ((jl_unionall_t*)res)->var->ub)) { jl_unionall_t * ures = (jl_unionall_t *)res; - res = jl_substitute_var_nothrow(ures->body, ures->var, ures->var->lb); + res = jl_substitute_var_nothrow(ures->body, ures->var, ures->var->lb, 2); } if (res == NULL) res = jl_bottom_type; diff --git a/test/subtype.jl b/test/subtype.jl index d222a35d2e6c9..d3f1dc217f699 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -2608,13 +2608,30 @@ end #issue 54356 abstract type A54356{T<:Real} end struct B54356{T} <: A54356{T} end -let S = Tuple{Val, Val{T}} where {T}, R = Tuple{Val{Val{T}}, Val{T}} where {T} - # general parameters check +struct C54356{S,T<:Union{S,Complex{S}}} end +struct D54356{S<:Real,T} end +let S = Tuple{Val, Val{T}} where {T}, R = Tuple{Val{Val{T}}, Val{T}} where {T}, + SS = Tuple{Val, Val{T}, Val{T}} where {T}, RR = Tuple{Val{Val{T}}, Val{T}, Val{T}} where {T} + # parameters check for self @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, Complex{B}}}, S{1}, R{1}) + # parameters check for supertype (B54356 -> A54356) @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, B54356{B}}}, S{1}, R{1}) + # enure unused TypeVar skips the `UnionAll` wrapping + @testintersect(Tuple{Val{A}, A} where {B, A<:(Union{Val{B}, D54356{B,C}} where {C})}, S{1}, R{1}) + # invariant parameter should not get narrowed + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, Val{Union{Int,Complex{B}}}}}, S{1}, R{1}) + # bit value could not be `Union` element + @testintersect(Tuple{Val{A}, A, Val{B}} where {B, A<:Union{B, Val{B}}}, SS{1}, RR{1}) + @testintersect(Tuple{Val{A}, A, Val{B}} where {B, A<:Union{B, Complex{B}}}, SS{1}, Union{}) + # `check_datatype_parameters` should ignore bad `Union` elements in constraint's ub + T = Tuple{Val{Union{Val{Nothing}, Val{C54356{V,V}}}}, Val{Nothing}} where {Nothing<:V<:Nothing} + @test T <: S{Nothing} + @test T <: Tuple{Val{A}, A} where {B, C, A<:Union{Val{B}, Val{C54356{B,C}}}} + @test T <: typeintersect(Tuple{Val{A}, A} where {B, C, A<:Union{Val{B}, Val{C54356{B,C}}}}, S{Nothing}) # extra check for Vararg @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NTuple{B,Any}}}, S{-1}, R{-1}) @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, Tuple{Any,Vararg{Any,B}}}}, S{-1}, R{-1}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, Tuple{Vararg{Int,Union{Int,Complex{B}}}}}}, S{1}, R{1}) # extra check for NamedTuple @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NamedTuple{B,Tuple{Int}}}}, S{1}, R{1}) @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NamedTuple{B,Tuple{Int}}}}, S{(1,)}, R{(1,)})