Skip to content

Commit 353ae21

Browse files
committed
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
1 parent 43dac09 commit 353ae21

File tree

6 files changed

+16
-14
lines changed

6 files changed

+16
-14
lines changed

base/array.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,6 @@ oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
612612
## Conversions ##
613613

614614
convert(::Type{T}, a::AbstractArray) where {T<:Array} = a isa T ? a : T(a)
615-
convert(::Type{Union{}}, a::AbstractArray) = throw(MethodError(convert, (Union{}, a)))
616615

617616
promote_rule(a::Type{Array{T,n}}, b::Type{Array{S,n}}) where {T,n,S} = el_same(promote_type(T,S), a, b)
618617

base/essentials.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,14 @@ See also: [`round`](@ref), [`trunc`](@ref), [`oftype`](@ref), [`reinterpret`](@r
279279
"""
280280
function convert end
281281

282-
convert(::Type{Union{}}, @nospecialize x) = throw(MethodError(convert, (Union{}, x)))
282+
# make convert(::Type{<:Union{}}, x::T) intentionally ambiguous for all T
283+
# so it will never get called or invalidated by loading packages
284+
# with carefully chosen types that won't have any other convert methods defined
285+
convert(T::Type{<:Core.IntrinsicFunction}, x) = throw(MethodError(convert, (T, x)))
286+
convert(T::Type{<:Nothing}, x) = throw(MethodError(convert, (Nothing, x)))
287+
convert(::Type{T}, x::T) where {T<:Core.IntrinsicFunction} = x
288+
convert(::Type{T}, x::T) where {T<:Nothing} = x
289+
283290
convert(::Type{Type}, x::Type) = x # the ssair optimizer is strongly dependent on this method existing to avoid over-specialization
284291
# in the absence of inlining-enabled
285292
# (due to fields typed as `Type`, which is generally a bad idea)

base/filesystem.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export File,
3636
# open,
3737
futime,
3838
write,
39-
JL_O_ACCMODE,
4039
JL_O_WRONLY,
4140
JL_O_RDONLY,
4241
JL_O_RDWR,

base/some.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ end
3434

3535
convert(::Type{T}, x::T) where {T>:Nothing} = x
3636
convert(::Type{T}, x) where {T>:Nothing} = convert(nonnothingtype_checked(T), x)
37-
convert(::Type{Nothing}, x) = throw(MethodError(convert, (Nothing, x)))
38-
convert(::Type{Nothing}, ::Nothing) = nothing
3937
convert(::Type{Some{T}}, x::Some{T}) where {T} = x
4038
convert(::Type{Some{T}}, x::Some) where {T} = Some{T}(convert(T, x.value))
4139

stdlib/Test/src/Test.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,11 +1734,11 @@ function detect_ambiguities(mods::Module...;
17341734
ambs = Set{Tuple{Method,Method}}()
17351735
mods = collect(mods)::Vector{Module}
17361736
function sortdefs(m1::Method, m2::Method)
1737-
ord12 = m1.file < m2.file
1738-
if !ord12 && (m1.file == m2.file)
1739-
ord12 = m1.line < m2.line
1737+
ord12 = cmp(m1.file, m2.file)
1738+
if ord12 == 0
1739+
ord12 = cmp(m1.line, m2.line)
17401740
end
1741-
return ord12 ? (m1, m2) : (m2, m1)
1741+
return ord12 <= 0 ? (m1, m2) : (m2, m1)
17421742
end
17431743
function examine(mt::Core.MethodTable)
17441744
for m in Base.MethodList(mt)

test/ambiguous.jl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,6 @@ ambig(x::Union{Char, Int16}) = 's'
100100
const allowed_undefineds = Set([
101101
GlobalRef(Base, :active_repl),
102102
GlobalRef(Base, :active_repl_backend),
103-
GlobalRef(Base.Filesystem, :JL_O_TEMPORARY),
104-
GlobalRef(Base.Filesystem, :JL_O_SHORT_LIVED),
105-
GlobalRef(Base.Filesystem, :JL_O_SEQUENTIAL),
106-
GlobalRef(Base.Filesystem, :JL_O_RANDOM),
107103
])
108104

109105
let Distributed = get(Base.loaded_modules,
@@ -167,7 +163,7 @@ using LinearAlgebra, SparseArrays, SuiteSparse
167163
# Test that Core and Base are free of ambiguities
168164
# not using isempty so this prints more information when it fails
169165
@testset "detect_ambiguities" begin
170-
let ambig = Set{Any}(((m1.sig, m2.sig) for (m1, m2) in detect_ambiguities(Core, Base; recursive=true, ambiguous_bottom=false, allowed_undefineds)))
166+
let ambig = Set(detect_ambiguities(Core, Base; recursive=true, ambiguous_bottom=false, allowed_undefineds))
171167
good = true
172168
for (sig1, sig2) in ambig
173169
@test sig1 === sig2 # print this ambiguity
@@ -178,6 +174,9 @@ using LinearAlgebra, SparseArrays, SuiteSparse
178174

179175
# some ambiguities involving Union{} type parameters are expected, but not required
180176
let ambig = Set(detect_ambiguities(Core; recursive=true, ambiguous_bottom=true))
177+
m1 = which(Core.Compiler.convert, Tuple{Type{<:Core.IntrinsicFunction}, Any})
178+
m2 = which(Core.Compiler.convert, Tuple{Type{<:Nothing}, Any})
179+
pop!(ambig, (m1, m2))
181180
@test !isempty(ambig)
182181
end
183182

0 commit comments

Comments
 (0)