From 353ae21214a4081f156e4ee8534dd01058e66761 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 11 Jul 2022 16:35:47 -0400 Subject: [PATCH] make convert(Union{},x) directly ambiguous This should make it impossible to accidentally define or call this method on foreign types. Refs: #31602 Fixes: #45837 Closes: #45051 --- base/array.jl | 1 - base/essentials.jl | 9 ++++++++- base/filesystem.jl | 1 - base/some.jl | 2 -- stdlib/Test/src/Test.jl | 8 ++++---- test/ambiguous.jl | 9 ++++----- 6 files changed, 16 insertions(+), 14 deletions(-) diff --git a/base/array.jl b/base/array.jl index 28572516ac99a..2f6072a89de07 100644 --- a/base/array.jl +++ b/base/array.jl @@ -612,7 +612,6 @@ oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x) ## Conversions ## convert(::Type{T}, a::AbstractArray) where {T<:Array} = a isa T ? a : T(a) -convert(::Type{Union{}}, a::AbstractArray) = throw(MethodError(convert, (Union{}, a))) promote_rule(a::Type{Array{T,n}}, b::Type{Array{S,n}}) where {T,n,S} = el_same(promote_type(T,S), a, b) diff --git a/base/essentials.jl b/base/essentials.jl index 906c36ad9c003..74a2551b814e2 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -279,7 +279,14 @@ See also: [`round`](@ref), [`trunc`](@ref), [`oftype`](@ref), [`reinterpret`](@r """ function convert end -convert(::Type{Union{}}, @nospecialize x) = throw(MethodError(convert, (Union{}, x))) +# make convert(::Type{<:Union{}}, x::T) intentionally ambiguous for all T +# so it will never get called or invalidated by loading packages +# with carefully chosen types that won't have any other convert methods defined +convert(T::Type{<:Core.IntrinsicFunction}, x) = throw(MethodError(convert, (T, x))) +convert(T::Type{<:Nothing}, x) = throw(MethodError(convert, (Nothing, x))) +convert(::Type{T}, x::T) where {T<:Core.IntrinsicFunction} = x +convert(::Type{T}, x::T) where {T<:Nothing} = x + convert(::Type{Type}, x::Type) = x # the ssair optimizer is strongly dependent on this method existing to avoid over-specialization # in the absence of inlining-enabled # (due to fields typed as `Type`, which is generally a bad idea) diff --git a/base/filesystem.jl b/base/filesystem.jl index 863eedf8ade9d..ee25c63a557e5 100644 --- a/base/filesystem.jl +++ b/base/filesystem.jl @@ -36,7 +36,6 @@ export File, # open, futime, write, - JL_O_ACCMODE, JL_O_WRONLY, JL_O_RDONLY, JL_O_RDWR, diff --git a/base/some.jl b/base/some.jl index 8e4e1b5e07c3f..8dc726e5c0022 100644 --- a/base/some.jl +++ b/base/some.jl @@ -34,8 +34,6 @@ end convert(::Type{T}, x::T) where {T>:Nothing} = x convert(::Type{T}, x) where {T>:Nothing} = convert(nonnothingtype_checked(T), x) -convert(::Type{Nothing}, x) = throw(MethodError(convert, (Nothing, x))) -convert(::Type{Nothing}, ::Nothing) = nothing convert(::Type{Some{T}}, x::Some{T}) where {T} = x convert(::Type{Some{T}}, x::Some) where {T} = Some{T}(convert(T, x.value)) diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index e73a53550c7f7..fb35f0646ec8e 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1734,11 +1734,11 @@ function detect_ambiguities(mods::Module...; ambs = Set{Tuple{Method,Method}}() mods = collect(mods)::Vector{Module} function sortdefs(m1::Method, m2::Method) - ord12 = m1.file < m2.file - if !ord12 && (m1.file == m2.file) - ord12 = m1.line < m2.line + ord12 = cmp(m1.file, m2.file) + if ord12 == 0 + ord12 = cmp(m1.line, m2.line) end - return ord12 ? (m1, m2) : (m2, m1) + return ord12 <= 0 ? (m1, m2) : (m2, m1) end function examine(mt::Core.MethodTable) for m in Base.MethodList(mt) diff --git a/test/ambiguous.jl b/test/ambiguous.jl index a06b92c5481b3..40781b71b543e 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -100,10 +100,6 @@ ambig(x::Union{Char, Int16}) = 's' const allowed_undefineds = Set([ GlobalRef(Base, :active_repl), GlobalRef(Base, :active_repl_backend), - GlobalRef(Base.Filesystem, :JL_O_TEMPORARY), - GlobalRef(Base.Filesystem, :JL_O_SHORT_LIVED), - GlobalRef(Base.Filesystem, :JL_O_SEQUENTIAL), - GlobalRef(Base.Filesystem, :JL_O_RANDOM), ]) let Distributed = get(Base.loaded_modules, @@ -167,7 +163,7 @@ using LinearAlgebra, SparseArrays, SuiteSparse # Test that Core and Base are free of ambiguities # not using isempty so this prints more information when it fails @testset "detect_ambiguities" begin - let ambig = Set{Any}(((m1.sig, m2.sig) for (m1, m2) in detect_ambiguities(Core, Base; recursive=true, ambiguous_bottom=false, allowed_undefineds))) + let ambig = Set(detect_ambiguities(Core, Base; recursive=true, ambiguous_bottom=false, allowed_undefineds)) good = true for (sig1, sig2) in ambig @test sig1 === sig2 # print this ambiguity @@ -178,6 +174,9 @@ using LinearAlgebra, SparseArrays, SuiteSparse # some ambiguities involving Union{} type parameters are expected, but not required let ambig = Set(detect_ambiguities(Core; recursive=true, ambiguous_bottom=true)) + m1 = which(Core.Compiler.convert, Tuple{Type{<:Core.IntrinsicFunction}, Any}) + m2 = which(Core.Compiler.convert, Tuple{Type{<:Nothing}, Any}) + pop!(ambig, (m1, m2)) @test !isempty(ambig) end