Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

code quality improvements from JET analysis #159

Closed
wants to merge 1 commit into from

Conversation

aviatesk
Copy link
Contributor

I ran JET analysis on this package, and fixed some true positive errors.

run JET on MacroTools

julia> using JET
julia> report_file("src/MacroTools.jl"; analyze_from_definitions = true, annotate_types = true)

Before this PR

═════ 11 possible errors found ═════
┌ @ src/match/match.jl:27 Base.getproperty(Base.getproperty(MacroTools.Base, :match::Symbol)::typeof(match)(r"^@?(.*?)_+(_str)?$", MacroTools.string(s::Symbol)::String)::Union{Nothing, RegexMatch}, :captures::Symbol)
│┌ @ Base.jl:33 Base.getfield(x::Nothing, f::Symbol)
││ type Nothing has no field captures
│└──────────────
┌ @ src/match/types.jl:20 MacroTools.map(MacroTools.totype, ts::Vector{Symbol})
│┌ @ abstractarray.jl:2301 Base.collect_similar(A::Vector{Symbol}, Base.Generator(f::typeof(MacroTools.totype), A::Vector{Symbol})::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})
││┌ @ array.jl:620 Base._collect(cont::Vector{Symbol}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, Base.IteratorEltype(itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})::Base.EltypeUnknown, Base.IteratorSize(itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})::Base.HasShape{1})
│││┌ @ array.jl:710 Base.collect_to_with_first!(Base._similar_for(c::Vector{Symbol}, Base.typeof(v1::Union{Expr, Symbol})::Union{Type{Expr}, Type{Symbol}}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, isz::Base.HasShape{1})::Union{Vector{Expr}, Vector{Symbol}}, v1::Union{Expr, Symbol}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, st::Int64)
││││┌ @ array.jl:715 Base.setindex!(dest::Vector{Symbol}, v1::Expr, i1::Int64)
│││││┌ @ array.jl:853 Base.convert(_::Type{Symbol}, x::Expr)
││││││ no matching method found for call signature: Base.convert(_::Type{Symbol}, x::Expr)
│││││└────────────────
││││┌ @ array.jl:715 Base.setindex!(dest::Vector{Expr}, v1::Symbol, i1::Int64)
│││││┌ @ array.jl:853 Base.convert(_::Type{Expr}, x::Symbol)
││││││ no matching method found for call signature: Base.convert(_::Type{Expr}, x::Symbol)
│││││└────────────────
┌ @ src/utils.jl:21 Base.collect(Base.Generator(#11::MacroTools.var"#11#12", MacroTools.map(MacroTools.esc, xs::Tuple)::Any)::Base.Generator{_A, MacroTools.var"#11#12"} where _A)
│┌ @ array.jl:697 Base.collect_to_with_first!(Base._array_for(Base.typeof(v1::Expr)::Type{Expr}, Base.getproperty(itr::Base.Generator{_A, MacroTools.var"#11#12"} where _A, :iter::Symbol)::Any, isz::Any)::Any, v1::Expr, itr::Base.Generator{_A, MacroTools.var"#11#12"} where _A, st::Any)
││┌ @ array.jl:721 Base.grow_to!(dest::Any, itr::Base.Generator{_A, MacroTools.var"#11#12"} where _A, st::Any)
│││┌ @ dict.jl:153 Base.indexed_iterate(Core.getfield(Base.indexed_iterate(y::Tuple{Expr, Any}, 1)::Tuple{Expr, Int64}, 1)::Expr, 1)
││││┌ @ tuple.jl:89 Base.iterate(I::Expr)
│││││ no matching method found for call signature: Base.iterate(I::Expr)
││││└───────────────
┌ @ src/utils.jl:423 MacroTools.rebuilddef(MacroTools.striplines(dict::Dict)::Dict)
│ variable MacroTools.rebuilddef is not defined: MacroTools.rebuilddef(MacroTools.striplines(dict::Dict)::Dict)
└────────────────────
┌ @ src/utils.jl:455 Core.tuple(splitvar::MacroTools.var"#splitvar#35"(arg::Any)::Union{Nothing, Tuple{Any, Any}}, Core.tuple(is_splat::Bool, default::Any)::Tuple{Bool, Any}...)
│ no matching method found for call signature: Core.tuple(splitvar::MacroTools.var"#splitvar#35"(arg::Any)::Union{Nothing, Tuple{Any, Any}}, Core.tuple(is_splat::Bool, default::Any)::Tuple{Bool, Any}...)
└────────────────────
┌ @ src/utils.jl:457 Core.tuple(splitvar::MacroTools.var"#splitvar#35"(arg_expr2::Any)::Union{Nothing, Tuple{Any, Any}}, Core.tuple(is_splat::Bool, MacroTools.nothing)::Tuple{Bool, Nothing}...)
│ no matching method found for call signature: Core.tuple(splitvar::MacroTools.var"#splitvar#35"(arg_expr2::Any)::Union{Nothing, Tuple{Any, Any}}, Core.tuple(is_splat::Bool, MacroTools.nothing)::Tuple{Bool, Nothing}...)
└────────────────────
┌ @ src/structdef.jl:13 MacroTools.parse_error(ex::Any)
│ variable MacroTools.parse_error is not defined: MacroTools.parse_error(ex::Any)
└───────────────────────
┌ @ src/structdef.jl:21 MacroTools.parse_error(ex::Any)
│ variable MacroTools.parse_error is not defined: MacroTools.parse_error(ex::Any)
└───────────────────────
┌ @ src/structdef.jl:29 MacroTools.parse_error(ex::Any)
│ variable MacroTools.parse_error is not defined: MacroTools.parse_error(ex::Any)
└───────────────────────
┌ @ src/examples/destruct.jl:24 MacroTools.error("Can't destructure fields with default values")
│┌ @ error.jl:33 error(::String)
││ may throw: Base.throw($(Expr(:invoke, MethodInstance for ErrorException(::String), :(Base.ErrorException), Core.Argument(2)))::ErrorException)
│└───────────────

After this PR: only the false positives ramain (Julia's inference or JET itself should be improved)

═════ 4 possible errors found ═════
┌ @ src/match/types.jl:20 MacroTools.map(MacroTools.totype, ts::Vector{Symbol})
│┌ @ abstractarray.jl:2301 Base.collect_similar(A::Vector{Symbol}, Base.Generator(f::typeof(MacroTools.totype), A::Vector{Symbol})::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})
││┌ @ array.jl:620 Base._collect(cont::Vector{Symbol}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, Base.IteratorEltype(itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})::Base.EltypeUnknown, Base.IteratorSize(itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})::Base.HasShape{1})
│││┌ @ array.jl:710 Base.collect_to_with_first!(Base._similar_for(c::Vector{Symbol}, Base.typeof(v1::Union{Expr, Symbol})::Union{Type{Expr}, Type{Symbol}}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, isz::Base.HasShape{1})::Union{Vector{Expr}, Vector{Symbol}}, v1::Union{Expr, Symbol}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, st::Int64)
││││┌ @ array.jl:715 Base.setindex!(dest::Vector{Symbol}, v1::Expr, i1::Int64)
│││││┌ @ array.jl:853 Base.convert(_::Type{Symbol}, x::Expr)
││││││ no matching method found for call signature: Base.convert(_::Type{Symbol}, x::Expr)
│││││└────────────────
││││┌ @ array.jl:715 Base.setindex!(dest::Vector{Expr}, v1::Symbol, i1::Int64)
│││││┌ @ array.jl:853 Base.convert(_::Type{Expr}, x::Symbol)
││││││ no matching method found for call signature: Base.convert(_::Type{Expr}, x::Symbol)
│││││└────────────────
┌ @ src/utils.jl:21 Base.collect(Base.Generator(#11::MacroTools.var"#11#12", MacroTools.map(MacroTools.esc, xs::Tuple)::Any)::Base.Generator{_A, MacroTools.var"#11#12"} where _A)
│┌ @ array.jl:697 Base.collect_to_with_first!(Base._array_for(Base.typeof(v1::Expr)::Type{Expr}, Base.getproperty(itr::Base.Generator{_A, MacroTools.var"#11#12"} where _A, :iter::Symbol)::Any, isz::Any)::Any, v1::Expr, itr::Base.Generator{_A, MacroTools.var"#11#12"} where _A, st::Any)
││┌ @ array.jl:721 Base.grow_to!(dest::Any, itr::Base.Generator{_A, MacroTools.var"#11#12"} where _A, st::Any)
│││┌ @ dict.jl:153 Base.indexed_iterate(Core.getfield(Base.indexed_iterate(y::Tuple{Expr, Any}, 1)::Tuple{Expr, Int64}, 1)::Expr, 1)
││││┌ @ tuple.jl:89 Base.iterate(I::Expr)
│││││ no matching method found for call signature: Base.iterate(I::Expr)
││││└───────────────
┌ @ src/examples/destruct.jl:24 MacroTools.error("Can't destructure fields with default values")
│┌ @ error.jl:33 error(::String)
││ may throw: Base.throw($(Expr(:invoke, MethodInstance for ErrorException(::String), :(Base.ErrorException), Core.Argument(2)))::ErrorException)
│└───────────────

Symbol((Base.match(r"^@?(.*?)_+(_str)?$", string(s))::AbstractMatch).captures[1])
else
Symbol((Base.match(r"^@?(.*?)_+(_str)?$", string(s))::Base.RegexMatch).captures[1])
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change just replaces one runtime error by another, right?

julia> nothing.captures
ERROR: type Nothing has no field captures

julia> (nothing::AbstractMatch).captures
ERROR: TypeError: in typeassert, expected AbstractMatch, got a value of type Nothing

What's the point?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIU that runtime error won't happen (the regex always matches bname's argument), thus this annotation.

@aviatesk
Copy link
Contributor Author

@cstjean can you have a quick review on this ? This doesn't change any fuctionality.

@@ -417,13 +417,6 @@ function combinearg(arg_name, arg_type, is_splat, default)
return default === nothing ? a2 : Expr(:kw, a2, default)
end


macro splitcombine(fundef)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The macro with the same name is defined in test file, and this
could be removed.
This definition is also timed, especially rebuilddef is no longer defined.

@aviatesk
Copy link
Contributor Author

aviatesk commented May 2, 2021

bump, @MikeInnes @cstjean ?

@cstjean
Copy link
Collaborator

cstjean commented May 2, 2021

I approve the splitcombine removal, but don't really know these other functions well enough to review. I'd be curious to know what's the improvement behind each of these changes though...

@aviatesk
Copy link
Contributor Author

aviatesk commented May 2, 2021

I'd be curious to know what's the improvement behind each of these changes though...

They're simply bugfixes, or attempts to improve runtime performance a bit or avoid invalidation risks by kindly telling some invariants to the compiler.
The latter won't change any current behavior.

@cstjean
Copy link
Collaborator

cstjean commented May 2, 2021

They're simply bugfixes

Can you provide a MWE triggering the bug and/or write a test for it?

@aviatesk
Copy link
Contributor Author

aviatesk commented May 3, 2021

Can you provide a MWE triggering the bug

MacroTools.splitstructdef(:(non_struct_ex(arg))) maybe ?

I ran [JET analysis](https://github.com/aviatesk/JET.jl) on this package, and fixed some true positive errors.

> run JET on `MacroTools`

```julia
julia> using JET
julia> report_file("src/MacroTools.jl"; analyze_from_definitions = true, annotate_types = true)
```

> Before this PR

```julia
═════ 11 possible errors found ═════
┌ @ src/match/match.jl:27 Base.getproperty(Base.getproperty(MacroTools.Base, :match::Symbol)::typeof(match)(r"^@?(.*?)_+(_str)?$", MacroTools.string(s::Symbol)::String)::Union{Nothing, RegexMatch}, :captures::Symbol)
│┌ @ Base.jl:33 Base.getfield(x::Nothing, f::Symbol)
││ type Nothing has no field captures
│└──────────────
┌ @ src/match/types.jl:20 MacroTools.map(MacroTools.totype, ts::Vector{Symbol})
│┌ @ abstractarray.jl:2301 Base.collect_similar(A::Vector{Symbol}, Base.Generator(f::typeof(MacroTools.totype), A::Vector{Symbol})::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})
││┌ @ array.jl:620 Base._collect(cont::Vector{Symbol}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, Base.IteratorEltype(itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})::Base.EltypeUnknown, Base.IteratorSize(itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})::Base.HasShape{1})
│││┌ @ array.jl:710 Base.collect_to_with_first!(Base._similar_for(c::Vector{Symbol}, Base.typeof(v1::Union{Expr, Symbol})::Union{Type{Expr}, Type{Symbol}}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, isz::Base.HasShape{1})::Union{Vector{Expr}, Vector{Symbol}}, v1::Union{Expr, Symbol}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, st::Int64)
││││┌ @ array.jl:715 Base.setindex!(dest::Vector{Symbol}, v1::Expr, i1::Int64)
│││││┌ @ array.jl:853 Base.convert(_::Type{Symbol}, x::Expr)
││││││ no matching method found for call signature: Base.convert(_::Type{Symbol}, x::Expr)
│││││└────────────────
││││┌ @ array.jl:715 Base.setindex!(dest::Vector{Expr}, v1::Symbol, i1::Int64)
│││││┌ @ array.jl:853 Base.convert(_::Type{Expr}, x::Symbol)
││││││ no matching method found for call signature: Base.convert(_::Type{Expr}, x::Symbol)
│││││└────────────────
┌ @ src/utils.jl:21 Base.collect(Base.Generator(FluxML#11::MacroTools.var"FluxML#11#12", MacroTools.map(MacroTools.esc, xs::Tuple)::Any)::Base.Generator{_A, MacroTools.var"FluxML#11#12"} where _A)
│┌ @ array.jl:697 Base.collect_to_with_first!(Base._array_for(Base.typeof(v1::Expr)::Type{Expr}, Base.getproperty(itr::Base.Generator{_A, MacroTools.var"FluxML#11#12"} where _A, :iter::Symbol)::Any, isz::Any)::Any, v1::Expr, itr::Base.Generator{_A, MacroTools.var"FluxML#11#12"} where _A, st::Any)
││┌ @ array.jl:721 Base.grow_to!(dest::Any, itr::Base.Generator{_A, MacroTools.var"FluxML#11#12"} where _A, st::Any)
│││┌ @ dict.jl:153 Base.indexed_iterate(Core.getfield(Base.indexed_iterate(y::Tuple{Expr, Any}, 1)::Tuple{Expr, Int64}, 1)::Expr, 1)
││││┌ @ tuple.jl:89 Base.iterate(I::Expr)
│││││ no matching method found for call signature: Base.iterate(I::Expr)
││││└───────────────
┌ @ src/utils.jl:423 MacroTools.rebuilddef(MacroTools.striplines(dict::Dict)::Dict)
│ variable MacroTools.rebuilddef is not defined: MacroTools.rebuilddef(MacroTools.striplines(dict::Dict)::Dict)
└────────────────────
┌ @ src/utils.jl:455 Core.tuple(splitvar::MacroTools.var"#splitvar#35"(arg::Any)::Union{Nothing, Tuple{Any, Any}}, Core.tuple(is_splat::Bool, default::Any)::Tuple{Bool, Any}...)
│ no matching method found for call signature: Core.tuple(splitvar::MacroTools.var"#splitvar#35"(arg::Any)::Union{Nothing, Tuple{Any, Any}}, Core.tuple(is_splat::Bool, default::Any)::Tuple{Bool, Any}...)
└────────────────────
┌ @ src/utils.jl:457 Core.tuple(splitvar::MacroTools.var"#splitvar#35"(arg_expr2::Any)::Union{Nothing, Tuple{Any, Any}}, Core.tuple(is_splat::Bool, MacroTools.nothing)::Tuple{Bool, Nothing}...)
│ no matching method found for call signature: Core.tuple(splitvar::MacroTools.var"#splitvar#35"(arg_expr2::Any)::Union{Nothing, Tuple{Any, Any}}, Core.tuple(is_splat::Bool, MacroTools.nothing)::Tuple{Bool, Nothing}...)
└────────────────────
┌ @ src/structdef.jl:13 MacroTools.parse_error(ex::Any)
│ variable MacroTools.parse_error is not defined: MacroTools.parse_error(ex::Any)
└───────────────────────
┌ @ src/structdef.jl:21 MacroTools.parse_error(ex::Any)
│ variable MacroTools.parse_error is not defined: MacroTools.parse_error(ex::Any)
└───────────────────────
┌ @ src/structdef.jl:29 MacroTools.parse_error(ex::Any)
│ variable MacroTools.parse_error is not defined: MacroTools.parse_error(ex::Any)
└───────────────────────
┌ @ src/examples/destruct.jl:24 MacroTools.error("Can't destructure fields with default values")
│┌ @ error.jl:33 error(::String)
││ may throw: Base.throw($(Expr(:invoke, MethodInstance for ErrorException(::String), :(Base.ErrorException), Core.Argument(2)))::ErrorException)
│└───────────────
```

> After this PR: only the false positives ramain (Julia's inference or JET itself should be improved)

```julia
═════ 4 possible errors found ═════
┌ @ src/match/types.jl:20 MacroTools.map(MacroTools.totype, ts::Vector{Symbol})
│┌ @ abstractarray.jl:2301 Base.collect_similar(A::Vector{Symbol}, Base.Generator(f::typeof(MacroTools.totype), A::Vector{Symbol})::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})
││┌ @ array.jl:620 Base._collect(cont::Vector{Symbol}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, Base.IteratorEltype(itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})::Base.EltypeUnknown, Base.IteratorSize(itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)})::Base.HasShape{1})
│││┌ @ array.jl:710 Base.collect_to_with_first!(Base._similar_for(c::Vector{Symbol}, Base.typeof(v1::Union{Expr, Symbol})::Union{Type{Expr}, Type{Symbol}}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, isz::Base.HasShape{1})::Union{Vector{Expr}, Vector{Symbol}}, v1::Union{Expr, Symbol}, itr::Base.Generator{Vector{Symbol}, typeof(MacroTools.totype)}, st::Int64)
││││┌ @ array.jl:715 Base.setindex!(dest::Vector{Symbol}, v1::Expr, i1::Int64)
│││││┌ @ array.jl:853 Base.convert(_::Type{Symbol}, x::Expr)
││││││ no matching method found for call signature: Base.convert(_::Type{Symbol}, x::Expr)
│││││└────────────────
││││┌ @ array.jl:715 Base.setindex!(dest::Vector{Expr}, v1::Symbol, i1::Int64)
│││││┌ @ array.jl:853 Base.convert(_::Type{Expr}, x::Symbol)
││││││ no matching method found for call signature: Base.convert(_::Type{Expr}, x::Symbol)
│││││└────────────────
┌ @ src/utils.jl:21 Base.collect(Base.Generator(FluxML#11::MacroTools.var"FluxML#11#12", MacroTools.map(MacroTools.esc, xs::Tuple)::Any)::Base.Generator{_A, MacroTools.var"FluxML#11#12"} where _A)
│┌ @ array.jl:697 Base.collect_to_with_first!(Base._array_for(Base.typeof(v1::Expr)::Type{Expr}, Base.getproperty(itr::Base.Generator{_A, MacroTools.var"FluxML#11#12"} where _A, :iter::Symbol)::Any, isz::Any)::Any, v1::Expr, itr::Base.Generator{_A, MacroTools.var"FluxML#11#12"} where _A, st::Any)
││┌ @ array.jl:721 Base.grow_to!(dest::Any, itr::Base.Generator{_A, MacroTools.var"FluxML#11#12"} where _A, st::Any)
│││┌ @ dict.jl:153 Base.indexed_iterate(Core.getfield(Base.indexed_iterate(y::Tuple{Expr, Any}, 1)::Tuple{Expr, Int64}, 1)::Expr, 1)
││││┌ @ tuple.jl:89 Base.iterate(I::Expr)
│││││ no matching method found for call signature: Base.iterate(I::Expr)
││││└───────────────
┌ @ src/examples/destruct.jl:24 MacroTools.error("Can't destructure fields with default values")
│┌ @ error.jl:33 error(::String)
││ may throw: Base.throw($(Expr(:invoke, MethodInstance for ErrorException(::String), :(Base.ErrorException), Core.Argument(2)))::ErrorException)
│└───────────────
```
@aviatesk
Copy link
Contributor Author

aviatesk commented May 4, 2021

Tests are added, should be good to go.

@aviatesk
Copy link
Contributor Author

I'm going to use this example at our JuliaCon workshop and want to preserve these changes for that.

@aviatesk aviatesk closed this Jul 24, 2021
@aviatesk aviatesk deleted the infers branch July 24, 2021 06:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants