64
64
# The type of a value might be constant
65
65
struct Const
66
66
val
67
- Const (v:: ANY ) = new (v)
67
+ actual:: Bool # if true, we obtained `val` by actually calling a @pure function
68
+ Const (v:: ANY ) = new (v, false )
69
+ Const (v:: ANY , a:: Bool ) = new (v, a)
68
70
end
69
71
70
72
# The type of a value might be Bool,
@@ -191,7 +193,7 @@ mutable struct InferenceState
191
193
vararg_type = rewrap (vararg_type, linfo. specTypes)
192
194
end
193
195
s_types[1 ][la] = VarState (vararg_type, false )
194
- src. slottypes[la] = widenconst ( vararg_type)
196
+ src. slottypes[la] = vararg_type
195
197
la -= 1
196
198
end
197
199
end
@@ -220,11 +222,11 @@ mutable struct InferenceState
220
222
end
221
223
i == laty && (lastatype = atyp)
222
224
s_types[1 ][i] = VarState (atyp, false )
223
- src. slottypes[i] = widenconst ( atyp)
225
+ src. slottypes[i] = atyp
224
226
end
225
227
for i = (atail + 1 ): la
226
228
s_types[1 ][i] = VarState (lastatype, false )
227
- src. slottypes[i] = widenconst ( lastatype)
229
+ src. slottypes[i] = lastatype
228
230
end
229
231
else
230
232
@assert la == 0 # wrong number of arguments
@@ -1544,7 +1546,7 @@ function return_type_tfunc(argtypes::ANY, vtypes::VarTable, sv::InferenceState)
1544
1546
return NF
1545
1547
end
1546
1548
1547
- function pure_eval_call (f:: ANY , argtypes:: ANY , atype:: ANY , vtypes :: VarTable , sv:: InferenceState )
1549
+ function pure_eval_call (f:: ANY , argtypes:: ANY , atype:: ANY , sv:: InferenceState )
1548
1550
for i = 2 : length (argtypes)
1549
1551
a = argtypes[i]
1550
1552
if ! (isa (a,Const) || isconstType (a))
@@ -1569,7 +1571,7 @@ function pure_eval_call(f::ANY, argtypes::ANY, atype::ANY, vtypes::VarTable, sv:
1569
1571
try
1570
1572
value = Core. _apply_pure (f, args)
1571
1573
# TODO : add some sort of edge(s)
1572
- return abstract_eval_constant (value)
1574
+ return Const (value, true )
1573
1575
catch
1574
1576
return false
1575
1577
end
@@ -1804,7 +1806,7 @@ function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vect
1804
1806
end
1805
1807
1806
1808
atype = argtypes_to_type (argtypes)
1807
- t = pure_eval_call (f, argtypes, atype, vtypes, sv)
1809
+ t = pure_eval_call (f, argtypes, atype, sv)
1808
1810
t != = false && return t
1809
1811
1810
1812
if istopfunction (tm, f, :promote_type ) || istopfunction (tm, f, :typejoin )
@@ -1976,14 +1978,7 @@ function abstract_eval(e::ANY, vtypes::VarTable, sv::InferenceState)
1976
1978
return t
1977
1979
end
1978
1980
1979
- const Type_Array = Const (Array)
1980
-
1981
- function abstract_eval_constant (x:: ANY )
1982
- if x === Array
1983
- return Type_Array
1984
- end
1985
- return Const (x)
1986
- end
1981
+ const abstract_eval_constant = Const
1987
1982
1988
1983
function abstract_eval_global (M:: Module , s:: Symbol )
1989
1984
if isdefined (M,s) && isconst (M,s)
@@ -2927,28 +2922,33 @@ function optimize(me::InferenceState)
2927
2922
2928
2923
if isa (me. bestguess, Const) || isconstType (me. bestguess)
2929
2924
me. const_ret = true
2930
- ispure = me. src. pure
2931
- if ! ispure && length (me. src. code) < 10
2932
- ispure = true
2925
+ proven_pure = false
2926
+ # must be proven pure to use const_api; otherwise we might skip throwing errors
2927
+ # (issue #20704)
2928
+ # TODO : Improve this analysis; if a function is marked @pure we should really
2929
+ # only care about certain errors (e.g. method errors and type errors).
2930
+ if length (me. src. code) < 10
2931
+ proven_pure = true
2933
2932
for stmt in me. src. code
2934
2933
if ! statement_effect_free (stmt, me. src, me. mod)
2935
- ispure = false
2934
+ proven_pure = false
2936
2935
break
2937
2936
end
2938
2937
end
2939
- if ispure
2938
+ if proven_pure
2940
2939
for fl in me. src. slotflags
2941
2940
if (fl & Slot_UsedUndef) != 0
2942
- ispure = false
2941
+ proven_pure = false
2943
2942
break
2944
2943
end
2945
2944
end
2946
2945
end
2947
2946
end
2948
- me. src. pure = ispure
2947
+ if proven_pure
2948
+ me. src. pure = true
2949
+ end
2949
2950
2950
- do_coverage = coverage_enabled ()
2951
- if ispure && ! do_coverage
2951
+ if proven_pure && ! coverage_enabled ()
2952
2952
# use constant calling convention
2953
2953
# Do not emit `jlcall_api == 2` if coverage is enabled
2954
2954
# so that we don't need to add coverage support
@@ -3079,7 +3079,7 @@ function annotate_slot_load!(e::Expr, vtypes::VarTable, sv::InferenceState, unde
3079
3079
undefs[id] = true
3080
3080
end
3081
3081
# add type annotations where needed
3082
- if ! (sv. src. slottypes[id] <: vt )
3082
+ if ! (sv. src. slottypes[id] ⊑ vt)
3083
3083
e. args[i] = TypedSlot (id, vt)
3084
3084
end
3085
3085
end
@@ -3222,6 +3222,7 @@ end
3222
3222
# we also need to preserve the type for any untyped load of a DataType
3223
3223
# since codegen optimizations of functions like `is` will depend on knowing it
3224
3224
function widen_slot_type (ty:: ANY , untypedload:: Bool )
3225
+ ty = widenconst (ty)
3225
3226
if isa (ty, DataType)
3226
3227
if untypedload || isbits (ty) || isdefined (ty, :instance )
3227
3228
return ty
@@ -3767,23 +3768,26 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
3767
3768
atype_unlimited, method. sig)
3768
3769
methsp = methsp:: SimpleVector
3769
3770
end
3770
- # check whether call can be inlined to just a quoted constant value
3771
- if isa (f, widenconst (ft)) && ! method. isstaged && (method. source. pure || f === return_type)
3772
- if isconstType (e. typ)
3773
- return inline_as_constant (e. typ. parameters[1 ], argexprs, sv,
3774
- invoke_data)
3775
- elseif isa (e. typ,Const)
3776
- return inline_as_constant (e. typ. val, argexprs, sv,
3777
- invoke_data)
3778
- end
3779
- end
3780
3771
3781
3772
methsig = method. sig
3782
3773
if ! (atype <: metharg )
3783
3774
return invoke_NF (argexprs, e. typ, atypes, sv, atype_unlimited,
3784
3775
invoke_data)
3785
3776
end
3786
3777
3778
+ # check whether call can be inlined to just a quoted constant value
3779
+ if isa (f, widenconst (ft)) && ! method. isstaged
3780
+ if f === return_type
3781
+ if isconstType (e. typ)
3782
+ return inline_as_constant (e. typ. parameters[1 ], argexprs, sv, invoke_data)
3783
+ elseif isa (e. typ,Const)
3784
+ return inline_as_constant (e. typ. val, argexprs, sv, invoke_data)
3785
+ end
3786
+ elseif method. source. pure && isa (e. typ,Const) && e. typ. actual
3787
+ return inline_as_constant (e. typ. val, argexprs, sv, invoke_data)
3788
+ end
3789
+ end
3790
+
3787
3791
argexprs0 = argexprs
3788
3792
na = Int (method. nargs)
3789
3793
# check for vararg function
0 commit comments