Skip to content

Commit 3a60e87

Browse files
authored
inference: fix fieldtype tfunc design (#31670)
fix #31666
1 parent 1dc8236 commit 3a60e87

File tree

2 files changed

+80
-19
lines changed

2 files changed

+80
-19
lines changed

base/compiler/tfuncs.jl

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ function fieldcount_noerror(@nospecialize t)
592592
end
593593

594594

595-
function try_compute_fieldidx(@nospecialize(typ), @nospecialize(field))
595+
function try_compute_fieldidx(typ::DataType, @nospecialize(field))
596596
if isa(field, Symbol)
597597
field = fieldindex(typ, field, false)
598598
field == 0 && return nothing
@@ -802,6 +802,7 @@ fieldtype_tfunc(@nospecialize(s0), @nospecialize(name), @nospecialize(inbounds))
802802
fieldtype_tfunc(s0, name)
803803

804804
function fieldtype_nothrow(@nospecialize(s0), @nospecialize(name))
805+
s0 === Bottom && return true # unreachable
805806
if s0 === Any || s0 === Type || DataType s0 || UnionAll s0
806807
# We have no idea
807808
return false
@@ -815,17 +816,27 @@ function fieldtype_nothrow(@nospecialize(s0), @nospecialize(name))
815816

816817
su = unwrap_unionall(s0)
817818
if isa(su, Union)
818-
return fieldtype_nothrow(rewrap_unionall(su.a, s0), name) && fieldtype_nothrow(rewrap_unionall(su.b, s0), name)
819+
return fieldtype_nothrow(rewrap_unionall(su.a, s0), name) &&
820+
fieldtype_nothrow(rewrap_unionall(su.b, s0), name)
819821
end
820822

821-
s = instanceof_tfunc(s0)[1]
822-
u = unwrap_unionall(s)
823-
return _fieldtype_nothrow(u, name)
823+
s, exact = instanceof_tfunc(s0)
824+
s === Bottom && return false # always
825+
return _fieldtype_nothrow(s, exact, name)
824826
end
825827

826-
function _fieldtype_nothrow(@nospecialize(u), name::Const)
828+
function _fieldtype_nothrow(@nospecialize(s), exact::Bool, name::Const)
829+
u = unwrap_unionall(s)
827830
if isa(u, Union)
828-
return _fieldtype_nothrow(u.a, name) || _fieldtype_nothrow(u.b, name)
831+
a = _fieldtype_nothrow(u.a, exact, name)
832+
b = _fieldtype_nothrow(u.b, exact, name)
833+
return exact ? (a || b) : (a && b)
834+
end
835+
u isa DataType || return false
836+
u.abstract && return false
837+
if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u)
838+
# TODO: better approximate inference
839+
return false
829840
end
830841
fld = name.val
831842
if isa(fld, Symbol)
@@ -844,6 +855,9 @@ function _fieldtype_nothrow(@nospecialize(u), name::Const)
844855
end
845856

846857
function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
858+
if s0 === Bottom
859+
return Bottom
860+
end
847861
if s0 === Any || s0 === Type || DataType s0 || UnionAll s0
848862
return Type
849863
end
@@ -855,18 +869,28 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
855869
return Bottom
856870
end
857871

858-
s = instanceof_tfunc(s0)[1]
859-
u = unwrap_unionall(s)
860-
861-
if isa(u, Union)
862-
return tmerge(rewrap(fieldtype_tfunc(Type{u.a}, name), s),
863-
rewrap(fieldtype_tfunc(Type{u.b}, name), s))
872+
su = unwrap_unionall(s0)
873+
if isa(su, Union)
874+
return tmerge(fieldtype_tfunc(rewrap(su.a, s0), name),
875+
fieldtype_tfunc(rewrap(su.b, s0), name))
864876
end
865877

866-
if !isa(u, DataType) || u.abstract
867-
return Type
878+
s, exact = instanceof_tfunc(s0)
879+
s === Bottom && return Bottom
880+
return _fieldtype_tfunc(s, exact, name)
881+
end
882+
883+
function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name))
884+
exact = exact && !has_free_typevars(s)
885+
u = unwrap_unionall(s)
886+
if isa(u, Union)
887+
return tmerge(_fieldtype_tfunc(rewrap(u.a, s), exact, name),
888+
_fieldtype_tfunc(rewrap(u.b, s), exact, name))
868889
end
890+
u isa DataType || return Type
891+
u.abstract && return Type
869892
if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u)
893+
# TODO: better approximate inference
870894
return Type
871895
end
872896
ftypes = u.types
@@ -875,12 +899,25 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
875899
end
876900

877901
if !isa(name, Const)
902+
name = widenconst(name)
878903
if !(Int <: name || Symbol <: name)
879904
return Bottom
880905
end
881906
t = Bottom
882907
for i in 1:length(ftypes)
883-
t = tmerge(t, fieldtype_tfunc(s0, Const(i)))
908+
ft1 = unwrapva(ftypes[i])
909+
exactft1 = exact || !has_free_typevars(ft1)
910+
ft1 = rewrap_unionall(ft1, s)
911+
if exactft1
912+
if issingletontype(ft1)
913+
ft1 = Const(ft1) # ft unique via type cache
914+
else
915+
ft1 = Type{ft1}
916+
end
917+
else
918+
ft1 = Type{ft} where ft<:ft1
919+
end
920+
t = tmerge(t, ft1)
884921
t === Any && break
885922
end
886923
return t
@@ -902,10 +939,13 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
902939
ft = ftypes[fld]
903940
end
904941

905-
exact = (isa(s0, Const) || isType(s0)) && !has_free_typevars(s)
942+
exactft = exact || !has_free_typevars(ft)
906943
ft = rewrap_unionall(ft, s)
907-
if exact
908-
return Const(ft)
944+
if exactft
945+
if issingletontype(ft)
946+
return Const(ft) # ft unique via type cache
947+
end
948+
return Type{ft}
909949
end
910950
return Type{<:ft}
911951
end

test/compiler/inference.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,27 @@ mutable struct HasAbstractlyTypedField
611611
end
612612
f_infer_abstract_fieldtype() = fieldtype(HasAbstractlyTypedField, :x)
613613
@test Base.return_types(f_infer_abstract_fieldtype, ()) == Any[Type{Union{Int,String}}]
614+
let fieldtype_tfunc = Core.Compiler.fieldtype_tfunc,
615+
fieldtype_nothrow = Core.Compiler.fieldtype_nothrow
616+
@test fieldtype_tfunc(Union{}, :x) == Union{}
617+
@test fieldtype_tfunc(Union{Type{Int32}, Int32}, Const(:x)) == Union{}
618+
@test fieldtype_tfunc(Union{Type{Base.RefValue{T}}, Type{Int32}} where {T<:Array}, Const(:x)) == Type{<:Array}
619+
@test fieldtype_tfunc(Union{Type{Base.RefValue{T}}, Type{Int32}} where {T<:Real}, Const(:x)) == Type{<:Real}
620+
@test fieldtype_tfunc(Union{Type{Base.RefValue{<:Array}}, Type{Int32}}, Const(:x)) == Type{Array}
621+
@test fieldtype_tfunc(Union{Type{Base.RefValue{<:Real}}, Type{Int32}}, Const(:x)) == Const(Real)
622+
@test fieldtype_tfunc(Const(Union{Base.RefValue{<:Real}, Type{Int32}}), Const(:x)) == Type
623+
@test fieldtype_tfunc(Type{Union{Base.RefValue{T}, Type{Int32}}} where {T<:Real}, Const(:x)) == Type
624+
@test fieldtype_nothrow(Type{Base.RefValue{<:Real}}, Const(:x))
625+
@test !fieldtype_nothrow(Type{Union{}}, Const(:x))
626+
@test !fieldtype_nothrow(Union{Type{Base.RefValue{T}}, Int32} where {T<:Real}, Const(:x))
627+
@test !fieldtype_nothrow(Union{Type{Base.RefValue{<:Real}}, Int32}, Const(:x))
628+
@test fieldtype_nothrow(Const(Union{Base.RefValue{<:Real}, Int32}), Const(:x))
629+
@test !fieldtype_nothrow(Type{Union{Base.RefValue{T}, Int32}} where {T<:Real}, Const(:x)) # improvable?
630+
@test fieldtype_nothrow(Union{Type{Base.RefValue{T}}, Type{Base.RefValue{Any}}} where {T<:Real}, Const(:x))
631+
@test fieldtype_nothrow(Union{Type{Base.RefValue{<:Real}}, Type{Base.RefValue{Any}}}, Const(:x))
632+
@test fieldtype_nothrow(Const(Union{Base.RefValue{<:Real}, Base.RefValue{Any}}), Const(:x))
633+
@test fieldtype_nothrow(Type{Union{Base.RefValue{T}, Base.RefValue{Any}}} where {T<:Real}, Const(:x))
634+
end
614635

615636
# issue #11480
616637
@noinline f11480(x,y) = x

0 commit comments

Comments
 (0)