diff --git a/docs/Manifest.toml b/docs/Manifest.toml index ac25b5e14..4dde8a9e5 100644 --- a/docs/Manifest.toml +++ b/docs/Manifest.toml @@ -9,6 +9,11 @@ git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" version = "0.0.1" +[[deps.AbstractTrees]] +git-tree-sha1 = "faa260e4cb5aba097a73fab382dd4b5819d8ec8c" +uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" +version = "0.4.4" + [[deps.ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" version = "1.1.1" @@ -40,10 +45,10 @@ uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" version = "0.9.3" [[deps.Documenter]] -deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "39fd748a73dce4c05a9655475e437170d8fb1b67" +deps = ["ANSIColoredPrinters", "AbstractTrees", "Base64", "Dates", "DocStringExtensions", "Downloads", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "MarkdownAST", "Pkg", "PrecompileTools", "REPL", "RegistryInstances", "SHA", "Test", "Unicode"] +git-tree-sha1 = "f1a7eaf2b5ac7a4feb27973a09d25daf80dc56db" uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.27.25" +version = "1.0.1" [[deps.Downloads]] deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] @@ -67,7 +72,7 @@ uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" deps = ["InteractiveUtils", "JuliaInterpreter", "LoweredCodeUtils", "MacroTools", "Pkg", "PrecompileTools", "Preferences", "Revise", "Test"] path = ".." uuid = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" -version = "0.8.13" +version = "0.8.14" [[deps.JSON]] deps = ["Dates", "Mmap", "Parsers", "Unicode"] @@ -81,6 +86,11 @@ git-tree-sha1 = "81dc6aefcbe7421bd62cb6ca0e700779330acff8" uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a" version = "0.9.25" +[[deps.LazilyInitializedFields]] +git-tree-sha1 = "410fe4739a4b092f2ffe36fcb0dcc3ab12648ce1" +uuid = "0e77f7df-68c5-4e49-93ce-4cd80f5598bf" +version = "1.2.1" + [[deps.LibCURL]] deps = ["LibCURL_jll", "MozillaCACerts_jll"] uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" @@ -98,7 +108,7 @@ uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" [[deps.LibGit2_jll]] deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.6.4+0" +version = "1.7.1+0" [[deps.LibSSH2_jll]] deps = ["Artifacts", "Libdl", "MbedTLS_jll"] @@ -133,6 +143,12 @@ version = "0.5.11" deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" +[[deps.MarkdownAST]] +deps = ["AbstractTrees", "Markdown"] +git-tree-sha1 = "e8513266815200c0c8f522d6d44ffb5e9b366ae4" +uuid = "d0879d2d-cac2-40c8-9cee-1863dc0c7391" +version = "0.1.1" + [[deps.MbedTLS_jll]] deps = ["Artifacts", "Libdl"] uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" @@ -173,9 +189,9 @@ version = "1.2.0" [[deps.Preferences]] deps = ["TOML"] -git-tree-sha1 = "7eb1686b4f04b82f96ed7a4ea5890a4f0c7a09f1" +git-tree-sha1 = "00805cd429dcb4870060ff49ef443486c262e38e" uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.4.0" +version = "1.4.1" [[deps.Printf]] deps = ["Unicode"] @@ -189,6 +205,12 @@ uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" deps = ["SHA"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +[[deps.RegistryInstances]] +deps = ["LazilyInitializedFields", "Pkg", "TOML", "Tar"] +git-tree-sha1 = "ffd19052caf598b8653b99404058fce14828be51" +uuid = "2792f1a3-b283-48e8-9a74-f99dce5104f3" +version = "0.1.0" + [[deps.Requires]] deps = ["UUIDs"] git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" diff --git a/docs/make.jl b/docs/make.jl index 796581d76..a6c1b3b75 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -71,7 +71,7 @@ function generate_example_docs!(dir = PLUGIN_EXAMPLES_DIRS[1], outs = String[]) push!(outs, Literate.markdown(normpath(root, file), outdir; documenter=true)) end for dir in dirs - gen_example_doc!(normpath(root, dir), outs) + generate_example_docs!(normpath(root, dir), outs) end end @@ -94,7 +94,15 @@ function generate_api_doc(examples_pages) contents = codeblock("Pages = $(repr([out]))", "@contents") interface_docs = let objs = getfield.(Ref(JET.JETInterface), JET.JETInterface.DOCUMENTED_NAMES) - codeblock(join(string.(parentmodule.(objs), '.', nameof.(objs)), '\n')) + map(objs) do @nospecialize obj + if obj === JET.AnalysisCache + return "JET.AnalysisCache(::JET.AbstractAnalyzer)" + elseif obj === JET.InferenceErrorReport + return "JET.InferenceErrorReport()" + else + return string(parentmodule(obj), '.', nameof(obj)) + end + end |> Base.Fix2(join, '\n') |> codeblock end examples_contents = codeblock("Pages = $(repr(examples_pages))", "@contents") @@ -140,22 +148,18 @@ let "Tutorial" => "tutorial.md", "Analyses" => Any[ "Error Analysis" => "jetanalysis.md", - "Optimization Analysis" => "optanalysis.md", - ], + "Optimization Analysis" => "optanalysis.md"], "Configurations" => "config.md", "Internals" => "internals.md", "`AbstractAnalyzer` Framework" => Any[ - "API" => generate_api_doc(examples), - "Examples" => examples, - ] + "API" => generate_api_doc(examples), + "Examples" => examples] ], format = Documenter.HTML(; prettyurls = get(ENV, "CI", nothing) == "true", - ansicolor = true, - ), - ) + ansicolor = true), + warnonly = [:missing_docs, :cross_references]) end deploydocs(; repo = "github.com/aviatesk/JET.jl.git", - push_preview = true, - ) + push_preview = true) diff --git a/examples/find_unstable_api.jl b/examples/find_unstable_api.jl index 206f08b50..a06c0e629 100644 --- a/examples/find_unstable_api.jl +++ b/examples/find_unstable_api.jl @@ -242,14 +242,14 @@ function report_package_unstable_api(args...; jetconfigs...) return analyze_and_report_package!(analyzer, args...; jetconfigs...) end -using Pkg #src -if "IRTools" in keys(Pkg.project().dependencies) #src +using Pkg #hide +if "IRTools" in keys(Pkg.project().dependencies) #hide report_package_unstable_api("IRTools"; ## to only find errors detected within the module context of `IRTools` target_defined_modules=true) -else #src -@warn "IRTools isn't installed in the current environment at $(Pkg.project().path)" #src -end #src +else #hide +@warn "IRTools isn't installed in the current environment at $(Pkg.project().path)" #hide +end #hide # ``` # ═════ 59 possible errors found ═════ diff --git a/src/abstractinterpret/abstractanalyzer.jl b/src/abstractinterpret/abstractanalyzer.jl index 8c0721111..70ff80e04 100644 --- a/src/abstractinterpret/abstractanalyzer.jl +++ b/src/abstractinterpret/abstractanalyzer.jl @@ -456,14 +456,6 @@ end AnalysisCache JET's internal representation of a global analysis cache. - ---- - - AnalysisCache(analyzer::AbstractAnalyzer) -> analysis_cache::AnalysisCache - -Returns [`AnalysisCache`](@ref) for this `analyzer::AbstractAnalyzer`. -`AbstractAnalyzer` instances can share the same cache if they perform the same analysis, -otherwise their cache should be separated. """ struct AnalysisCache cache::IdDict{MethodInstance,CodeInstance} @@ -477,6 +469,13 @@ Base.setindex!(analysis_cache::AnalysisCache, ci::CodeInstance, mi::MethodInstan Base.delete!(analysis_cache::AnalysisCache, mi::MethodInstance) = delete!(analysis_cache.cache, mi) Base.show(io::IO, analysis_cache::AnalysisCache) = print(io, typeof(analysis_cache), "(", length(analysis_cache.cache), " entries)") +""" + AnalysisCache(analyzer::AbstractAnalyzer) -> analysis_cache::AnalysisCache + +Returns [`AnalysisCache`](@ref) for this `analyzer::AbstractAnalyzer`. +`AbstractAnalyzer` instances can share the same cache if they perform the same analysis, +otherwise their cache should be separated. +""" @noinline function AnalysisCache(analyzer::AbstractAnalyzer) AnalyzerType = nameof(typeof(analyzer)) error(lazy""" diff --git a/src/abstractinterpret/inferenceerrorreport.jl b/src/abstractinterpret/inferenceerrorreport.jl index 6622e5bab..8950b8b33 100644 --- a/src/abstractinterpret/inferenceerrorreport.jl +++ b/src/abstractinterpret/inferenceerrorreport.jl @@ -408,34 +408,48 @@ handle_sig!(sig::Vector{Any}, ::StateAtPC, @nospecialize(x)) = (push!(sig, x); r # new report # ---------- +""" + abstract type InferenceErrorReport end + +An interface type of error reports collected by JET's abstract interpretation based analysis. +All `InferenceErrorReport`s have the following fields, +which explains _where_ and _how_ this error is reported: +- [`vst::VirtualStackTrace`](@ref VirtualStackTrace): a virtual stack trace of the error +- [`sig::Signature`](@ref Signature): a signature of the error point + +Note that some `InferenceErrorReport` may have additional fields other than `vst` and `sig` +to explain _why_ they are reported. +""" +abstract type InferenceErrorReport end + """ InferenceErrorReport -An interface type of error reports that JET collects by abstract interpration. -In order for `R<:InferenceErrorReport` to implement the interface, +In order for `Report <: InferenceErrorReport` to implement the interface, it should satisfy the following requirements: - **Required fields** \\ - `R` should have the following fields, which explains _where_ and _how_ this error is reported: + `Report` should have the following fields, + which explains _where_ and _how_ this error is reported: * `vst::VirtualStackTrace`: a virtual stack trace of the error * [`sig::Signature`](@ref Signature): a signature of the error point - Note that `R` can have additional fields other than `vst` and `sig` to explain + Note that `Report` can have additional fields other than `vst` and `sig` to explain _why_ this error is reported (mostly used for [`print_report_message`](@ref)). - **Required overloads** \\ - * [`copy_report(report::R) -> new::R`](@ref copy_report) - * [`print_report_message(io::IO, report::R)`](@ref print_report_message) + * [`copy_report(report::Report) -> new::Report`](@ref copy_report) + * [`print_report_message(io::IO, report::Report)`](@ref print_report_message) - **Optional overloads** \\ - * [`print_signature(::R) -> Bool`](@ref print_signature) - * [`report_color(::R) -> Symbol`](@ref report_color) + * [`print_signature(::Report) -> Bool`](@ref print_signature) + * [`report_color(::Report) -> Symbol`](@ref report_color) -`R<:InferenceErrorReport` is supposed to be constructed using the following constructor +`Report <: InferenceErrorReport` is supposed to be constructed using the following constructor - R(::AbstractAnalyzer, state, spec_args...) -> R + Report(::AbstractAnalyzer, state, spec_args...) -> Report where `state` can be either of: - `state::$StateAtPC`: a state with the current program counter specified @@ -445,15 +459,15 @@ where `state` can be either of: See also: [`@jetreport`](@ref), [`VirtualStackTrace`](@ref), [`VirtualFrame`](@ref) """ -abstract type InferenceErrorReport end +function InferenceErrorReport() end # interfaces # ---------- """ - copy_report(report::R) where R<:InferenceErrorReport -> new::R + copy_report(report::Report) where Report<:InferenceErrorReport -> new::Report -Returns new `new::R`, that should be identical to the original `report::R`, except +Returns new `new::Report`, that should be identical to the original `report::Report`, except that `new.vst` is copied from `report.vst` so that the further modification on `report.vst` that may happen in later abstract interpretation doesn't affect `new.vst`. """ @@ -461,7 +475,7 @@ that may happen in later abstract interpretation doesn't affect `new.vst`. error(lazy"`copy_report(::$(typeof(report)))` is not implemented")) """ - print_report_message(io::IO, report::R) where R<:InferenceErrorReport + print_report_message(io::IO, report::Report) where Report<:InferenceErrorReport Prints to `io` and describes _why_ `report` is reported. """ @@ -469,16 +483,16 @@ Prints to `io` and describes _why_ `report` is reported. error(lazy"`print_report_message(::IO, ::$(typeof(report)))` is not implemented")) """ - print_signature(::R) where R<:InferenceErrorReport -> Bool + print_signature(::Report) where Report<:InferenceErrorReport -> Bool -Configures whether or not to print the report signature when printing `R` (defaults to `true`). +Configures whether or not to print the report signature when printing `Report` (defaults to `true`). """ print_signature(::InferenceErrorReport) = true """ - report_color(::R) where R<:InferenceErrorReport -> Symbol + report_color(::Report) where Report<:InferenceErrorReport -> Symbol -Configures the color for `R` (defaults to `:red`). +Configures the color for `Report` (defaults to `:red`). """ report_color(::InferenceErrorReport) = ERROR_COLOR @@ -500,11 +514,11 @@ end function copy_report′(@nospecialize report::InferenceErrorReport) @static if JET_DEV_MODE new = copy_report(report) - R = typeof(report) - if !isa(new, R) + Report = typeof(report) + if !isa(new, Report) error(lazy""" bad `$InferenceErrorReport` interface: - `$copy_report(::$R)` should return new `$R`. + `$copy_report(::$Report)` should return new `$Report`. See the documentation of `$InferenceErrorReport` and `$copy_report` """) end @@ -512,7 +526,7 @@ function copy_report′(@nospecialize report::InferenceErrorReport) if report.vst === new.vst && (@static JET_DEV_MODE ? report.vst == new.vst : true) error(lazy""" bad `$InferenceErrorReport` interface: - `$copy_report(report::$R).vst` should be a copy of `report.vst`. + `$copy_report(report::$Report).vst` should be a copy of `report.vst`. See the documentation of `$InferenceErrorReport` and `$copy_report` """) end @@ -529,11 +543,11 @@ function Base.show(io::IO, report::InferenceErrorReport) end # the default constructor to create a report from abstract interpretation -function (T::Type{<:InferenceErrorReport})(state, @nospecialize(spec_args...)) +function (Report::Type{<:InferenceErrorReport})(state, @nospecialize(spec_args...)) vf = get_virtual_frame(state) vst = VirtualFrame[vf] sig = get_sig(state) - return T(vst, sig, spec_args...) + return Report(vst, sig, spec_args...) end # utility @@ -542,7 +556,7 @@ end # TODO parametric definition? """ - @jetreport struct T <: InferenceErrorReport + @jetreport struct NewReport <: InferenceErrorReport ... end @@ -551,8 +565,8 @@ It can be very tedious to manually satisfy the `InferenceErrorReport` interfaces JET internally uses this `@jetreport` utility macro, which takes a `struct` definition of `InferenceErrorReport` without the required fields specified, and automatically defines the `struct` as well as constructor definitions. -If the report `T <: InferenceErrorReport` is defined using `@jetreport`, -then `T` just needs to implement the `print_report_message` interface. +If the report `NewReport <: InferenceErrorReport` is defined using `@jetreport`, +then `NewReport` just needs to implement the `print_report_message` interface. For example, [`JETAnalyzer`](@ref)'s `MethodErrorReport` is defined as follows: ```julia @@ -578,8 +592,8 @@ end and constructed as like `MethodErrorReport(sv::InferenceState, atype::Any, 0)`. """ macro jetreport(ex) - @assert @capture(ex, struct T_ <: S_; spec_sigs__; end) - @assert Core.eval(__module__, S) <: InferenceErrorReport + @assert @capture(ex, struct NewReport_ <: Super_; spec_sigs__; end) + @assert Core.eval(__module__, Super) <: InferenceErrorReport spec_decls = Any[] for i in 1:length(spec_sigs) @@ -596,12 +610,12 @@ macro jetreport(ex) spec_names = extract_decl_name.(spec_decls) spec_types = esc.(extract_decl_type.(spec_decls)) - T, S = esc(T), esc(S) + NewReport, Super = esc(NewReport), esc(Super) # copy_report copy_report = let - sig = :($(GlobalRef(JET, :copy_report))(report::$T)) - call = :($T(copy(report.vst), report.sig)) + sig = :($(GlobalRef(JET, :copy_report))(report::$NewReport)) + call = :($NewReport(copy(report.vst), report.sig)) for name in spec_names push!(call.args, :(getproperty(report, $(QuoteNode(name))))) end @@ -609,11 +623,11 @@ macro jetreport(ex) end return quote - Base.@__doc__ struct $T <: $S + Base.@__doc__ struct $NewReport <: $Super $(INFERENCE_ERROR_REPORT_FIELD_DECLS...) $(map(esc, spec_decls)...) # esc is needed here since signanture might be `@nospecialize`d - function $T($(INFERENCE_ERROR_REPORT_FIELD_DECLS...), $(map(esc, spec_sigs)...)) + function $NewReport($(INFERENCE_ERROR_REPORT_FIELD_DECLS...), $(map(esc, spec_sigs)...)) new($(extract_decl_name.(INFERENCE_ERROR_REPORT_FIELD_DECLS)...), $(map(esc, spec_names)...)) end end