Skip to content

Commit 9352745

Browse files
committed
Improve inference for ismutable with missing sparam
We could already infer `ismutable(RefValue{T})` if we knew what `T` was at inference time. However, the mutable does of course not change depending on what `T` is, so fix that up by adding an appropriate special case in `_getfield_tfunc`.
1 parent f1a0dd6 commit 9352745

File tree

3 files changed

+67
-33
lines changed

3 files changed

+67
-33
lines changed

base/compiler/tfuncs.jl

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ function find_tfunc(@nospecialize f)
2525
end
2626

2727
const DATATYPE_TYPES_FIELDINDEX = fieldindex(DataType, :types)
28+
const DATATYPE_NAME_FIELDINDEX = fieldindex(DataType, :name)
2829

2930
##########
3031
# tfuncs #
@@ -823,7 +824,11 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), boundscheck::
823824
if isa(s, Union)
824825
return getfield_nothrow(rewrap_unionall(s.a, s00), name, boundscheck) &&
825826
getfield_nothrow(rewrap_unionall(s.b, s00), name, boundscheck)
826-
elseif isa(s, DataType)
827+
elseif isType(s)
828+
sv = s.parameters[1]
829+
s = s0 = typeof(sv)
830+
end
831+
if isa(s, DataType)
827832
# Can't say anything about abstract types
828833
isabstracttype(s) && return false
829834
s.name.atomicfields == C_NULL || return false # TODO: currently we're only testing for ordering === :not_atomic
@@ -863,15 +868,40 @@ function getfield_tfunc(s00, name, order, boundscheck)
863868
return getfield_tfunc(s00, name)
864869
end
865870
getfield_tfunc(@nospecialize(s00), @nospecialize(name)) = _getfield_tfunc(s00, name, false)
871+
872+
function _getfield_fieldindex(@nospecialize(s), name::Const)
873+
nv = name.val
874+
if isa(nv, Symbol)
875+
nv = fieldindex(s, nv, false)
876+
end
877+
if isa(nv, Int)
878+
return nv
879+
end
880+
return nothing
881+
end
882+
883+
function _getfield_tfunc_const(@nospecialize(sv), name::Const, setfield::Bool)
884+
if isa(name, Const)
885+
nv = _getfield_fieldindex(typeof(sv), name)
886+
nv === nothing && return Bottom
887+
if isa(sv, DataType) && nv == DATATYPE_TYPES_FIELDINDEX && isdefined(sv, nv)
888+
return Const(getfield(sv, nv))
889+
end
890+
if isconst(typeof(sv), nv)
891+
if isdefined(sv, nv)
892+
return Const(getfield(sv, nv))
893+
end
894+
return Union{}
895+
end
896+
end
897+
return nothing
898+
end
899+
866900
function _getfield_tfunc(@nospecialize(s00), @nospecialize(name), setfield::Bool)
867901
if isa(s00, Conditional)
868902
return Bottom # Bool has no fields
869-
elseif isa(s00, Const) || isconstType(s00)
870-
if !isa(s00, Const)
871-
sv = s00.parameters[1]
872-
else
873-
sv = s00.val
874-
end
903+
elseif isa(s00, Const)
904+
sv = s00.val
875905
if isa(name, Const)
876906
nv = name.val
877907
if isa(sv, Module)
@@ -881,31 +911,15 @@ function _getfield_tfunc(@nospecialize(s00), @nospecialize(name), setfield::Bool
881911
end
882912
return Bottom
883913
end
884-
if isa(nv, Symbol)
885-
nv = fieldindex(typeof(sv), nv, false)
886-
end
887-
if !isa(nv, Int)
888-
return Bottom
889-
end
890-
if isa(sv, DataType) && nv == DATATYPE_TYPES_FIELDINDEX && isdefined(sv, nv)
891-
return Const(getfield(sv, nv))
892-
end
893-
if isconst(typeof(sv), nv)
894-
if isdefined(sv, nv)
895-
return Const(getfield(sv, nv))
896-
end
897-
return Union{}
898-
end
914+
r = _getfield_tfunc_const(sv, name, setfield)
915+
r !== nothing && return r
899916
end
900917
s = typeof(sv)
901918
elseif isa(s00, PartialStruct)
902919
s = widenconst(s00)
903920
sty = unwrap_unionall(s)::DataType
904921
if isa(name, Const)
905-
nv = name.val
906-
if isa(nv, Symbol)
907-
nv = fieldindex(sty, nv, false)
908-
end
922+
nv = _getfield_fieldindex(sty, name)
909923
if isa(nv, Int) && 1 <= nv <= length(s00.fields)
910924
return unwrapva(s00.fields[nv])
911925
end
@@ -917,6 +931,26 @@ function _getfield_tfunc(@nospecialize(s00), @nospecialize(name), setfield::Bool
917931
return tmerge(_getfield_tfunc(rewrap_unionall(s.a, s00), name, setfield),
918932
_getfield_tfunc(rewrap_unionall(s.b, s00), name, setfield))
919933
end
934+
if isType(s)
935+
if isconstType(s)
936+
sv = s00.parameters[1]
937+
if isa(name, Const)
938+
r = _getfield_tfunc_const(sv, name, setfield)
939+
r !== nothing && return r
940+
end
941+
s = typeof(sv)
942+
else
943+
sv = s.parameters[1]
944+
if isa(sv, DataType) && isa(name, Const) && (!isType(sv) && sv !== Core.TypeofBottom)
945+
nv = _getfield_fieldindex(DataType, name)
946+
if nv == DATATYPE_NAME_FIELDINDEX
947+
# N.B. This doesn't work in general, because
948+
return Const(sv.name)
949+
end
950+
s = DataType
951+
end
952+
end
953+
end
920954
isa(s, DataType) || return Any
921955
isabstracttype(s) && return Any
922956
if s <: Tuple && !hasintersect(widenconst(name), Int)
@@ -972,13 +1006,8 @@ function _getfield_tfunc(@nospecialize(s00), @nospecialize(name), setfield::Bool
9721006
end
9731007
return t
9741008
end
975-
fld = name.val
976-
if isa(fld, Symbol)
977-
fld = fieldindex(s, fld, false)
978-
end
979-
if !isa(fld, Int)
980-
return Bottom
981-
end
1009+
fld = _getfield_fieldindex(s, name)
1010+
fld === nothing && return Bottom
9821011
if s <: Tuple && fld >= nf && isvarargtype(ftypes[nf])
9831012
return rewrap_unionall(unwrapva(ftypes[nf]), s00)
9841013
end

test/compiler/inference.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,7 @@ g23024(TT::Tuple{DataType}) = f23024(TT[1], v23024)
15881588
@test g23024((UInt8,)) === 2
15891589

15901590
@test !Core.Compiler.isconstType(Type{typeof(Union{})}) # could be Core.TypeofBottom or Type{Union{}} at runtime
1591+
@test !isa(Core.Compiler.getfield_tfunc(Type{Core.TypeofBottom}, Core.Compiler.Const(:name)), Core.Compiler.Const)
15911592
@test Base.return_types(supertype, (Type{typeof(Union{})},)) == Any[Any]
15921593

15931594
# issue #23685

test/compiler/inline.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,3 +1496,7 @@ call_twice_sitofp(x::Int) = twice_sitofp(x, 2)
14961496
let src = code_typed1(call_twice_sitofp, (Int,))
14971497
@test count(iscall((src, Base.sitofp)), src.code) == 1
14981498
end
1499+
1500+
# Test getfield modeling of Type{Ref{_A}} where _A
1501+
@test Core.Compiler.getfield_tfunc(Type, Core.Compiler.Const(:parameters)) !== Union{}
1502+
@test fully_eliminated(Base.ismutable, Tuple{Base.RefValue})

0 commit comments

Comments
 (0)