Skip to content

Commit b215ec4

Browse files
vtjnashKristofferC
authored andcommitted
inference: fix fieldtype tfunc design (#31670)
fix #31666 (cherry picked from commit 3a60e87)
1 parent afe3a87 commit b215ec4

File tree

2 files changed

+84
-18
lines changed

2 files changed

+84
-18
lines changed

base/compiler/tfuncs.jl

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ function fieldcount_noerror(@nospecialize t)
511511
end
512512

513513

514-
function try_compute_fieldidx(@nospecialize(typ), @nospecialize(field))
514+
function try_compute_fieldidx(typ::DataType, @nospecialize(field))
515515
if isa(field, Symbol)
516516
field = fieldindex(typ, field, false)
517517
field == 0 && return nothing
@@ -710,6 +710,7 @@ fieldtype_tfunc(@nospecialize(s0), @nospecialize(name), @nospecialize(inbounds))
710710
fieldtype_tfunc(s0, name)
711711

712712
function fieldtype_nothrow(@nospecialize(s0), @nospecialize(name))
713+
s0 === Bottom && return true # unreachable
713714
if s0 === Any || s0 === Type || DataType s0 || UnionAll s0
714715
# We have no idea
715716
return false
@@ -721,14 +722,29 @@ function fieldtype_nothrow(@nospecialize(s0), @nospecialize(name))
721722
return false
722723
end
723724

724-
s = instanceof_tfunc(s0)[1]
725-
u = unwrap_unionall(s)
726-
return _fieldtype_nothrow(u, name)
725+
su = unwrap_unionall(s0)
726+
if isa(su, Union)
727+
return fieldtype_nothrow(rewrap_unionall(su.a, s0), name) &&
728+
fieldtype_nothrow(rewrap_unionall(su.b, s0), name)
729+
end
730+
731+
s, exact = instanceof_tfunc(s0)
732+
s === Bottom && return false # always
733+
return _fieldtype_nothrow(s, exact, name)
727734
end
728735

729-
function _fieldtype_nothrow(@nospecialize(u), name::Const)
736+
function _fieldtype_nothrow(@nospecialize(s), exact::Bool, name::Const)
737+
u = unwrap_unionall(s)
730738
if isa(u, Union)
731-
return _fieldtype_nothrow(u.a, name) && _fieldtype_nothrow(u.b, name)
739+
a = _fieldtype_nothrow(u.a, exact, name)
740+
b = _fieldtype_nothrow(u.b, exact, name)
741+
return exact ? (a || b) : (a && b)
742+
end
743+
u isa DataType || return false
744+
u.abstract && return false
745+
if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u)
746+
# TODO: better approximate inference
747+
return false
732748
end
733749
fld = name.val
734750
if isa(fld, Symbol)
@@ -747,6 +763,9 @@ function _fieldtype_nothrow(@nospecialize(u), name::Const)
747763
end
748764

749765
function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
766+
if s0 === Bottom
767+
return Bottom
768+
end
750769
if s0 === Any || s0 === Type || DataType s0 || UnionAll s0
751770
return Type
752771
end
@@ -758,18 +777,28 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
758777
return Bottom
759778
end
760779

761-
s = instanceof_tfunc(s0)[1]
762-
u = unwrap_unionall(s)
763-
764-
if isa(u, Union)
765-
return tmerge(rewrap(fieldtype_tfunc(Type{u.a}, name), s),
766-
rewrap(fieldtype_tfunc(Type{u.b}, name), s))
780+
su = unwrap_unionall(s0)
781+
if isa(su, Union)
782+
return tmerge(fieldtype_tfunc(rewrap(su.a, s0), name),
783+
fieldtype_tfunc(rewrap(su.b, s0), name))
767784
end
768785

769-
if !isa(u, DataType) || u.abstract
770-
return Type
786+
s, exact = instanceof_tfunc(s0)
787+
s === Bottom && return Bottom
788+
return _fieldtype_tfunc(s, exact, name)
789+
end
790+
791+
function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name))
792+
exact = exact && !has_free_typevars(s)
793+
u = unwrap_unionall(s)
794+
if isa(u, Union)
795+
return tmerge(_fieldtype_tfunc(rewrap(u.a, s), exact, name),
796+
_fieldtype_tfunc(rewrap(u.b, s), exact, name))
771797
end
798+
u isa DataType || return Type
799+
u.abstract && return Type
772800
if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u)
801+
# TODO: better approximate inference
773802
return Type
774803
end
775804
ftypes = u.types
@@ -778,12 +807,25 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
778807
end
779808

780809
if !isa(name, Const)
810+
name = widenconst(name)
781811
if !(Int <: name || Symbol <: name)
782812
return Bottom
783813
end
784814
t = Bottom
785815
for i in 1:length(ftypes)
786-
t = tmerge(t, fieldtype_tfunc(s0, Const(i)))
816+
ft1 = unwrapva(ftypes[i])
817+
exactft1 = exact || !has_free_typevars(ft1)
818+
ft1 = rewrap_unionall(ft1, s)
819+
if exactft1
820+
if issingletontype(ft1)
821+
ft1 = Const(ft1) # ft unique via type cache
822+
else
823+
ft1 = Type{ft1}
824+
end
825+
else
826+
ft1 = Type{ft} where ft<:ft1
827+
end
828+
t = tmerge(t, ft1)
787829
t === Any && break
788830
end
789831
return t
@@ -805,10 +847,13 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name))
805847
ft = ftypes[fld]
806848
end
807849

808-
exact = (isa(s0, Const) || isType(s0)) && !has_free_typevars(s)
850+
exactft = exact || !has_free_typevars(ft)
809851
ft = rewrap_unionall(ft, s)
810-
if exact
811-
return Const(ft)
852+
if exactft
853+
if issingletontype(ft)
854+
return Const(ft) # ft unique via type cache
855+
end
856+
return Type{ft}
812857
end
813858
return Type{<:ft}
814859
end

test/compiler/compiler.jl

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

617638
# issue #11480
618639
@noinline f11480(x,y) = x

0 commit comments

Comments
 (0)