Skip to content

Commit

Permalink
JETAnalyzer: report undefined static parameters (#588)
Browse files Browse the repository at this point in the history
  • Loading branch information
aviatesk authored Jan 4, 2024
1 parent 0443cb6 commit 24b96dc
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ InteractiveUtils = "1.10"
JuliaInterpreter = "0.9"
Libdl = "1.10"
Logging = "1.10"
LoweredCodeUtils = "2.2"
LoweredCodeUtils = "< 2.4" # TODO
MacroTools = "0.5.6"
Pkg = "1.10"
PrecompileTools = "1"
Expand Down
2 changes: 1 addition & 1 deletion src/abstractinterpret/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ end
# cache
# =====

cache_report!(cache, @nospecialize(report::InferenceErrorReport)) =
cache_report!(cache::Vector{InferenceErrorReport}, @nospecialize(report::InferenceErrorReport)) =
push!(cache, copy_report′(report)::InferenceErrorReport)

struct AbstractAnalyzerView{Analyzer<:AbstractAnalyzer}
Expand Down
55 changes: 34 additions & 21 deletions src/analyzers/jetanalyzer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -335,15 +335,25 @@ function CC.abstract_invoke(analyzer::JETAnalyzer, arginfo::ArgInfo, si::StmtInf
return ret
end

# TODO enable this with https://github.com/JuliaLang/julia/pull/46791 to close https://github.com/aviatesk/JET.jl/issues/285
# function CC.abstract_eval_value_expr(analyzer::JETAnalyzer, e::Expr, sv::InferenceState)
# ret = @invoke CC.abstract_eval_value_expr(analyzer::AbstractInterpreter, e::Expr, sv::InferenceState)
# if e.head === :static_parameter
# # report pass for undefined static parameter
# ReportPass(analyzer)(UndefVarErrorReport, analyzer, sv, e.args[1]::Int)
# end
# return ret
# end
@static if VERSION v"1.11.0-DEV.888"
function CC.abstract_eval_statement_expr(analyzer::JETAnalyzer, e::Expr, vtypes::VarTable, sv::InferenceState)
ret = @invoke CC.abstract_eval_statement_expr(analyzer::AbstractInterpreter, e::Expr, vtypes::VarTable, sv::InferenceState)
if e.head === :static_parameter
# report pass for undefined static parameter
ReportPass(analyzer)(UndefVarErrorReport, analyzer, sv, e.args[1]::Int)
end
return ret
end
else
function CC.abstract_eval_value_expr(analyzer::JETAnalyzer, e::Expr, vtypes::VarTable, sv::InferenceState)
ret = @invoke CC.abstract_eval_value_expr(analyzer::AbstractInterpreter, e::Expr, vtypes::VarTable, sv::InferenceState)
if e.head === :static_parameter
# report pass for undefined static parameter
ReportPass(analyzer)(UndefVarErrorReport, analyzer, sv, e.args[1]::Int)
end
return ret
end
end

function CC.abstract_eval_special_value(analyzer::JETAnalyzer,
@nospecialize(e), vtypes::VarTable, sv::InferenceState)
Expand Down Expand Up @@ -815,14 +825,16 @@ end
end
function print_report_message(io::IO, r::UndefVarErrorReport)
var = r.var
if isa(var, GlobalRef)
print(io, "`", var.mod, '.', var.name, "`")
elseif isa(var, TypeVar)
print(io, "static parameter `", var.name, "`")
if isa(var, TypeVar)
print(io, "`", var.name, "` not defined in static parameter matching")
else
print(io, "local variable `", var, "`")
if isa(var, GlobalRef)
print(io, "`", var.mod, '.', var.name, "`")
else
print(io, "local variable `", var, "`")
end
print(io, " is not defined")
end
print(io, " is not defined")
end

# undefined global variable report passes
Expand Down Expand Up @@ -860,15 +872,16 @@ end
# undefined static parameter report passes

(::SoundPass)(::Type{UndefVarErrorReport}, analyzer::JETAnalyzer, sv::InferenceState, n::Int) =
report_undef_static_parameter!(analyzer, sv, n)
report_undef_static_parameter!(analyzer, sv, n, true)
(::BasicPass)(::Type{UndefVarErrorReport}, analyzer::JETAnalyzer, sv::InferenceState, n::Int) =
report_undef_static_parameter!(analyzer, sv, n)
report_undef_static_parameter!(analyzer, sv, n, false)
(::TypoPass)(::Type{UndefVarErrorReport}, analyzer::JETAnalyzer, sv::InferenceState, n::Int) =
report_undef_static_parameter!(analyzer, sv, n)
function report_undef_static_parameter!(analyzer::JETAnalyzer, sv::InferenceState, n::Int)
report_undef_static_parameter!(analyzer, sv, n, false)
function report_undef_static_parameter!(analyzer::JETAnalyzer, sv::InferenceState, n::Int, sound::Bool)
if 1 n length(sv.sptypes)
if sv.sptypes[n].typ === Any
tv = sv.linfo.sparam_vals[n]
mi = sv.linfo
if sv.sptypes[n].undef && (sound || is_compileable_mi(mi))
tv = mi.sparam_vals[n]::TypeVar
add_new_report!(analyzer, sv.result, UndefVarErrorReport(sv, tv))
return true
end
Expand Down
36 changes: 36 additions & 0 deletions test/analyzers/test_jetanalyzer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@ end
end
end

issue285(x, y::Vararg{T}) where {T} = T
issue586(t::Vararg{Type{<:T}}) where {T} = T

@testset "UndefVarErrorReport" begin
@testset "global" begin
let result = report_call(()->foo)
Expand Down Expand Up @@ -348,6 +351,39 @@ end
end
end
end

@testset "static parameter" begin
@test_call issue285(1, 2)
let result = @report_call issue285(1)
r = only(get_reports_with_test(result))
@test r isa UndefVarErrorReport && r.var isa TypeVar && r.var.name == :T
end
test_call((Vector{Any},)) do xs
issue285(xs...)
end
let result = report_call((Vector{Any},); mode=:sound) do xs
issue285(xs...)
end
@test any(get_reports_with_test(result)) do r
r isa UndefVarErrorReport && r.var isa TypeVar && r.var.name == :T
end
end
@test_call issue586(Int, Int)
let result = @report_call issue586(Int, String)
r = only(get_reports_with_test(result))
@test r isa UndefVarErrorReport && r.var isa TypeVar && r.var.name == :T
end
test_call((Vector{Type},)) do ts
issue586(ts...)
end
let result = report_call((Vector{Type},); mode=:sound) do ts
issue586(ts...)
end
@test any(get_reports_with_test(result)) do r
r isa UndefVarErrorReport && r.var isa TypeVar && r.var.name == :T
end
end
end
end

global __int_globalvar__::Int
Expand Down

0 comments on commit 24b96dc

Please sign in to comment.