From 886b9226eacf9fff76cfc53ae4eedc59e2dc8536 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 8 Sep 2021 02:32:49 -0400 Subject: [PATCH] inference: bail from const-prop if const-prop fails (#42112) Otherwise we can end up in an infinite cycle of attempting const-prop, and that failing. Also handle `Varargs` in method-lookup matching, which was the cause for which we could not compute the const-prop signature. Fixes #42097 (cherry picked from commit 3a4198e91644a66b33d82921348ce4e050fae633) --- base/compiler/abstractinterpretation.jl | 4 +++ base/compiler/inferenceresult.jl | 34 +++++++++++++------------ test/compiler/inference.jl | 7 +++++ 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index aa83cc1a7aac27..afdd201a80c08e 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -510,6 +510,10 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, resul return Any, nothing end inf_result = InferenceResult(mi, argtypes, va_override) + if !any(inf_result.overridden_by_const) + add_remark!(interp, sv, "[constprop] Could not handle constant info in matching_cache_argtypes") + return nothing + end frame = InferenceState(inf_result, #=cache=#false, interp) frame === nothing && return Any, nothing # this is probably a bad generated function (unsound), but just ignore it frame.parent = sv diff --git a/base/compiler/inferenceresult.jl b/base/compiler/inferenceresult.jl index 327ab85d104f39..05c4c59111acb8 100644 --- a/base/compiler/inferenceresult.jl +++ b/base/compiler/inferenceresult.jl @@ -16,30 +16,32 @@ end function matching_cache_argtypes(linfo::MethodInstance, given_argtypes::Vector, va_override) @assert isa(linfo.def, Method) # ensure the next line works nargs::Int = linfo.def.nargs - @assert length(given_argtypes) >= (nargs - 1) given_argtypes = anymap(widenconditional, given_argtypes) - if va_override || linfo.def.isva + isva = va_override || linfo.def.isva + if isva || isvarargtype(given_argtypes[end]) isva_given_argtypes = Vector{Any}(undef, nargs) - for i = 1:(nargs - 1) + for i = 1:(nargs - isva) isva_given_argtypes[i] = argtype_by_index(given_argtypes, i) end - if length(given_argtypes) >= nargs || !isvarargtype(given_argtypes[end]) - isva_given_argtypes[nargs] = tuple_tfunc(given_argtypes[nargs:end]) - else - isva_given_argtypes[nargs] = tuple_tfunc(given_argtypes[end:end]) + if isva + if length(given_argtypes) < nargs && isvarargtype(given_argtypes[end]) + last = length(given_argtypes) + else + last = nargs + end + isva_given_argtypes[nargs] = tuple_tfunc(given_argtypes[last:end]) end given_argtypes = isva_given_argtypes end + @assert length(given_argtypes) == nargs cache_argtypes, overridden_by_const = matching_cache_argtypes(linfo, nothing, va_override) - if nargs === length(given_argtypes) - for i in 1:nargs - given_argtype = given_argtypes[i] - cache_argtype = cache_argtypes[i] - if !is_argtype_match(given_argtype, cache_argtype, overridden_by_const[i]) - # prefer the argtype we were given over the one computed from `linfo` - cache_argtypes[i] = given_argtype - overridden_by_const[i] = true - end + for i in 1:nargs + given_argtype = given_argtypes[i] + cache_argtype = cache_argtypes[i] + if !is_argtype_match(given_argtype, cache_argtype, overridden_by_const[i]) + # prefer the argtype we were given over the one computed from `linfo` + cache_argtypes[i] = given_argtype + overridden_by_const[i] = true end end return cache_argtypes, overridden_by_const diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index a2432169b09adc..007157e42f47d2 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -3499,3 +3499,10 @@ end end return x end) === Union{Int, Float64, Char} + +# issue #42097 +struct Foo42097{F} end +Foo42097(f::F, args) where {F} = Foo42097{F}() +Foo42097(A) = Foo42097(Base.inferencebarrier(+), Base.inferencebarrier(1)...) +foo42097() = Foo42097([1]...) +@test foo42097() isa Foo42097{typeof(+)}