|
1 | 1 | module Analyzer |
2 | 2 |
|
3 | 3 | export LSAnalyzer, inference_error_report_severity, inference_error_report_stack, reset_report_target_modules! |
4 | | -export BoundsErrorReport, FieldErrorReport, UndefVarErrorReport |
| 4 | +export BoundsErrorReport, FieldErrorReport, MethodErrorReport, UndefVarErrorReport |
5 | 5 |
|
6 | 6 | using Core.IR |
7 | 7 | using JET.JETInterface |
@@ -234,6 +234,29 @@ end # @static if VERSION ≥ v"1.12.2" |
234 | 234 | # Analysis injections |
235 | 235 | # =================== |
236 | 236 |
|
| 237 | +function CC.abstract_call_gf_by_type( |
| 238 | + analyzer::LSAnalyzer, @nospecialize(func), arginfo::CC.ArgInfo, si::CC.StmtInfo, |
| 239 | + @nospecialize(atype), sv::CC.InferenceState, max_methods::Int |
| 240 | + ) |
| 241 | + ret = @invoke CC.abstract_call_gf_by_type(analyzer::ToplevelAbstractAnalyzer, |
| 242 | + func::Any, arginfo::CC.ArgInfo, si::CC.StmtInfo, atype::Any, sv::CC.InferenceState, max_methods::Int) |
| 243 | + if !should_analyze(analyzer, sv) |
| 244 | + return ret |
| 245 | + end |
| 246 | + atype′ = Ref{Any}(atype) |
| 247 | + function after_abstract_call_gf_by_type(analyzer′::LSAnalyzer, sv′::CC.InferenceState) |
| 248 | + ret′ = ret[] |
| 249 | + report_method_error!(analyzer′, sv′, ret′, arginfo, atype′[]) |
| 250 | + return true |
| 251 | + end |
| 252 | + if isready(ret) |
| 253 | + after_abstract_call_gf_by_type(analyzer, sv) |
| 254 | + else |
| 255 | + push!(sv.tasks, after_abstract_call_gf_by_type) |
| 256 | + end |
| 257 | + return ret |
| 258 | +end |
| 259 | + |
237 | 260 | # TODO Better to factor out and share it with `JET.JETAnalyzer` |
238 | 261 | function CC.abstract_eval_globalref( |
239 | 262 | analyzer::LSAnalyzer, g::GlobalRef, saw_latestworld::Bool, sv::CC.InferenceState; |
@@ -469,6 +492,76 @@ function report_fieldaccess!( |
469 | 492 | return true |
470 | 493 | end |
471 | 494 |
|
| 495 | +# MethodErrorReport |
| 496 | +# ----------------- |
| 497 | + |
| 498 | +@jetreport struct MethodErrorReport <: LSErrorReport |
| 499 | + @nospecialize t # ::Union{Type, Vector{Type}} |
| 500 | + union_split::Int |
| 501 | +end |
| 502 | +function JETInterface.print_report_message(io::IO, report::MethodErrorReport) |
| 503 | + print(io, "no matching method found ") |
| 504 | + if report.union_split == 0 |
| 505 | + print_callsig(io, report.t) |
| 506 | + else |
| 507 | + ts = report.t::Vector{Any} |
| 508 | + nts = length(ts) |
| 509 | + for i = 1:nts |
| 510 | + print_callsig(io, ts[i]) |
| 511 | + i == nts || print(io, ", ") |
| 512 | + end |
| 513 | + print(io, " (", nts, '/', report.union_split, " union split)") |
| 514 | + end |
| 515 | +end |
| 516 | +function print_callsig(io, @nospecialize(t)) |
| 517 | + print(io, '`') |
| 518 | + Base.show_tuple_as_call(io, Symbol(""), t) |
| 519 | + print(io, '`') |
| 520 | +end |
| 521 | +inference_error_report_stack_impl(r::MethodErrorReport) = length(r.vst):-1:1 |
| 522 | +inference_error_report_severity_impl(::MethodErrorReport) = DiagnosticSeverity.Warning |
| 523 | + |
| 524 | +function report_method_error!(analyzer::LSAnalyzer, |
| 525 | + sv::CC.InferenceState, call::CC.CallMeta, arginfo::CC.ArgInfo, @nospecialize(atype)) |
| 526 | + info = call.info |
| 527 | + if isa(info, CC.ConstCallInfo) |
| 528 | + info = info.call |
| 529 | + end |
| 530 | + if isa(info, CC.MethodMatchInfo) |
| 531 | + report_method_error!(analyzer, sv, info, atype) |
| 532 | + elseif isa(info, CC.UnionSplitInfo) |
| 533 | + report_method_error_for_union_split!(analyzer, sv, info, arginfo) |
| 534 | + end |
| 535 | +end |
| 536 | + |
| 537 | +function report_method_error!(analyzer::LSAnalyzer, sv::CC.InferenceState, info::CC.MethodMatchInfo, @nospecialize(atype)) |
| 538 | + if CC.isempty(info.results) |
| 539 | + report = MethodErrorReport(sv, atype, 0) |
| 540 | + add_new_report!(analyzer, sv.result, report) |
| 541 | + end |
| 542 | +end |
| 543 | + |
| 544 | +function report_method_error_for_union_split!(analyzer::LSAnalyzer, sv::CC.InferenceState, info::CC.UnionSplitInfo, arginfo::CC.ArgInfo) |
| 545 | + # check each match for union-split signature |
| 546 | + split_argtypes = empty_matches = nothing |
| 547 | + for (i, matchinfo) in enumerate(info.split) |
| 548 | + if CC.isempty(matchinfo.results) |
| 549 | + if isnothing(split_argtypes) |
| 550 | + split_argtypes = CC.switchtupleunion(CC.typeinf_lattice(analyzer), arginfo.argtypes) |
| 551 | + end |
| 552 | + argtypes′ = split_argtypes[i]::Vector{Any} |
| 553 | + if empty_matches === nothing |
| 554 | + empty_matches = (Any[], length(info.split)) |
| 555 | + end |
| 556 | + sig_n = CC.argtypes_to_type(argtypes′) |
| 557 | + push!(empty_matches[1], sig_n) |
| 558 | + end |
| 559 | + end |
| 560 | + if empty_matches !== nothing |
| 561 | + add_new_report!(analyzer, sv.result, MethodErrorReport(sv, empty_matches...)) |
| 562 | + end |
| 563 | +end |
| 564 | + |
472 | 565 | # Constructor |
473 | 566 | # =========== |
474 | 567 |
|
|
0 commit comments