Skip to content

Commit edba0db

Browse files
committed
inference: permit recursive type traits
We had a special case for Type that disallowed type trait recursion in favor of a pattern that almost never appears in code (only once in the compiler by accident where it doesn't matter). This was unnecessarily confusing and unexpected to predict what can infer, and made traits harder than necessary (such as Broadcast.ndims since 70fc3cd). Fix #43296 Fix #43368
1 parent dc06468 commit edba0db

File tree

2 files changed

+71
-24
lines changed

2 files changed

+71
-24
lines changed

base/compiler/typelimits.jl

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,32 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec
116116
return Union{a, b}
117117
end
118118
elseif isa(t, DataType)
119-
if isType(t) # see equivalent case in type_more_complex
120-
tt = unwrap_unionall(t.parameters[1])
121-
if isa(tt, Union) || isa(tt, TypeVar) || isType(tt)
122-
is_derived_type_from_any(tt, sources, depth + 1) && return t
119+
if isType(t)
120+
# Type is fairly important, so do not widen it as fast as other types if avoidable
121+
tt = t.parameters[1]
122+
ttu = unwrap_unionall(tt) # TODO: use argument_datatype(tt) after #50692 fixed
123+
# must forbid nesting through this if we detect that potentially occurring
124+
# we already know !is_derived_type_from_any so refuse to recurse here
125+
if !isa(ttu, DataType)
126+
return Type
127+
elseif isType(ttu)
128+
return Type{<:Type}
129+
end
130+
# try to peek into c to get a comparison object, but if we can't perhaps t is already simple enough on its own
131+
# (this is slightly more permissive than type_more_complex implements for the same case).
132+
if isType(c)
133+
ct = c.parameters[1]
123134
else
124-
isType(c) && (c = unwrap_unionall(c.parameters[1]))
125-
type_more_complex(tt, c, sources, depth, 0, 0) || return t
135+
ct = Union{}
126136
end
127-
return Type
137+
Qt = __limit_type_size(tt, ct, sources, depth + 1, 0)
138+
Qt === Any && return Type
139+
Qt === tt && return t
140+
# Can't form Type{<:Qt} just yet, without first make sure we limited the depth
141+
# enough, since this moves Qt outside of Type for is_derived_type_from_any
142+
Qt = __limit_type_size(tt, ct, sources, depth + 2, 0)
143+
Qt === Any && return Type
144+
return Type{<:Qt}
128145
elseif isa(c, DataType)
129146
tP = t.parameters
130147
cP = c.parameters
@@ -157,6 +174,7 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec
157174
end
158175
end
159176
if allowed_tuplelen < 1 && t.name === Tuple.name
177+
# forbid nesting Tuple{Tuple{Tuple...}} through this
160178
return Any
161179
end
162180
widert = t.name.wrapper
@@ -247,18 +265,7 @@ function type_more_complex(@nospecialize(t), @nospecialize(c), sources::SimpleVe
247265
# base case for data types
248266
if isa(t, DataType)
249267
tP = t.parameters
250-
if isType(t)
251-
# Treat Type{T} and T as equivalent to allow taking typeof any
252-
# source type (DataType) anywhere as Type{...}, as long as it isn't
253-
# nesting as Type{Type{...}}
254-
tt = unwrap_unionall(t.parameters[1])
255-
if isa(tt, Union) || isa(tt, TypeVar) || isType(tt)
256-
return !is_derived_type_from_any(tt, sources, depth + 1)
257-
else
258-
isType(c) && (c = unwrap_unionall(c.parameters[1]))
259-
return type_more_complex(tt, c, sources, depth, 0, 0)
260-
end
261-
elseif isa(c, DataType) && t.name === c.name
268+
if isa(c, DataType) && t.name === c.name
262269
cP = c.parameters
263270
length(cP) < length(tP) && return true
264271
isempty(tP) && return false

test/compiler/inference.jl

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ end
6060
# issue #42835
6161
@test !Core.Compiler.type_more_complex(Int, Any, Core.svec(), 1, 1, 1)
6262
@test !Core.Compiler.type_more_complex(Int, Type{Int}, Core.svec(), 1, 1, 1)
63-
@test !Core.Compiler.type_more_complex(Type{Int}, Any, Core.svec(), 1, 1, 1)
63+
@test Core.Compiler.type_more_complex(Type{Int}, Any, Core.svec(), 1, 1, 1) # maybe should be fixed?
64+
@test Core.Compiler.limit_type_size(Type{Int}, Any, Union{}, 0, 0) == Type{Int}
6465
@test Core.Compiler.type_more_complex(Type{Type{Int}}, Type{Int}, Core.svec(Type{Int}), 1, 1, 1)
6566
@test Core.Compiler.type_more_complex(Type{Type{Int}}, Int, Core.svec(Type{Int}), 1, 1, 1)
6667
@test Core.Compiler.type_more_complex(Type{Type{Int}}, Any, Core.svec(), 1, 1, 1)
@@ -71,22 +72,23 @@ end
7172
@test Core.Compiler.type_more_complex(ComplexF32, Type{ComplexF32}, Core.svec(), 1, 1, 1)
7273
@test !Core.Compiler.type_more_complex(Type{ComplexF32}, Any, Core.svec(Type{Type{ComplexF32}}), 1, 1, 1)
7374
@test Core.Compiler.type_more_complex(Type{ComplexF32}, Type{Type{ComplexF32}}, Core.svec(), 1, 1, 1)
74-
@test !Core.Compiler.type_more_complex(Type{ComplexF32}, ComplexF32, Core.svec(), 1, 1, 1)
75+
@test Core.Compiler.type_more_complex(Type{ComplexF32}, ComplexF32, Core.svec(), 1, 1, 1)
76+
@test Core.Compiler.limit_type_size(Type{ComplexF32}, ComplexF32, Union{}, 1, 1) == Type{<:Complex}
7577
@test Core.Compiler.type_more_complex(Type{ComplexF32}, Any, Core.svec(), 1, 1, 1)
7678
@test Core.Compiler.type_more_complex(Type{Type{ComplexF32}}, Type{ComplexF32}, Core.svec(Type{ComplexF32}), 1, 1, 1)
7779
@test Core.Compiler.type_more_complex(Type{Type{ComplexF32}}, ComplexF32, Core.svec(ComplexF32), 1, 1, 1)
7880
@test Core.Compiler.type_more_complex(Type{Type{Type{ComplexF32}}}, Type{Type{ComplexF32}}, Core.svec(Type{ComplexF32}), 1, 1, 1)
7981

8082
# n.b. Type{Type{Union{}} === Type{Core.TypeofBottom}
81-
@test !Core.Compiler.type_more_complex(Type{Union{}}, Any, Core.svec(), 1, 1, 1)
82-
@test !Core.Compiler.type_more_complex(Type{Type{Union{}}}, Any, Core.svec(), 1, 1, 1)
83+
@test Core.Compiler.type_more_complex(Type{Union{}}, Any, Core.svec(), 1, 1, 1)
84+
@test Core.Compiler.type_more_complex(Type{Type{Union{}}}, Any, Core.svec(), 1, 1, 1)
8385
@test Core.Compiler.type_more_complex(Type{Type{Type{Union{}}}}, Any, Core.svec(), 1, 1, 1)
8486
@test Core.Compiler.type_more_complex(Type{Type{Type{Union{}}}}, Type{Type{Union{}}}, Core.svec(Type{Type{Union{}}}), 1, 1, 1)
8587
@test Core.Compiler.type_more_complex(Type{Type{Type{Type{Union{}}}}}, Type{Type{Type{Union{}}}}, Core.svec(Type{Type{Type{Union{}}}}), 1, 1, 1)
8688

8789
@test !Core.Compiler.type_more_complex(Type{1}, Type{2}, Core.svec(), 1, 1, 1)
8890
@test Core.Compiler.type_more_complex(Type{Union{Float32,Float64}}, Union{Float32,Float64}, Core.svec(Union{Float32,Float64}), 1, 1, 1)
89-
@test !Core.Compiler.type_more_complex(Type{Union{Float32,Float64}}, Union{Float32,Float64}, Core.svec(Union{Float32,Float64}), 0, 1, 1)
91+
@test Core.Compiler.type_more_complex(Type{Union{Float32,Float64}}, Union{Float32,Float64}, Core.svec(Union{Float32,Float64}), 0, 1, 1)
9092
@test Core.Compiler.type_more_complex(Type{<:Union{Float32,Float64}}, Type{Union{Float32,Float64}}, Core.svec(Union{Float32,Float64}), 1, 1, 1)
9193
@test Core.Compiler.type_more_complex(Type{<:Union{Float32,Float64}}, Any, Core.svec(Union{Float32,Float64}), 1, 1, 1)
9294

@@ -101,6 +103,44 @@ let # 40336
101103
@test t !== r && t <: r
102104
end
103105

106+
@test Core.Compiler.limit_type_size(Type{Type{Type{Int}}}, Type, Union{}, 0, 0) == Type{<:Type}
107+
@test Core.Compiler.limit_type_size(Type{Type{Int}}, Type, Union{}, 0, 0) == Type{<:Type}
108+
@test Core.Compiler.limit_type_size(Type{Int}, Type, Union{}, 0, 0) == Type{Int}
109+
@test Core.Compiler.limit_type_size(Type{<:Int}, Type, Union{}, 0, 0) == Type{<:Int}
110+
@test Core.Compiler.limit_type_size(Type{ComplexF32}, ComplexF32, Union{}, 0, 0) == Type{<:Complex} # added nesting
111+
@test Core.Compiler.limit_type_size(Type{ComplexF32}, Type{ComplexF64}, Union{}, 0, 0) == Type{ComplexF32} # base matches
112+
@test Core.Compiler.limit_type_size(Type{ComplexF32}, Type, Union{}, 0, 0) == Type{<:Complex}
113+
@test_broken Core.Compiler.limit_type_size(Type{<:ComplexF64}, Type, Union{}, 0, 0) == Type{<:Complex}
114+
@test Core.Compiler.limit_type_size(Type{<:ComplexF64}, Type, Union{}, 0, 0) == Type #50692
115+
@test Core.Compiler.limit_type_size(Type{Union{ComplexF32,ComplexF64}}, Type, Union{}, 0, 0) == Type
116+
@test_broken Core.Compiler.limit_type_size(Type{Union{ComplexF32,ComplexF64}}, Type, Union{}, 0, 0) == Type{<:Complex} #50692
117+
@test Core.Compiler.limit_type_size(Type{Union{Float32,Float64}}, Type, Union{}, 0, 0) == Type
118+
@test Core.Compiler.limit_type_size(Type{Union{Int,Type{Int}}}, Type{Type{Int}}, Union{}, 0, 0) == Type
119+
@test Core.Compiler.limit_type_size(Type{Union{Int,Type{Int}}}, Union{Type{Int},Type{Type{Int}}}, Union{}, 0, 0) == Type
120+
@test Core.Compiler.limit_type_size(Type{Union{Int,Type{Int}}}, Type{Union{Type{Int},Type{Type{Int}}}}, Union{}, 0, 0) == Type{Union{Int64, Type{Int64}}}
121+
@test Core.Compiler.limit_type_size(Type{Union{Int,Type{Int}}}, Type{Type{Int}}, Union{}, 0, 0) == Type
122+
123+
124+
# issue #43296 #43296
125+
struct C43296{t,I} end
126+
r43296(b) = r43296(typeof(b))
127+
r43296(::Type) = nothing
128+
r43296(::Nothing) = nonexistent
129+
r43296(::Type{C43296{c,d}}) where {c,d} = f43296(r43296(c), e)
130+
f43296(::Nothing, :) = nothing
131+
f43296(g, :) = h
132+
k43296(b, j, :) = l
133+
k43296(b, j, ::Nothing) = b
134+
i43296(b, j) = k43296(b, j, r43296(j))
135+
@test only(Base.return_types(i43296, (Int, C43296{C43296{C43296{Val, Tuple}, Tuple}}))) == Int
136+
137+
abstract type e43296{a, j} <: AbstractArray{a, j} end
138+
abstract type b43296{a, j, c, d} <: e43296{a, j} end
139+
struct h43296{a, j, f, d, i} <: b43296{a, j, f, d} end
140+
Base.ndims(::Type{f}) where {f<:e43296} = ndims(supertype(f))
141+
Base.ndims(g::e43296) = ndims(typeof(g))
142+
@test only(Base.return_types(ndims, (h43296{Any, 0, Any, Int, Any},))) == Int
143+
104144
@test Core.Compiler.unionlen(Union{}) == 1
105145
@test Core.Compiler.unionlen(Int8) == 1
106146
@test Core.Compiler.unionlen(Union{Int8, Int16}) == 2

0 commit comments

Comments
 (0)