Skip to content

Commit

Permalink
inference: relax type_more_complex for Type (#42901)
Browse files Browse the repository at this point in the history
If the object is not a potential Type{...}, we can allow greater
flexibility in recursion.
  • Loading branch information
vtjnash authored Nov 8, 2021
1 parent 2539a67 commit 27f579f
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 24 deletions.
58 changes: 36 additions & 22 deletions base/compiler/typelimits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ function is_derived_type(@nospecialize(t), @nospecialize(c), mindepth::Int)
if t === c
return mindepth <= 1
end
isvarargtype(t) && (t = unwrapva(t))
isvarargtype(c) && (c = unwrapva(c))
if isa(c, Union)
# see if it is one of the elements of the union
return is_derived_type(t, c.a, mindepth) || is_derived_type(t, c.b, mindepth)
elseif isa(c, UnionAll)
# see if it is derived from the body
# also handle the var here, since this construct bounds the mindepth to the smallest possible value
return is_derived_type(t, c.var.ub, mindepth) || is_derived_type(t, c.body, mindepth)
elseif isvarargtype(c)
return is_derived_type(t, unwrapva(c), mindepth)
elseif isa(c, DataType)
if mindepth > 0
mindepth -= 1
Expand Down Expand Up @@ -114,10 +114,14 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec
return Union{a, b}
end
elseif isa(t, DataType)
if isType(t) # allow taking typeof as Type{...}, but ensure it doesn't start nesting
if isType(t) # see equivalent case in type_more_complex
tt = unwrap_unionall(t.parameters[1])
(!isa(tt, DataType) || isType(tt)) && (depth += 1)
is_derived_type_from_any(tt, sources, depth) && return t
if isa(tt, Union) || isa(tt, TypeVar) || isType(tt)
is_derived_type_from_any(tt, sources, depth + 1) && return t
else
isType(c) && (c = unwrap_unionall(c.parameters[1]))
type_more_complex(tt, c, sources, depth, 0, 0) || return t
end
return Type
elseif isa(c, DataType)
tP = t.parameters
Expand Down Expand Up @@ -167,6 +171,11 @@ end

# helper function of `_limit_type_size`, which has the right to take and return `TypeVar` / `Vararg`
function __limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVector, depth::Int, allowed_tuplelen::Int)
cN = 0
if isvarargtype(c) # Tuple{Vararg{T}} --> Tuple{T} is OK
isdefined(c, :N) && (cN = c.N)
c = unwrapva(c)
end
if isa(c, TypeVar)
if isa(t, TypeVar) && t.ub === c.ub && (t.lb === Union{} || t.lb === c.lb)
return t # it's ok to change the name, or widen `lb` to Union{}, so we can handle this immediately here
Expand All @@ -176,15 +185,17 @@ function __limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVe
# don't have a matching TypeVar in comparison, so we keep just the upper bound
return __limit_type_size(t.ub, c, sources, depth, allowed_tuplelen)
elseif isvarargtype(t)
isvarargtype(c) || return Vararg
VaT = __limit_type_size(unwrapva(t), unwrapva(c), sources, depth + 1, 0)
if isdefined(t, :N) && (isa(t.N, TypeVar) || (isdefined(c, :N) && t.N === c.N))
return Vararg{VaT, t.N}
# Tuple{Vararg{T,N}} --> Tuple{Vararg{S,M}} is OK
# Tuple{T} --> Tuple{Vararg{T}} is OK
# but S must be more limited than T, and must not introduce a new number for M
VaT = __limit_type_size(unwrapva(t), c, sources, depth + 1, 0)
if isdefined(t, :N)
tN = t.N
if isa(tN, TypeVar) || tN === cN
return Vararg{VaT, tN}
end
end
return Vararg{VaT}
elseif isvarargtype(c)
# Tuple{Vararg{T}} --> Tuple{T} is OK
return __limit_type_size(t, unwrapva(c), sources, depth, 0)
else
return _limit_type_size(t, c, sources, depth, allowed_tuplelen)
end
Expand All @@ -205,6 +216,8 @@ function type_more_complex(@nospecialize(t), @nospecialize(c), sources::SimpleVe
return false # t isn't something new
end
# peel off wrappers
isvarargtype(t) && (t = unwrapva(t))
isvarargtype(c) && (c = unwrapva(c))
if isa(c, UnionAll)
# allow wrapping type with fewer UnionAlls than comparison if in a covariant context
if !isa(t, UnionAll) && tupledepth == 0
Expand Down Expand Up @@ -233,18 +246,19 @@ function type_more_complex(@nospecialize(t), @nospecialize(c), sources::SimpleVe
return t !== 1 && !(0 <= t < c) # alternatively, could use !(abs(t) <= abs(c) || abs(t) < n) for some n
end
# base case for data types
if isvarargtype(t)
if isvarargtype(c)
return type_more_complex(unwrapva(t), unwrapva(c), sources, depth + 1, tupledepth, 0)
end
elseif isa(t, DataType)
if isa(t, DataType)
tP = t.parameters
if isvarargtype(c)
return type_more_complex(t, unwrapva(c), sources, depth, tupledepth, 0)
elseif isType(t) # allow taking typeof any source type anywhere as Type{...}, as long as it isn't nesting Type{Type{...}}
if isType(t)
# Treat Type{T} and T as equivalent to allow taking typeof any
# source type (DataType) anywhere as Type{...}, as long as it isn't
# nesting as Type{Type{...}}
tt = unwrap_unionall(t.parameters[1])
(!isa(tt, DataType) || isType(tt)) && (depth += 1)
return !is_derived_type_from_any(tt, sources, depth)
if isa(tt, Union) || isa(tt, TypeVar) || isType(tt)
return !is_derived_type_from_any(tt, sources, depth + 1)
else
isType(c) && (c = unwrap_unionall(c.parameters[1]))
return type_more_complex(tt, c, sources, depth, 0, 0)
end
elseif isa(c, DataType) && t.name === c.name
cP = c.parameters
length(cP) < length(tP) && return true
Expand Down
38 changes: 36 additions & 2 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,42 @@ end

# obtain Vararg with 2 undefined fields
let va = ccall(:jl_type_intersection_with_env, Any, (Any, Any), Tuple{Tuple}, Tuple{Tuple{Vararg{Any, N}}} where N)[2][1]
@test Core.Compiler.__limit_type_size(Tuple, va, Core.svec(va, Union{}), 2, 2) === Any
end
@test Core.Compiler.__limit_type_size(Tuple, va, Core.svec(va, Union{}), 2, 2) === Tuple
end

# issue #42835
@test !Core.Compiler.type_more_complex(Int, Any, Core.svec(), 1, 1, 1)
@test !Core.Compiler.type_more_complex(Int, Type{Int}, Core.svec(), 1, 1, 1)
@test !Core.Compiler.type_more_complex(Type{Int}, Any, Core.svec(), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Type{Int}}, Type{Int}, Core.svec(Type{Int}), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Type{Int}}, Int, Core.svec(Type{Int}), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Type{Int}}, Any, Core.svec(), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Type{Type{Int}}}, Type{Type{Int}}, Core.svec(Type{Type{Int}}), 1, 1, 1)

@test Core.Compiler.type_more_complex(ComplexF32, Any, Core.svec(), 1, 1, 1)
@test !Core.Compiler.type_more_complex(ComplexF32, Any, Core.svec(Type{ComplexF32}), 1, 1, 1)
@test Core.Compiler.type_more_complex(ComplexF32, Type{ComplexF32}, Core.svec(), 1, 1, 1)
@test !Core.Compiler.type_more_complex(Type{ComplexF32}, Any, Core.svec(Type{Type{ComplexF32}}), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{ComplexF32}, Type{Type{ComplexF32}}, Core.svec(), 1, 1, 1)
@test !Core.Compiler.type_more_complex(Type{ComplexF32}, ComplexF32, Core.svec(), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{ComplexF32}, Any, Core.svec(), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Type{ComplexF32}}, Type{ComplexF32}, Core.svec(Type{ComplexF32}), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Type{ComplexF32}}, ComplexF32, Core.svec(ComplexF32), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Type{Type{ComplexF32}}}, Type{Type{ComplexF32}}, Core.svec(Type{ComplexF32}), 1, 1, 1)

# n.b. Type{Type{Union{}} === Type{Core.TypeofBottom}
@test !Core.Compiler.type_more_complex(Type{Union{}}, Any, Core.svec(), 1, 1, 1)
@test !Core.Compiler.type_more_complex(Type{Type{Union{}}}, Any, Core.svec(), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Type{Type{Union{}}}}, Any, Core.svec(), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Type{Type{Union{}}}}, Type{Type{Union{}}}, Core.svec(Type{Type{Union{}}}), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Type{Type{Type{Union{}}}}}, Type{Type{Type{Union{}}}}, Core.svec(Type{Type{Type{Union{}}}}), 1, 1, 1)

@test !Core.Compiler.type_more_complex(Type{1}, Type{2}, Core.svec(), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{Union{Float32,Float64}}, Union{Float32,Float64}, Core.svec(Union{Float32,Float64}), 1, 1, 1)
@test !Core.Compiler.type_more_complex(Type{Union{Float32,Float64}}, Union{Float32,Float64}, Core.svec(Union{Float32,Float64}), 0, 1, 1)
@test_broken Core.Compiler.type_more_complex(Type{<:Union{Float32,Float64}}, Type{Union{Float32,Float64}}, Core.svec(Union{Float32,Float64}), 1, 1, 1)
@test Core.Compiler.type_more_complex(Type{<:Union{Float32,Float64}}, Any, Core.svec(Union{Float32,Float64}), 1, 1, 1)


let # 40336
t = Type{Type{Int}}
Expand Down

0 comments on commit 27f579f

Please sign in to comment.