@@ -1010,9 +1010,12 @@ function maybe_get_const_prop_profitable(interp::AbstractInterpreter,
1010
1010
# N.B. remarks are emitted within `const_prop_rettype_heuristic`
1011
1011
return nothing
1012
1012
end
1013
- if ! const_prop_argument_heuristic (interp, arginfo, sv)
1013
+ arg_result = const_prop_argument_heuristic (interp, arginfo, sv)
1014
+ if arg_result === nothing
1014
1015
add_remark! (interp, sv, " [constprop] Disabled by argument heuristics" )
1015
1016
return nothing
1017
+ else
1018
+ force |= arg_result
1016
1019
end
1017
1020
all_overridden = is_all_overridden (interp, arginfo, sv)
1018
1021
if ! force && ! const_prop_function_heuristic (interp, f, arginfo, all_overridden, sv)
@@ -1079,16 +1082,19 @@ end
1079
1082
function const_prop_argument_heuristic (interp:: AbstractInterpreter , arginfo:: ArgInfo , sv:: AbsIntState )
1080
1083
𝕃ᵢ = typeinf_lattice (interp)
1081
1084
argtypes = arginfo. argtypes
1082
- for i in 1 : length (argtypes)
1085
+ for i = 1 : length (argtypes)
1083
1086
a = argtypes[i]
1084
1087
if has_conditional (𝕃ᵢ, sv) && isa (a, Conditional) && arginfo. fargs != = nothing
1085
- is_const_prop_profitable_conditional (a, arginfo. fargs, sv) && return true
1088
+ is_const_prop_profitable_conditional (a, arginfo. fargs, sv) && return false
1086
1089
else
1087
1090
a = widenslotwrapper (a)
1088
- has_nontrivial_extended_info (𝕃ᵢ, a) && is_const_prop_profitable_arg (𝕃ᵢ, a) && return true
1091
+ if has_nontrivial_extended_info (𝕃ᵢ, a) && is_const_prop_profitable_arg (𝕃ᵢ, a)
1092
+ # force const-prop' if the function object itself has some profitable information
1093
+ return i == 1 || widenconst (a) <: Function
1094
+ end
1089
1095
end
1090
1096
end
1091
- return false
1097
+ return nothing
1092
1098
end
1093
1099
1094
1100
function is_const_prop_profitable_conditional (cnd:: Conditional , fargs:: Vector{Any} , sv:: InferenceState )
@@ -2899,16 +2905,16 @@ end
2899
2905
2900
2906
function abstract_eval_new (interp:: AbstractInterpreter , e:: Expr , vtypes:: Union{VarTable,Nothing} ,
2901
2907
sv:: AbsIntState )
2902
- 𝕃ᵢ = typeinf_lattice (interp)
2908
+ lat = typeinf_lattice (interp)
2903
2909
rt, isexact = instanceof_tfunc (abstract_eval_value (interp, e. args[1 ], vtypes, sv), true )
2904
2910
ut = unwrap_unionall (rt)
2905
2911
exct = Union{ErrorException,TypeError}
2906
2912
if isa (ut, DataType) && ! isabstracttype (ut)
2907
2913
ismutable = ismutabletype (ut)
2908
2914
fcount = datatype_fieldcount (ut)
2909
2915
nargs = length (e. args) - 1
2910
- has_any_uninitialized = (fcount === nothing || (fcount > nargs && (let t = rt
2911
- any (i:: Int -> ! is_undefref_fieldtype (fieldtype (t , i)), (nargs+ 1 ): fcount)
2916
+ has_any_uninitialized = (fcount === nothing || (fcount > nargs && (let boxed = Core . Box (rt)
2917
+ any (i:: Int -> ! is_undefref_fieldtype (fieldtype (boxed . contents , i)), (nargs+ 1 ): fcount)
2912
2918
end )))
2913
2919
if has_any_uninitialized
2914
2920
# allocation with undefined field is inconsistent always
@@ -2920,43 +2926,69 @@ function abstract_eval_new(interp::AbstractInterpreter, e::Expr, vtypes::Union{V
2920
2926
else
2921
2927
consistent = ALWAYS_TRUE # immutable allocation is consistent
2922
2928
end
2923
- if isconcretedispatch (rt)
2924
- nothrow = true
2925
- @assert fcount != = nothing && fcount ≥ nargs " malformed :new expression" # syntactically enforced by the front-end
2926
- ats = Vector {Any} (undef, nargs)
2927
- local anyrefine = false
2928
- local allconst = true
2929
+ @inline function compute_fields_info (@nospecialize (rt))
2930
+ local anyrefine, allconst, nothrow = false , true , true
2931
+ ⊑ , ⋤ , ⊓ = partialorder (lat), strictneqpartialorder (lat), meet (lat)
2929
2932
for i = 1 : nargs
2930
2933
at = widenslotwrapper (abstract_eval_value (interp, e. args[i+ 1 ], vtypes, sv))
2931
2934
ft = fieldtype (rt, i)
2932
- nothrow && (nothrow = ⊑ (𝕃ᵢ, at, ft) )
2933
- at = tmeet (𝕃ᵢ, at, ft)
2934
- at === Bottom && return RTEffects (Bottom, TypeError, EFFECTS_THROWS)
2935
+ nothrow && (nothrow = at ⊑ ft )
2936
+ at = at ⊓ ft
2937
+ at === Bottom && return nothing
2935
2938
if ismutable && ! isconst (rt, i)
2936
- ats[i] = ft # can't constrain this field (as it may be modified later)
2939
+ # can't constrain this field (as it may be modified later)
2940
+ allconst = false
2937
2941
continue
2938
2942
end
2939
2943
allconst &= isa (at, Const)
2940
- if ! anyrefine
2941
- anyrefine = has_nontrivial_extended_info (𝕃ᵢ, at) || # extended lattice information
2942
- ⋤ (𝕃ᵢ, at, ft) # just a type-level information, but more precise than the declared type
2944
+ anyrefine || (anyrefine =
2945
+ has_nontrivial_extended_info (lat, at) || # extended lattice information
2946
+ at ⋤ ft) # just a type-level information, but more precise than the declared type
2947
+ end
2948
+ return anyrefine, allconst, nothrow
2949
+ end
2950
+ @noinline function compute_fields (@nospecialize (rt), unwrap_const:: Bool = false )
2951
+ local fields = Vector {Any} (undef, nargs)
2952
+ ⊓ = meet (lat)
2953
+ for i = 1 : nargs
2954
+ at = widenslotwrapper (abstract_eval_value (interp, e. args[i+ 1 ], vtypes, sv))
2955
+ ft = fieldtype (rt, i)
2956
+ if ismutable && ! isconst (rt, i)
2957
+ @assert ! unwrap_const
2958
+ fields[i] = ft # can't constrain this field (as it may be modified later)
2959
+ else
2960
+ at = at ⊓ ft
2961
+ if unwrap_const
2962
+ fields[i] = (at:: Const ). val
2963
+ else
2964
+ fields[i] = at
2965
+ end
2943
2966
end
2944
- ats[i] = at
2945
2967
end
2968
+ return fields
2969
+ end
2970
+ if isconcretedispatch (rt)
2971
+ @assert fcount != = nothing && fcount ≥ nargs " malformed :new expression" # syntactically enforced by the front-end
2972
+ ret = compute_fields_info (rt)
2973
+ ret === nothing && return RTEffects (Bottom, TypeError, EFFECTS_THROWS)
2974
+ anyrefine, allconst, nothrow = ret
2946
2975
if fcount == nargs && consistent === ALWAYS_TRUE && allconst
2947
- argvals = Vector {Any} (undef, nargs)
2948
- for j in 1 : nargs
2949
- argvals[j] = (ats[j]:: Const ). val
2950
- end
2976
+ argvals = compute_fields (rt, #= unwrap_const=# true )
2951
2977
rt = Const (ccall (:jl_new_structv , Any, (Any, Ptr{Cvoid}, UInt32), rt, argvals, nargs))
2952
2978
elseif anyrefine || nargs > datatype_min_ninitialized (rt)
2953
2979
# propagate partially initialized struct as `PartialStruct` when:
2954
2980
# - any refinement information is available (`anyrefine`), or when
2955
2981
# - `nargs` is greater than `n_initialized` derived from the struct type
2956
2982
# information alone
2957
- rt = PartialStruct (𝕃ᵢ , rt, ats )
2983
+ rt = PartialStruct (lat , rt, compute_fields (rt) )
2958
2984
end
2959
2985
else
2986
+ ret = compute_fields_info (rt)
2987
+ ret === nothing && return RTEffects (Bottom, TypeError, EFFECTS_THROWS)
2988
+ anyrefine = ret[1 ]
2989
+ if anyrefine || nargs > datatype_min_ninitialized (ut)
2990
+ rt = PartialStruct (lat, rt, compute_fields (rt))
2991
+ end
2960
2992
rt = refine_partial_type (rt)
2961
2993
nothrow = false
2962
2994
end
@@ -2978,18 +3010,18 @@ function abstract_eval_splatnew(interp::AbstractInterpreter, e::Expr, vtypes::Un
2978
3010
at = abstract_eval_value (interp, e. args[2 ], vtypes, sv)
2979
3011
n = fieldcount (rt)
2980
3012
if (isa (at, Const) && isa (at. val, Tuple) && n == length (at. val:: Tuple ) &&
2981
- (let t = rt, at = at
2982
- all (i:: Int -> getfield (at. val:: Tuple , i) isa fieldtype (t , i), 1 : n)
3013
+ (let boxed = Core . Box (rt)
3014
+ all (i:: Int -> getfield (at. val:: Tuple , i) isa fieldtype (boxed . contents , i), 1 : n)
2983
3015
end ))
2984
3016
nothrow = isexact
2985
3017
rt = Const (ccall (:jl_new_structt , Any, (Any, Any), rt, at. val))
2986
3018
elseif (isa (at, PartialStruct) && ⊑ (𝕃ᵢ, at, Tuple) && n > 0 &&
2987
- n == length (at. fields:: Vector{Any} ) && ! isvarargtype (at. fields[end ]) &&
2988
- (let t = rt, at = at
2989
- all (i:: Int -> ⊑ (𝕃ᵢ, (at. fields:: Vector{Any} )[i], fieldtype (t , i)), 1 : n)
3019
+ n == length (at. fields) && ! isvarargtype (at. fields[end ]) &&
3020
+ (let boxed = Core . Box (rt)
3021
+ all (i:: Int -> ⊑ (𝕃ᵢ, (at. fields)[i], fieldtype (boxed . contents , i)), 1 : n)
2990
3022
end ))
2991
3023
nothrow = isexact
2992
- rt = PartialStruct (𝕃ᵢ, rt, at. fields:: Vector{Any} )
3024
+ rt = PartialStruct (𝕃ᵢ, rt, at. fields)
2993
3025
end
2994
3026
else
2995
3027
rt = refine_partial_type (rt)
0 commit comments