diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 329988744fe23..a5d3395bca486 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -715,7 +715,7 @@ function concrete_eval_eligible(interp::AbstractInterpreter, isoverlayed(method_table(interp)) && result.edge_effects.overlayed && return false return f !== nothing && result.edge !== nothing && - is_total_or_error(result.edge_effects) && + is_concrete_eval_eligible(result.edge_effects) && is_all_const_arg(arginfo) end diff --git a/base/compiler/types.jl b/base/compiler/types.jl index 0d8275ac0e7a0..b66c6213a0221 100644 --- a/base/compiler/types.jl +++ b/base/compiler/types.jl @@ -78,13 +78,13 @@ function Effects(e::Effects = EFFECTS_UNKNOWN; inbounds_taints_consistency) end -is_total_or_error(effects::Effects) = +is_concrete_eval_eligible(effects::Effects) = effects.consistent === ALWAYS_TRUE && effects.effect_free === ALWAYS_TRUE && effects.terminates === ALWAYS_TRUE is_total(effects::Effects) = - is_total_or_error(effects) && + is_concrete_eval_eligible(effects) && effects.nothrow === ALWAYS_TRUE is_removable_if_unused(effects::Effects) = diff --git a/base/expr.jl b/base/expr.jl index de1045d6addfe..de8264a14e1b6 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -512,11 +512,24 @@ This `setting` combines the following other assertions: - `:terminates_globally` and is a convenient shortcut. +--- +# `:total_but_may_throw` + +This `setting` combines the following other assertions: +- `:consistent` +- `:effect_free` +- `:terminates_globally` +and is a convenient shortcut. + !!! note - `@assume_effects :total` is similar to `@Base.pure` with the primary + This setting is particularly useful since it allows the compiler to evaluate a call of + the applied method when all the call arguments are fully known, no matter if the call + results in an error or not. + + `@assume_effects :total_but_may_throw` is similar to `Base.@pure` with the primary distinction that the `:consistent`-cy requirement applies world-age wise rather than globally as described above. However, in particular, a method annotated - `@Base.pure` is always `:total`. + `Base.@pure` should always be `:total` or `:total_but_may_throw`. """ macro assume_effects(args...) (consistent, effect_free, nothrow, terminates_globally, terminates_locally) = @@ -537,12 +550,14 @@ macro assume_effects(args...) terminates_locally = true elseif setting === :total consistent = effect_free = nothrow = terminates_globally = true + elseif setting === :total_but_may_throw + consistent = effect_free = terminates_globally = true else throw(ArgumentError("@assume_effects $setting not supported")) end end ex = args[end] - isa(ex, Expr) || throw(ArgumentError("Bad expression `$ex` in @constprop [settings] ex")) + isa(ex, Expr) || throw(ArgumentError("Bad expression `$ex` in `@assume_effects [settings] ex`")) if ex.head === :macrocall && ex.args[1] == Symbol("@ccall") ex.args[1] = GlobalRef(Base, Symbol("@ccall_effects")) insert!(ex.args, 3, Core.Compiler.encode_effects_override(Core.Compiler.EffectsOverride( diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index cc94ace0026df..4743e036faf0a 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -1088,11 +1088,11 @@ recur_termination22(x) = x * recur_termination21(x-1) recur_termination21(12) + recur_termination22(12) end -const ___CONST_DICT___ = Dict{Any,Any}(:a => 1, :b => 2) -Base.@assume_effects :consistent :effect_free :terminates_globally consteval( +const ___CONST_DICT___ = Dict{Any,Any}(Symbol(c) => i for (i, c) in enumerate('a':'z')) +Base.@assume_effects :total_but_may_throw concrete_eval( f, args...; kwargs...) = f(args...; kwargs...) @test fully_eliminated() do - consteval(getindex, ___CONST_DICT___, :a) + concrete_eval(getindex, ___CONST_DICT___, :a) end # https://github.com/JuliaLang/julia/issues/44732