Skip to content

Commit 1c831fc

Browse files
committed
inference: fix fieldtype tfunc design
fix #31666
1 parent c9786e6 commit 1c831fc

File tree

2 files changed

+61
-17
lines changed

2 files changed

+61
-17
lines changed

base/compiler/tfuncs.jl

Lines changed: 42 additions & 17 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,24 @@ 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

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

826-
function _fieldtype_nothrow(@nospecialize(u), name::Const)
828+
function _fieldtype_nothrow(@nospecialize(s), 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+
return _fieldtype_nothrow(u.a, name) && _fieldtype_nothrow(u.b, name)
832+
end
833+
u isa DataType || return false
834+
u.abstract && return true
835+
if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u)
836+
return false
829837
end
830838
fld = name.val
831839
if isa(fld, Symbol)
@@ -844,6 +852,9 @@ function _fieldtype_nothrow(@nospecialize(u), name::Const)
844852
end
845853

846854
function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
855+
if s0 === Bottom
856+
return Bottom
857+
end
847858
if s0 === Any || s0 === Type || DataType s0 || UnionAll s0
848859
return Type
849860
end
@@ -855,17 +866,26 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
855866
return Bottom
856867
end
857868

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))
869+
su = unwrap_unionall(s0)
870+
if isa(su, Union)
871+
return tmerge(fieldtype_tfunc(rewrap(su.a, s0), name),
872+
fieldtype_tfunc(rewrap(su.b, s0), name))
864873
end
865874

866-
if !isa(u, DataType) || u.abstract
867-
return Type
875+
s, exact = instanceof_tfunc(s0)
876+
s === Bottom && return Bottom
877+
return _fieldtype_tfunc(s, exact, name)
878+
end
879+
880+
function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name))
881+
exact = exact && !has_free_typevars(s)
882+
u = unwrap_unionall(s)
883+
if isa(u, Union)
884+
return tmerge(_fieldtype_tfunc(rewrap(u.a, s), exact, name),
885+
_fieldtype_tfunc(rewrap(u.b, s), exact, name))
868886
end
887+
u isa DataType || return Type
888+
u.abstract && return Type
869889
if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u)
870890
return Type
871891
end
@@ -875,12 +895,17 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
875895
end
876896

877897
if !isa(name, Const)
898+
name = widenconst(name)
878899
if !(Int <: name || Symbol <: name)
879900
return Bottom
880901
end
881902
t = Bottom
882903
for i in 1:length(ftypes)
883-
t = tmerge(t, fieldtype_tfunc(s0, Const(i)))
904+
ft1 = unwrapva(ftypes[i])
905+
exactft1 = exact || !has_free_typevars(ft1)
906+
ft1 = rewrap_unionall(ft1, s)
907+
ft1 = exactft1 ? Const(ft1) : Type{ft} where ft<:ft1
908+
t = tmerge(t, ft1)
884909
t === Any && break
885910
end
886911
return t
@@ -902,9 +927,9 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
902927
ft = ftypes[fld]
903928
end
904929

905-
exact = (isa(s0, Const) || isType(s0)) && !has_free_typevars(s)
930+
exactft = exact || !has_free_typevars(ft)
906931
ft = rewrap_unionall(ft, s)
907-
if exact
932+
if exactft
908933
return Const(ft)
909934
end
910935
return Type{<:ft}

test/compiler/inference.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,25 @@ 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<:Real}, Const(:x)) == Type{<:Real}
619+
@test fieldtype_tfunc(Union{Type{Base.RefValue{<:Real}}, Type{Int32}}, Const(:x)) == Const(Real)
620+
@test fieldtype_tfunc(Const(Union{Base.RefValue{<:Real}, Type{Int32}}), Const(:x)) == Type
621+
@test fieldtype_tfunc(Type{Union{Base.RefValue{T}, Type{Int32}}} where {T<:Real}, Const(:x)) == Type
622+
@test fieldtype_nothrow(Type{Base.RefValue{<:Real}}, Const(:x))
623+
@test !fieldtype_nothrow(Type{Union{}}, Const(:x))
624+
@test !fieldtype_nothrow(Union{Type{Base.RefValue{T}}, Int32} where {T<:Real}, Const(:x))
625+
@test !fieldtype_nothrow(Union{Type{Base.RefValue{<:Real}}, Int32}, Const(:x))
626+
@test !fieldtype_nothrow(Const(Union{Base.RefValue{<:Real}, Int32}), Const(:x))
627+
@test !fieldtype_nothrow(Type{Union{Base.RefValue{T}, Int32}} where {T<:Real}, Const(:x))
628+
@test fieldtype_nothrow(Union{Type{Base.RefValue{T}}, Type{Base.RefValue{Any}}} where {T<:Real}, Const(:x))
629+
@test fieldtype_nothrow(Union{Type{Base.RefValue{<:Real}}, Type{Base.RefValue{Any}}}, Const(:x))
630+
@test fieldtype_nothrow(Const(Union{Base.RefValue{<:Real}, Base.RefValue{Any}}), Const(:x))
631+
@test fieldtype_nothrow(Type{Union{Base.RefValue{T}, Base.RefValue{Any}}} where {T<:Real}, Const(:x))
632+
end
614633

615634
# issue #11480
616635
@noinline f11480(x,y) = x

0 commit comments

Comments
 (0)