Skip to content

Commit ae789ca

Browse files
authored
Fix incorrect fieldtype tfunc (#38148)
`fieldtype_tfunc` was returning `Type` as the widest possible return value, but this is not correct, since fields of unwrapped DataTypes can legally be TypeVars. This was in fact causing incorrect execution in the isdefined_tfunc, though on master it happened to accidentally do the correct thing. Fix this by returning `Any` rather than `Type` as the widest type from `fieldtype_tfunc`, but while we're at it, improve the precision of `fieldtype_tfunc` a bit, such that this widening doesn't regress inference precision in some important cases.
1 parent b8df95f commit ae789ca

File tree

3 files changed

+26
-13
lines changed

3 files changed

+26
-13
lines changed

base/compiler/tfuncs.jl

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -295,13 +295,16 @@ function isdefined_tfunc(@nospecialize(arg1), @nospecialize(sym))
295295
end
296296
elseif idx <= 0 || (!isvatuple(a1) && idx > fieldcount(a1))
297297
return Const(false)
298-
elseif !isvatuple(a1) && isbitstype(fieldtype(a1, idx))
299-
return Const(true)
300298
elseif isa(arg1, Const)
301299
arg1v = (arg1::Const).val
302300
if !ismutable(arg1v) || isdefined(arg1v, idx) || (isa(arg1v, DataType) && is_dt_const_field(idx))
303301
return Const(isdefined(arg1v, idx))
304302
end
303+
elseif !isvatuple(a1)
304+
fieldT = fieldtype(a1, idx)
305+
if isa(fieldT, DataType) && isbitstype(fieldT)
306+
return Const(true)
307+
end
305308
end
306309
end
307310
end
@@ -975,7 +978,9 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
975978
return Bottom
976979
end
977980
if s0 === Any || s0 === Type || DataType s0 || UnionAll s0
978-
return Type
981+
# For a generic DataType, one of the fields could still be a TypeVar
982+
# which is not a Type
983+
return Union{Type, TypeVar}
979984
end
980985
# fieldtype only accepts Types
981986
if isa(s0, Const) && !(isa(s0.val, DataType) || isa(s0.val, UnionAll) || isa(s0.val, Union))
@@ -1003,11 +1008,18 @@ function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name))
10031008
return tmerge(_fieldtype_tfunc(rewrap(u.a, s), exact, name),
10041009
_fieldtype_tfunc(rewrap(u.b, s), exact, name))
10051010
end
1006-
u isa DataType || return Type
1007-
u.abstract && return Type
1011+
u isa DataType || return Union{Type, TypeVar}
1012+
if u.abstract
1013+
# Abstract types have no fields
1014+
exact && return Bottom
1015+
# Type{...} without free typevars has no subtypes, so it is actually
1016+
# exact, even if `exact` is false.
1017+
isType(u) && !has_free_typevars(u.parameters[1]) && return Bottom
1018+
return Union{Type, TypeVar}
1019+
end
10081020
if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u)
10091021
# TODO: better approximate inference
1010-
return Type
1022+
return Union{Type, TypeVar}
10111023
end
10121024
ftypes = datatype_fieldtypes(u)
10131025
if isempty(ftypes)

test/compiler/inference.jl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -653,8 +653,8 @@ let fieldtype_tfunc = Core.Compiler.fieldtype_tfunc,
653653
@test fieldtype_tfunc(Union{Type{Base.RefValue{T}}, Type{Int32}} where {T<:Real}, Const(:x)) == Type{<:Real}
654654
@test fieldtype_tfunc(Union{Type{Base.RefValue{<:Array}}, Type{Int32}}, Const(:x)) == Type{Array}
655655
@test fieldtype_tfunc(Union{Type{Base.RefValue{<:Real}}, Type{Int32}}, Const(:x)) == Const(Real)
656-
@test fieldtype_tfunc(Const(Union{Base.RefValue{<:Real}, Type{Int32}}), Const(:x)) == Type
657-
@test fieldtype_tfunc(Type{Union{Base.RefValue{T}, Type{Int32}}} where {T<:Real}, Const(:x)) == Type
656+
@test fieldtype_tfunc(Const(Union{Base.RefValue{<:Real}, Type{Int32}}), Const(:x)) == Const(Real)
657+
@test fieldtype_tfunc(Type{Union{Base.RefValue{T}, Type{Int32}}} where {T<:Real}, Const(:x)) == Type{<:Real}
658658
@test fieldtype_tfunc(Type{<:Tuple}, Const(1)) == Type
659659
@test fieldtype_tfunc(Type{<:Tuple}, Any) == Type
660660
@test fieldtype_nothrow(Type{Base.RefValue{<:Real}}, Const(:x))
@@ -673,6 +673,7 @@ let fieldtype_tfunc = Core.Compiler.fieldtype_tfunc,
673673
@test fieldtype_nothrow(Type{Tuple{Vararg{Int}}}, Const(2))
674674
@test fieldtype_nothrow(Type{Tuple{Vararg{Int}}}, Const(42))
675675
@test !fieldtype_nothrow(Type{<:Tuple{Vararg{Int}}}, Const(1))
676+
@test TypeVar <: fieldtype_tfunc(Any, Any)
676677
end
677678

678679
# issue #11480
@@ -2828,10 +2829,10 @@ end
28282829
@test Core.Compiler.return_type(apply26826, Tuple{typeof(getfield), Tuple{Int}, Any, Vararg}) == Int
28292830
@test Core.Compiler.return_type(apply26826, Tuple{typeof(getfield), Tuple{Int}, Any, Any, Vararg}) == Int
28302831
@test Core.Compiler.return_type(apply26826, Tuple{typeof(getfield), Any, Any, Any, Any, Vararg}) == Union{}
2831-
@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Vararg}) == Type
2832-
@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Vararg}) == Type
2833-
@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Vararg}) == Type
2834-
@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Any, Vararg}) == Type
2832+
@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Vararg}) == Union{Type, TypeVar}
2833+
@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Vararg}) == Union{Type, TypeVar}
2834+
@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Vararg}) == Union{Type, TypeVar}
2835+
@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Any, Vararg}) == Union{Type, TypeVar}
28352836
@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Any, Any, Vararg}) == Union{}
28362837
@test Core.Compiler.return_type(apply26826, Tuple{typeof(Core.apply_type), Vararg}) == Type
28372838
@test Core.Compiler.return_type(apply26826, Tuple{typeof(Core.apply_type), Any, Vararg}) == Type

test/namedtuple.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ namedtuple_get_a(x) = x.a
167167
@test Base.return_types(namedtuple_get_a, (typeof((b=1,a="")),)) == Any[String]
168168

169169
namedtuple_fieldtype_a(x) = fieldtype(typeof(x), :a)
170-
@test Base.return_types(namedtuple_fieldtype_a, (NamedTuple,)) == Any[Type]
170+
@test Base.return_types(namedtuple_fieldtype_a, (NamedTuple,)) == Any[Union{Type, TypeVar}]
171171
@test Base.return_types(namedtuple_fieldtype_a, (typeof((b=1,a="")),)) == Any[Type{String}]
172172
namedtuple_fieldtype__(x, y) = fieldtype(typeof(x), y)
173173
@test Base.return_types(namedtuple_fieldtype__, (typeof((b=1,a="")),Symbol))[1] >: Union{Type{Int}, Type{String}}

0 commit comments

Comments
 (0)