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
@@ -1546,7 +1548,7 @@ function return_type_tfunc(argtypes::ANY, vtypes::VarTable, sv::InferenceState)
1546
1548
return NF
1547
1549
end
1548
1550
1549
- function pure_eval_call (f:: ANY , argtypes:: ANY , atype:: ANY , vtypes :: VarTable , sv:: InferenceState )
1551
+ function pure_eval_call (f:: ANY , argtypes:: ANY , atype:: ANY , sv:: InferenceState )
1550
1552
for i = 2 : length (argtypes)
1551
1553
a = argtypes[i]
1552
1554
if ! (isa (a,Const) || isconstType (a))
@@ -1571,7 +1573,7 @@ function pure_eval_call(f::ANY, argtypes::ANY, atype::ANY, vtypes::VarTable, sv:
1571
1573
try
1572
1574
value = Core. _apply_pure (f, args)
1573
1575
# TODO : add some sort of edge(s)
1574
- return abstract_eval_constant (value)
1576
+ return Const (value, true )
1575
1577
catch
1576
1578
return false
1577
1579
end
@@ -1807,7 +1809,7 @@ function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vect
1807
1809
end
1808
1810
1809
1811
atype = argtypes_to_type (argtypes)
1810
- t = pure_eval_call (f, argtypes, atype, vtypes, sv)
1812
+ t = pure_eval_call (f, argtypes, atype, sv)
1811
1813
t != = false && return t
1812
1814
1813
1815
if istopfunction (tm, f, :promote_type ) || istopfunction (tm, f, :typejoin )
@@ -1979,14 +1981,7 @@ function abstract_eval(e::ANY, vtypes::VarTable, sv::InferenceState)
1979
1981
return t
1980
1982
end
1981
1983
1982
- const Type_Array = Const (Array)
1983
-
1984
- function abstract_eval_constant (x:: ANY )
1985
- if x === Array
1986
- return Type_Array
1987
- end
1988
- return Const (x)
1989
- end
1984
+ const abstract_eval_constant = Const
1990
1985
1991
1986
function abstract_eval_global (M:: Module , s:: Symbol )
1992
1987
if isdefined (M,s) && isconst (M,s)
@@ -2930,28 +2925,33 @@ function optimize(me::InferenceState)
2930
2925
2931
2926
if isa (me. bestguess, Const) || isconstType (me. bestguess)
2932
2927
me. const_ret = true
2933
- ispure = me. src. pure
2934
- if ! ispure && length (me. src. code) < 10
2935
- ispure = true
2928
+ proven_pure = false
2929
+ # must be proven pure to use const_api; otherwise we might skip throwing errors
2930
+ # (issue #20704)
2931
+ # TODO : Improve this analysis; if a function is marked @pure we should really
2932
+ # only care about certain errors (e.g. method errors and type errors).
2933
+ if length (me. src. code) < 10
2934
+ proven_pure = true
2936
2935
for stmt in me. src. code
2937
2936
if ! statement_effect_free (stmt, me. src, me. mod)
2938
- ispure = false
2937
+ proven_pure = false
2939
2938
break
2940
2939
end
2941
2940
end
2942
- if ispure
2941
+ if proven_pure
2943
2942
for fl in me. src. slotflags
2944
2943
if (fl & Slot_UsedUndef) != 0
2945
- ispure = false
2944
+ proven_pure = false
2946
2945
break
2947
2946
end
2948
2947
end
2949
2948
end
2950
2949
end
2951
- me. src. pure = ispure
2950
+ if proven_pure
2951
+ me. src. pure = true
2952
+ end
2952
2953
2953
- do_coverage = coverage_enabled ()
2954
- if ispure && ! do_coverage
2954
+ if proven_pure && ! coverage_enabled ()
2955
2955
# use constant calling convention
2956
2956
# Do not emit `jlcall_api == 2` if coverage is enabled
2957
2957
# so that we don't need to add coverage support
@@ -3082,7 +3082,7 @@ function annotate_slot_load!(e::Expr, vtypes::VarTable, sv::InferenceState, unde
3082
3082
undefs[id] = true
3083
3083
end
3084
3084
# add type annotations where needed
3085
- if ! (sv. src. slottypes[id] <: vt )
3085
+ if ! (sv. src. slottypes[id] ⊑ vt)
3086
3086
e. args[i] = TypedSlot (id, vt)
3087
3087
end
3088
3088
end
@@ -3225,6 +3225,7 @@ end
3225
3225
# we also need to preserve the type for any untyped load of a DataType
3226
3226
# since codegen optimizations of functions like `is` will depend on knowing it
3227
3227
function widen_slot_type (ty:: ANY , untypedload:: Bool )
3228
+ ty = widenconst (ty)
3228
3229
if isa (ty, DataType)
3229
3230
if untypedload || isbits (ty) || isdefined (ty, :instance )
3230
3231
return ty
@@ -3770,23 +3771,26 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
3770
3771
atype_unlimited, method. sig)
3771
3772
methsp = methsp:: SimpleVector
3772
3773
end
3773
- # check whether call can be inlined to just a quoted constant value
3774
- if isa (f, widenconst (ft)) && ! method. isstaged && (method. source. pure || f === return_type)
3775
- if isconstType (e. typ)
3776
- return inline_as_constant (e. typ. parameters[1 ], argexprs, sv,
3777
- invoke_data)
3778
- elseif isa (e. typ,Const)
3779
- return inline_as_constant (e. typ. val, argexprs, sv,
3780
- invoke_data)
3781
- end
3782
- end
3783
3774
3784
3775
methsig = method. sig
3785
3776
if ! (atype <: metharg )
3786
3777
return invoke_NF (argexprs, e. typ, atypes, sv, atype_unlimited,
3787
3778
invoke_data)
3788
3779
end
3789
3780
3781
+ # check whether call can be inlined to just a quoted constant value
3782
+ if isa (f, widenconst (ft)) && ! method. isstaged
3783
+ if f === return_type
3784
+ if isconstType (e. typ)
3785
+ return inline_as_constant (e. typ. parameters[1 ], argexprs, sv, invoke_data)
3786
+ elseif isa (e. typ,Const)
3787
+ return inline_as_constant (e. typ. val, argexprs, sv, invoke_data)
3788
+ end
3789
+ elseif method. source. pure && isa (e. typ,Const) && e. typ. actual
3790
+ return inline_as_constant (e. typ. val, argexprs, sv, invoke_data)
3791
+ end
3792
+ end
3793
+
3790
3794
argexprs0 = argexprs
3791
3795
na = Int (method. nargs)
3792
3796
# check for vararg function
0 commit comments