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

more exception escaping #3

Merged
merged 4 commits into from
Jan 13, 2020
Merged

more exception escaping #3

merged 4 commits into from
Jan 13, 2020

Conversation

aviatesk
Copy link
Owner

No description provided.

@aviatesk aviatesk merged commit 18252ca into escape-recursion Jan 13, 2020
@aviatesk aviatesk deleted the exception branch January 13, 2020 15:21
aviatesk added a commit that referenced this pull request May 4, 2021
WIP because I found this is better to be generalized to a control flow
analysis that checks for "never reaching exit points".
For As an example, `sum(a for a in NeverTeminate(::Int))` will come down
to `Base._fold_impl`, which directly uses `iterate(::NeverTeminate, [state])`,
against which the current implementation based on the iteration protocol
can't report an error.

> Adapated from https://github.com/JuliaLang/julia/blob/24d9eab45632bdb3120c9e664503745eb58aa2d6/base/reduce.jl#L53-L65

```julia
function _foldl_impl(op::OP, init, itr) where {OP}
    # Unroll the while loop once; if init is known, the call to op may
    # be evaluated at compile time
    y = iterate(itr)
    y === nothing && return init
    v = op(init, y[1])
    while true
        y = iterate(itr, y[2])
        y === nothing && break
        v = op(v, y[1])
    end
    return v
end
```

> In a lowered representation

```julia
CodeInfo(
1 ─       Core.NewvarNode(:(v))
│         y = Base.iterate(itr)
│   %3  = y === Base.nothing
└──       goto #3 if not %3
2 ─       return init
3 ─ %6  = Base.getindex(y, 1)
└──       v = (op)(init, %6)
4 ┄       goto #8 if not true
5 ─ %9  = Base.getindex(y, 2)
│         y = Base.iterate(itr, %9)
│   %11 = y === Base.nothing
└──       goto #7 if not %11
6 ─       goto #8
7 ─ %14 = v
│   %15 = Base.getindex(y, 1)
│         v = (op)(%14, %15)
└──       goto #4
8 ┄       return v
)
```

We can report infinite iteration by checking both `goto #3 if not %3`
and
`goto #7 if not %11` never happens and thus this function never returns.

---

- closes #135
- closes #179
aviatesk added a commit that referenced this pull request May 6, 2021
WIP because I found this is better to be generalized to a control flow
analysis that checks for "never reaching exit points".
For As an example, `sum(a for a in NeverTeminate(::Int))` will come down
to `Base._fold_impl`, which directly uses `iterate(::NeverTeminate, [state])`,
against which the current implementation based on the iteration protocol
can't report an error.

> Adapated from https://github.com/JuliaLang/julia/blob/24d9eab45632bdb3120c9e664503745eb58aa2d6/base/reduce.jl#L53-L65

```julia
function _foldl_impl(op::OP, init, itr) where {OP}
    # Unroll the while loop once; if init is known, the call to op may
    # be evaluated at compile time
    y = iterate(itr)
    y === nothing && return init
    v = op(init, y[1])
    while true
        y = iterate(itr, y[2])
        y === nothing && break
        v = op(v, y[1])
    end
    return v
end
```

> In a lowered representation

```julia
CodeInfo(
1 ─       Core.NewvarNode(:(v))
│         y = Base.iterate(itr)
│   %3  = y === Base.nothing
└──       goto #3 if not %3
2 ─       return init
3 ─ %6  = Base.getindex(y, 1)
└──       v = (op)(init, %6)
4 ┄       goto #8 if not true
5 ─ %9  = Base.getindex(y, 2)
│         y = Base.iterate(itr, %9)
│   %11 = y === Base.nothing
└──       goto #7 if not %11
6 ─       goto #8
7 ─ %14 = v
│   %15 = Base.getindex(y, 1)
│         v = (op)(%14, %15)
└──       goto #4
8 ┄       return v
)
```

We can report infinite iteration by checking both `goto #3 if not %3` and
`goto #7 if not %11` never happens and thus this function never returns.

---

- closes #135
- closes #179
aviatesk added a commit that referenced this pull request May 10, 2021
WIP because I found this is better to be generalized to a control flow
analysis that checks for "never reaching exit points".
For As an example, `sum(a for a in NeverTeminate(::Int))` will come down
to `Base._fold_impl`, which directly uses `iterate(::NeverTeminate, [state])`,
against which the current implementation based on the iteration protocol
can't report an error.

> Adapated from https://github.com/JuliaLang/julia/blob/24d9eab45632bdb3120c9e664503745eb58aa2d6/base/reduce.jl#L53-L65

```julia
function _foldl_impl(op::OP, init, itr) where {OP}
    # Unroll the while loop once; if init is known, the call to op may
    # be evaluated at compile time
    y = iterate(itr)
    y === nothing && return init
    v = op(init, y[1])
    while true
        y = iterate(itr, y[2])
        y === nothing && break
        v = op(v, y[1])
    end
    return v
end
```

> In a lowered representation

```julia
CodeInfo(
1 ─       Core.NewvarNode(:(v))
│         y = Base.iterate(itr)
│   %3  = y === Base.nothing
└──       goto #3 if not %3
2 ─       return init
3 ─ %6  = Base.getindex(y, 1)
└──       v = (op)(init, %6)
4 ┄       goto #8 if not true
5 ─ %9  = Base.getindex(y, 2)
│         y = Base.iterate(itr, %9)
│   %11 = y === Base.nothing
└──       goto #7 if not %11
6 ─       goto #8
7 ─ %14 = v
│   %15 = Base.getindex(y, 1)
│         v = (op)(%14, %15)
└──       goto #4
8 ┄       return v
)
```

We can report infinite iteration by checking both `goto #3 if not %3` and
`goto #7 if not %11` never happens and thus this function never returns.

---

- closes #135
- closes #179
aviatesk added a commit that referenced this pull request May 25, 2023
Since we are familiar with the stacktrace view that Julia Base shows
when an exception is thrown, it might be better to use the same view for
showing JET's abstract stacktrace.

Previously JET tries to "infer" the textual code representation of the
call-sites of each stack-frame, but now JET does not need to do so as
`MethodInstance` is already available for each (abstract) stack-frame.
So this commit may result in some performance improvement.

Examples:

> Before
```julia
julia> @report_call sum([])
═════ 1 possible error found ═════
┌ @ reducedim.jl:996 Base.:(var"#sum#821")(:, pairs(NamedTuple()), #self#, a)
│┌ @ reducedim.jl:996 Base._sum(a, dims)
││┌ @ reducedim.jl:1000 Base.:(var"#_sum#823")(pairs(NamedTuple()), #self#, a, _3)
│││┌ @ reducedim.jl:1000 Base._sum(identity, a, :)
││││┌ @ reducedim.jl:1001 Base.:(var"#_sum#824")(pairs(NamedTuple()), #self#, f, a, _4)
│││││┌ @ reducedim.jl:1001 mapreduce(f, Base.add_sum, a)
││││││┌ @ reducedim.jl:357 Base.:(var"#mapreduce#814")(:, Base._InitialValue(), #self#, f, op, A)
│││││││┌ @ reducedim.jl:357 Base._mapreduce_dim(f, op, init, A, dims)
││││││││┌ @ reducedim.jl:365 Base._mapreduce(f, op, IndexStyle(A), A)
│││││││││┌ @ reduce.jl:432 Base.mapreduce_empty_iter(f, op, A, Base.IteratorEltype(A))
││││││││││┌ @ reduce.jl:380 Base.reduce_empty_iter(Base.MappingRF(f, op), itr, ItrEltype)
│││││││││││┌ @ reduce.jl:384 Base.reduce_empty(op, eltype(itr))
││││││││││││┌ @ reduce.jl:361 Base.mapreduce_empty(op.f, op.rf, T)
│││││││││││││┌ @ reduce.jl:372 Base.reduce_empty(op, T)
││││││││││││││┌ @ reduce.jl:352 Base.reduce_empty(+, T)
│││││││││││││││┌ @ reduce.jl:343 zero(T)
││││││││││││││││┌ @ missing.jl:106 Base.throw(Base.MethodError(zero, tuple(Base.Any)))
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└──────────────────
```
> After
```julia
julia> @report_call sum([])
═════ 1 possible error found ═════
┌ @ reducedim.jl:996 sum(a::Vector{Any})
│┌ @ reducedim.jl:996 sum(a::Vector{Any}; dims::Colon, kw::Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}})
││┌ @ reducedim.jl:1000 _sum(a::Vector{Any}, ::Colon)
│││┌ @ reducedim.jl:1000 _sum(a::Vector{Any}, ::Colon; kw::Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}})
││││┌ @ reducedim.jl:1001 _sum(f::typeof(identity), a::Vector{Any}, ::Colon)
│││││┌ @ reducedim.jl:1001 _sum(f::typeof(identity), a::Vector{Any}, ::Colon; kw::Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}})
││││││┌ @ reducedim.jl:357 mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any})
│││││││┌ @ reducedim.jl:357 mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}; dims::Colon, init::Base._InitialValue)
││││││││┌ @ reducedim.jl:365 _mapreduce_dim(f::typeof(identity), op::typeof(Base.add_sum), ::Base._InitialValue, A::Vector{Any}, ::Colon)
│││││││││┌ @ reduce.jl:432 _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Any})
││││││││││┌ @ reduce.jl:380 mapreduce_empty_iter(f::typeof(identity), op::typeof(Base.add_sum), itr::Vector{Any}, ItrEltype::Base.HasEltype)
│││││││││││┌ @ reduce.jl:384 reduce_empty_iter(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, itr::Vector{Any}, ::Base.HasEltype)
││││││││││││┌ @ reduce.jl:361 reduce_empty(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, ::Type{Any})
│││││││││││││┌ @ reduce.jl:372 mapreduce_empty(::typeof(identity), op::typeof(Base.add_sum), T::Type{Any})
││││││││││││││┌ @ reduce.jl:352 reduce_empty(::typeof(Base.add_sum), ::Type{Any})
│││││││││││││││┌ @ reduce.jl:343 reduce_empty(::typeof(+), ::Type{Any})
││││││││││││││││┌ @ missing.jl:106 zero(::Type{Any})
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└──────────────────
```

> Before
```julia
julia> getprop(x) = x.nonexist;

julia> report_call((Regex,)) do r
           getprop(r)
       end
═════ 1 possible error found ═════
┌ @ REPL[30]:2 getprop(r)
│┌ @ REPL[29]:1 x.nonexist
││┌ @ Base.jl:37 Base.getfield(x, f)
│││ type Regex has no field nonexist
││└──────────────
```
> After
```julia
julia> getprop(x) = x.nonexist;

julia> report_call((Regex,)) do r
           getprop(r)
       end
═════ 1 possible error found ═════
┌ @ REPL[5]:2 (::var"#3#4")(r::Regex)
│┌ @ REPL[4]:1 getprop(x::Regex)
││┌ @ Base.jl:37 getproperty(x::Regex, f::Symbol)
│││ type Regex has no field nonexist: Base.getfield(x::Regex, f::Symbol)
││└──────────────
```
aviatesk added a commit that referenced this pull request May 29, 2023
Since the stacktrace view shown by Julia Base upon exception is more
familiar to general users, it would be better to use the same view for
showing JET's abstract stacktrace.

Previously JET tries to "infer" the textual code representation of the
call-sites of each stack-frame, but now JET does not need to do so, and
JET can show the method signature of each abstract stack-frame from
their `MethodInstance` that is already available. Therefore, this commit
may result in some performance improvement.

Note that JET still computes the textual code representation with type
annotations for each error point. We may replace that part with
TypedSyntax.jl in the future since it would be more robust and nicer.

\## Examples: `@report_call sum([])`

> Before
```julia
═════ 1 possible error found ═════
┌ @ reducedim.jl:996 Base.:(var"#sum#821")(:, pairs(NamedTuple()), #self#, a)
│┌ @ reducedim.jl:996 Base._sum(a, dims)
││┌ @ reducedim.jl:1000 Base.:(var"#_sum#823")(pairs(NamedTuple()), #self#, a, _3)
│││┌ @ reducedim.jl:1000 Base._sum(identity, a, :)
││││┌ @ reducedim.jl:1001 Base.:(var"#_sum#824")(pairs(NamedTuple()), #self#, f, a, _4)
│││││┌ @ reducedim.jl:1001 mapreduce(f, Base.add_sum, a)
││││││┌ @ reducedim.jl:357 Base.:(var"#mapreduce#814")(:, Base._InitialValue(), #self#, f, op, A)
│││││││┌ @ reducedim.jl:357 Base._mapreduce_dim(f, op, init, A, dims)
││││││││┌ @ reducedim.jl:365 Base._mapreduce(f, op, IndexStyle(A), A)
│││││││││┌ @ reduce.jl:432 Base.mapreduce_empty_iter(f, op, A, Base.IteratorEltype(A))
││││││││││┌ @ reduce.jl:380 Base.reduce_empty_iter(Base.MappingRF(f, op), itr, ItrEltype)
│││││││││││┌ @ reduce.jl:384 Base.reduce_empty(op, eltype(itr))
││││││││││││┌ @ reduce.jl:361 Base.mapreduce_empty(op.f, op.rf, T)
│││││││││││││┌ @ reduce.jl:372 Base.reduce_empty(op, T)
││││││││││││││┌ @ reduce.jl:352 Base.reduce_empty(+, T)
│││││││││││││││┌ @ reduce.jl:343 zero(T)
││││││││││││││││┌ @ missing.jl:106 Base.throw(Base.MethodError(zero, tuple(Base.Any)))
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└──────────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ sum(a::Vector{Any}) @ Base ./reducedim.jl:996
│┌ sum(a::Vector{Any}; dims::Colon, kw::Base.@kwargs{}) @ Base ./reducedim.jl:996
││┌ _sum(a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1000
│││┌ _sum(a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1000
││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1001
│││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1001
││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}) @ Base ./reducedim.jl:357
│││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}; dims::Colon, init::Base._InitialValue) @ Base ./reducedim.jl:357
││││││││┌ _mapreduce_dim(f::typeof(identity), op::typeof(Base.add_sum), ::Base._InitialValue, A::Vector{Any}, ::Colon) @ Base ./reducedim.jl:365
│││││││││┌ _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Any}) @ Base ./reduce.jl:432
││││││││││┌ mapreduce_empty_iter(f::typeof(identity), op::typeof(Base.add_sum), itr::Vector{Any}, ItrEltype::Base.HasEltype) @ Base ./reduce.jl:380
│││││││││││┌ reduce_empty_iter(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, itr::Vector{Any}, ::Base.HasEltype) @ Base ./reduce.jl:384
││││││││││││┌ reduce_empty(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, ::Type{Any}) @ Base ./reduce.jl:361
│││││││││││││┌ mapreduce_empty(::typeof(identity), op::typeof(Base.add_sum), T::Type{Any}) @ Base ./reduce.jl:372
││││││││││││││┌ reduce_empty(::typeof(Base.add_sum), ::Type{Any}) @ Base ./reduce.jl:352
│││││││││││││││┌ reduce_empty(::typeof(+), ::Type{Any}) @ Base ./reduce.jl:343
││││││││││││││││┌ zero(::Type{Any}) @ Base ./missing.jl:106
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└────────────────────
```

\## Example 2
```julia
getprop(x) = x.nonexist;

report_call((Regex,)) do r
    getprop(r)
end
```

> Before
```julia
═════ 1 possible error found ═════
┌ @ REPL[30]:2 getprop(r)
│┌ @ REPL[29]:1 x.nonexist
││┌ @ Base.jl:37 Base.getfield(x, f)
│││ type Regex has no field nonexist
││└──────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ (::var"#3#4")(r::Regex) @ Main ./REPL[12]:2
│┌ getprop(x::Regex) @ Main ./REPL[11]:1
││┌ getproperty(x::Regex, f::Symbol) @ Base ./Base.jl:37
│││ type Regex has no field nonexist: Base.getfield(x::Regex, f::Symbol)
││└────────────────────
```
aviatesk added a commit that referenced this pull request May 29, 2023
Since the stacktrace view shown by Julia Base upon exception is more
familiar to general users, it would be better to use the same view for
showing JET's abstract stacktrace.

Previously JET tries to "infer" the textual code representation of the
call-sites of each stack-frame, but now JET does not need to do so, and
JET can show the method signature of each abstract stack-frame from
their `MethodInstance` that is already available. Therefore, this commit
may result in some performance improvement.

Note that JET still computes the textual code representation with type
annotations for each error point. We may replace that part with
TypedSyntax.jl in the future since it would be more robust and nicer.

\## Examples: `@report_call sum([])`

> Before
```julia
═════ 1 possible error found ═════
┌ @ reducedim.jl:996 Base.:(var"#sum#821")(:, pairs(NamedTuple()), #self#, a)
│┌ @ reducedim.jl:996 Base._sum(a, dims)
││┌ @ reducedim.jl:1000 Base.:(var"#_sum#823")(pairs(NamedTuple()), #self#, a, _3)
│││┌ @ reducedim.jl:1000 Base._sum(identity, a, :)
││││┌ @ reducedim.jl:1001 Base.:(var"#_sum#824")(pairs(NamedTuple()), #self#, f, a, _4)
│││││┌ @ reducedim.jl:1001 mapreduce(f, Base.add_sum, a)
││││││┌ @ reducedim.jl:357 Base.:(var"#mapreduce#814")(:, Base._InitialValue(), #self#, f, op, A)
│││││││┌ @ reducedim.jl:357 Base._mapreduce_dim(f, op, init, A, dims)
││││││││┌ @ reducedim.jl:365 Base._mapreduce(f, op, IndexStyle(A), A)
│││││││││┌ @ reduce.jl:432 Base.mapreduce_empty_iter(f, op, A, Base.IteratorEltype(A))
││││││││││┌ @ reduce.jl:380 Base.reduce_empty_iter(Base.MappingRF(f, op), itr, ItrEltype)
│││││││││││┌ @ reduce.jl:384 Base.reduce_empty(op, eltype(itr))
││││││││││││┌ @ reduce.jl:361 Base.mapreduce_empty(op.f, op.rf, T)
│││││││││││││┌ @ reduce.jl:372 Base.reduce_empty(op, T)
││││││││││││││┌ @ reduce.jl:352 Base.reduce_empty(+, T)
│││││││││││││││┌ @ reduce.jl:343 zero(T)
││││││││││││││││┌ @ missing.jl:106 Base.throw(Base.MethodError(zero, tuple(Base.Any)))
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└──────────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ sum(a::Vector{Any}) @ Base ./reducedim.jl:996
│┌ sum(a::Vector{Any}; dims::Colon, kw::Base.@kwargs{}) @ Base ./reducedim.jl:996
││┌ _sum(a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1000
│││┌ _sum(a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1000
││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1001
│││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1001
││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}) @ Base ./reducedim.jl:357
│││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}; dims::Colon, init::Base._InitialValue) @ Base ./reducedim.jl:357
││││││││┌ _mapreduce_dim(f::typeof(identity), op::typeof(Base.add_sum), ::Base._InitialValue, A::Vector{Any}, ::Colon) @ Base ./reducedim.jl:365
│││││││││┌ _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Any}) @ Base ./reduce.jl:432
││││││││││┌ mapreduce_empty_iter(f::typeof(identity), op::typeof(Base.add_sum), itr::Vector{Any}, ItrEltype::Base.HasEltype) @ Base ./reduce.jl:380
│││││││││││┌ reduce_empty_iter(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, itr::Vector{Any}, ::Base.HasEltype) @ Base ./reduce.jl:384
││││││││││││┌ reduce_empty(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, ::Type{Any}) @ Base ./reduce.jl:361
│││││││││││││┌ mapreduce_empty(::typeof(identity), op::typeof(Base.add_sum), T::Type{Any}) @ Base ./reduce.jl:372
││││││││││││││┌ reduce_empty(::typeof(Base.add_sum), ::Type{Any}) @ Base ./reduce.jl:352
│││││││││││││││┌ reduce_empty(::typeof(+), ::Type{Any}) @ Base ./reduce.jl:343
││││││││││││││││┌ zero(::Type{Any}) @ Base ./missing.jl:106
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└────────────────────
```

\## Example 2
```julia
getprop(x) = x.nonexist;

report_call((Regex,)) do r
    getprop(r)
end
```

> Before
```julia
═════ 1 possible error found ═════
┌ @ REPL[30]:2 getprop(r)
│┌ @ REPL[29]:1 x.nonexist
││┌ @ Base.jl:37 Base.getfield(x, f)
│││ type Regex has no field nonexist
││└──────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ (::var"#3#4")(r::Regex) @ Main ./REPL[12]:2
│┌ getprop(x::Regex) @ Main ./REPL[11]:1
││┌ getproperty(x::Regex, f::Symbol) @ Base ./Base.jl:37
│││ type Regex has no field nonexist: Base.getfield(x::Regex, f::Symbol)
││└────────────────────
```
aviatesk added a commit that referenced this pull request May 30, 2023
Since the stacktrace view shown by Julia Base upon exception is more
familiar to general users, it would be better to use the same view for
showing JET's abstract stacktrace.

Previously JET tries to "infer" the textual code representation of the
call-sites of each stack-frame, but now JET does not need to do so, and
JET can show the method signature of each abstract stack-frame from
their `MethodInstance` that is already available. Therefore, this commit
may result in some performance improvement.

Note that JET still computes the textual code representation with type
annotations for each error point. We may replace that part with
TypedSyntax.jl in the future since it would be more robust and nicer.

\## Examples: `@report_call sum([])`

> Before
```julia
═════ 1 possible error found ═════
┌ @ reducedim.jl:996 Base.:(var"#sum#821")(:, pairs(NamedTuple()), #self#, a)
│┌ @ reducedim.jl:996 Base._sum(a, dims)
││┌ @ reducedim.jl:1000 Base.:(var"#_sum#823")(pairs(NamedTuple()), #self#, a, _3)
│││┌ @ reducedim.jl:1000 Base._sum(identity, a, :)
││││┌ @ reducedim.jl:1001 Base.:(var"#_sum#824")(pairs(NamedTuple()), #self#, f, a, _4)
│││││┌ @ reducedim.jl:1001 mapreduce(f, Base.add_sum, a)
││││││┌ @ reducedim.jl:357 Base.:(var"#mapreduce#814")(:, Base._InitialValue(), #self#, f, op, A)
│││││││┌ @ reducedim.jl:357 Base._mapreduce_dim(f, op, init, A, dims)
││││││││┌ @ reducedim.jl:365 Base._mapreduce(f, op, IndexStyle(A), A)
│││││││││┌ @ reduce.jl:432 Base.mapreduce_empty_iter(f, op, A, Base.IteratorEltype(A))
││││││││││┌ @ reduce.jl:380 Base.reduce_empty_iter(Base.MappingRF(f, op), itr, ItrEltype)
│││││││││││┌ @ reduce.jl:384 Base.reduce_empty(op, eltype(itr))
││││││││││││┌ @ reduce.jl:361 Base.mapreduce_empty(op.f, op.rf, T)
│││││││││││││┌ @ reduce.jl:372 Base.reduce_empty(op, T)
││││││││││││││┌ @ reduce.jl:352 Base.reduce_empty(+, T)
│││││││││││││││┌ @ reduce.jl:343 zero(T)
││││││││││││││││┌ @ missing.jl:106 Base.throw(Base.MethodError(zero, tuple(Base.Any)))
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└──────────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ sum(a::Vector{Any}) @ Base ./reducedim.jl:996
│┌ sum(a::Vector{Any}; dims::Colon, kw::Base.@kwargs{}) @ Base ./reducedim.jl:996
││┌ _sum(a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1000
│││┌ _sum(a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1000
││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1001
│││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1001
││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}) @ Base ./reducedim.jl:357
│││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}; dims::Colon, init::Base._InitialValue) @ Base ./reducedim.jl:357
││││││││┌ _mapreduce_dim(f::typeof(identity), op::typeof(Base.add_sum), ::Base._InitialValue, A::Vector{Any}, ::Colon) @ Base ./reducedim.jl:365
│││││││││┌ _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Any}) @ Base ./reduce.jl:432
││││││││││┌ mapreduce_empty_iter(f::typeof(identity), op::typeof(Base.add_sum), itr::Vector{Any}, ItrEltype::Base.HasEltype) @ Base ./reduce.jl:380
│││││││││││┌ reduce_empty_iter(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, itr::Vector{Any}, ::Base.HasEltype) @ Base ./reduce.jl:384
││││││││││││┌ reduce_empty(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, ::Type{Any}) @ Base ./reduce.jl:361
│││││││││││││┌ mapreduce_empty(::typeof(identity), op::typeof(Base.add_sum), T::Type{Any}) @ Base ./reduce.jl:372
││││││││││││││┌ reduce_empty(::typeof(Base.add_sum), ::Type{Any}) @ Base ./reduce.jl:352
│││││││││││││││┌ reduce_empty(::typeof(+), ::Type{Any}) @ Base ./reduce.jl:343
││││││││││││││││┌ zero(::Type{Any}) @ Base ./missing.jl:106
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└────────────────────
```

\## Example 2
```julia
getprop(x) = x.nonexist;

report_call((Regex,)) do r
    getprop(r)
end
```

> Before
```julia
═════ 1 possible error found ═════
┌ @ REPL[30]:2 getprop(r)
│┌ @ REPL[29]:1 x.nonexist
││┌ @ Base.jl:37 Base.getfield(x, f)
│││ type Regex has no field nonexist
││└──────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ (::var"#3#4")(r::Regex) @ Main ./REPL[12]:2
│┌ getprop(x::Regex) @ Main ./REPL[11]:1
││┌ getproperty(x::Regex, f::Symbol) @ Base ./Base.jl:37
│││ type Regex has no field nonexist: Base.getfield(x::Regex, f::Symbol)
││└────────────────────
```
aviatesk added a commit that referenced this pull request May 30, 2023
Since the stacktrace view shown by Julia Base upon exception is more
familiar to general users, it would be better to use the same view for
showing JET's abstract stacktrace.

Previously JET tries to "infer" the textual code representation of the
call-sites of each stack-frame, but now JET does not need to do so, and
JET can show the method signature of each abstract stack-frame from
their `MethodInstance` that is already available. Therefore, this commit
may result in some performance improvement.

Note that JET still computes the textual code representation with type
annotations for each error point. We may replace that part with
TypedSyntax.jl in the future since it would be more robust and nicer.

\## Examples: `@report_call sum([])`

> Before
```julia
═════ 1 possible error found ═════
┌ @ reducedim.jl:996 Base.:(var"#sum#821")(:, pairs(NamedTuple()), #self#, a)
│┌ @ reducedim.jl:996 Base._sum(a, dims)
││┌ @ reducedim.jl:1000 Base.:(var"#_sum#823")(pairs(NamedTuple()), #self#, a, _3)
│││┌ @ reducedim.jl:1000 Base._sum(identity, a, :)
││││┌ @ reducedim.jl:1001 Base.:(var"#_sum#824")(pairs(NamedTuple()), #self#, f, a, _4)
│││││┌ @ reducedim.jl:1001 mapreduce(f, Base.add_sum, a)
││││││┌ @ reducedim.jl:357 Base.:(var"#mapreduce#814")(:, Base._InitialValue(), #self#, f, op, A)
│││││││┌ @ reducedim.jl:357 Base._mapreduce_dim(f, op, init, A, dims)
││││││││┌ @ reducedim.jl:365 Base._mapreduce(f, op, IndexStyle(A), A)
│││││││││┌ @ reduce.jl:432 Base.mapreduce_empty_iter(f, op, A, Base.IteratorEltype(A))
││││││││││┌ @ reduce.jl:380 Base.reduce_empty_iter(Base.MappingRF(f, op), itr, ItrEltype)
│││││││││││┌ @ reduce.jl:384 Base.reduce_empty(op, eltype(itr))
││││││││││││┌ @ reduce.jl:361 Base.mapreduce_empty(op.f, op.rf, T)
│││││││││││││┌ @ reduce.jl:372 Base.reduce_empty(op, T)
││││││││││││││┌ @ reduce.jl:352 Base.reduce_empty(+, T)
│││││││││││││││┌ @ reduce.jl:343 zero(T)
││││││││││││││││┌ @ missing.jl:106 Base.throw(Base.MethodError(zero, tuple(Base.Any)))
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└──────────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ sum(a::Vector{Any}) @ Base ./reducedim.jl:996
│┌ sum(a::Vector{Any}; dims::Colon, kw::Base.@kwargs{}) @ Base ./reducedim.jl:996
││┌ _sum(a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1000
│││┌ _sum(a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1000
││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1001
│││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1001
││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}) @ Base ./reducedim.jl:357
│││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}; dims::Colon, init::Base._InitialValue) @ Base ./reducedim.jl:357
││││││││┌ _mapreduce_dim(f::typeof(identity), op::typeof(Base.add_sum), ::Base._InitialValue, A::Vector{Any}, ::Colon) @ Base ./reducedim.jl:365
│││││││││┌ _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Any}) @ Base ./reduce.jl:432
││││││││││┌ mapreduce_empty_iter(f::typeof(identity), op::typeof(Base.add_sum), itr::Vector{Any}, ItrEltype::Base.HasEltype) @ Base ./reduce.jl:380
│││││││││││┌ reduce_empty_iter(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, itr::Vector{Any}, ::Base.HasEltype) @ Base ./reduce.jl:384
││││││││││││┌ reduce_empty(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, ::Type{Any}) @ Base ./reduce.jl:361
│││││││││││││┌ mapreduce_empty(::typeof(identity), op::typeof(Base.add_sum), T::Type{Any}) @ Base ./reduce.jl:372
││││││││││││││┌ reduce_empty(::typeof(Base.add_sum), ::Type{Any}) @ Base ./reduce.jl:352
│││││││││││││││┌ reduce_empty(::typeof(+), ::Type{Any}) @ Base ./reduce.jl:343
││││││││││││││││┌ zero(::Type{Any}) @ Base ./missing.jl:106
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└────────────────────
```

\## Example 2
```julia
getprop(x) = x.nonexist;

report_call((Regex,)) do r
    getprop(r)
end
```

> Before
```julia
═════ 1 possible error found ═════
┌ @ REPL[30]:2 getprop(r)
│┌ @ REPL[29]:1 x.nonexist
││┌ @ Base.jl:37 Base.getfield(x, f)
│││ type Regex has no field nonexist
││└──────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ (::var"#3#4")(r::Regex) @ Main ./REPL[12]:2
│┌ getprop(x::Regex) @ Main ./REPL[11]:1
││┌ getproperty(x::Regex, f::Symbol) @ Base ./Base.jl:37
│││ type Regex has no field nonexist: Base.getfield(x::Regex, f::Symbol)
││└────────────────────
```
aviatesk added a commit that referenced this pull request May 30, 2023
Since the stacktrace view shown by Julia Base upon exception is more
familiar to general users, it would be better to use the same view for
showing JET's abstract stacktrace.

Previously JET tries to "infer" the textual code representation of the
call-sites of each stack-frame, but now JET does not need to do so, and
JET can show the method signature of each abstract stack-frame from
their `MethodInstance` that is already available. Therefore, this commit
may result in some performance improvement.

Note that JET still computes the textual code representation with type
annotations for each error point. We may replace that part with
TypedSyntax.jl in the future since it would be more robust and nicer.

\## Examples: `@report_call sum([])`

> Before
```julia
═════ 1 possible error found ═════
┌ @ reducedim.jl:996 Base.:(var"#sum#821")(:, pairs(NamedTuple()), #self#, a)
│┌ @ reducedim.jl:996 Base._sum(a, dims)
││┌ @ reducedim.jl:1000 Base.:(var"#_sum#823")(pairs(NamedTuple()), #self#, a, _3)
│││┌ @ reducedim.jl:1000 Base._sum(identity, a, :)
││││┌ @ reducedim.jl:1001 Base.:(var"#_sum#824")(pairs(NamedTuple()), #self#, f, a, _4)
│││││┌ @ reducedim.jl:1001 mapreduce(f, Base.add_sum, a)
││││││┌ @ reducedim.jl:357 Base.:(var"#mapreduce#814")(:, Base._InitialValue(), #self#, f, op, A)
│││││││┌ @ reducedim.jl:357 Base._mapreduce_dim(f, op, init, A, dims)
││││││││┌ @ reducedim.jl:365 Base._mapreduce(f, op, IndexStyle(A), A)
│││││││││┌ @ reduce.jl:432 Base.mapreduce_empty_iter(f, op, A, Base.IteratorEltype(A))
││││││││││┌ @ reduce.jl:380 Base.reduce_empty_iter(Base.MappingRF(f, op), itr, ItrEltype)
│││││││││││┌ @ reduce.jl:384 Base.reduce_empty(op, eltype(itr))
││││││││││││┌ @ reduce.jl:361 Base.mapreduce_empty(op.f, op.rf, T)
│││││││││││││┌ @ reduce.jl:372 Base.reduce_empty(op, T)
││││││││││││││┌ @ reduce.jl:352 Base.reduce_empty(+, T)
│││││││││││││││┌ @ reduce.jl:343 zero(T)
││││││││││││││││┌ @ missing.jl:106 Base.throw(Base.MethodError(zero, tuple(Base.Any)))
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└──────────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ sum(a::Vector{Any}) @ Base ./reducedim.jl:996
│┌ sum(a::Vector{Any}; dims::Colon, kw::Base.@kwargs{}) @ Base ./reducedim.jl:996
││┌ _sum(a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1000
│││┌ _sum(a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1000
││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1001
│││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1001
││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}) @ Base ./reducedim.jl:357
│││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}; dims::Colon, init::Base._InitialValue) @ Base ./reducedim.jl:357
││││││││┌ _mapreduce_dim(f::typeof(identity), op::typeof(Base.add_sum), ::Base._InitialValue, A::Vector{Any}, ::Colon) @ Base ./reducedim.jl:365
│││││││││┌ _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Any}) @ Base ./reduce.jl:432
││││││││││┌ mapreduce_empty_iter(f::typeof(identity), op::typeof(Base.add_sum), itr::Vector{Any}, ItrEltype::Base.HasEltype) @ Base ./reduce.jl:380
│││││││││││┌ reduce_empty_iter(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, itr::Vector{Any}, ::Base.HasEltype) @ Base ./reduce.jl:384
││││││││││││┌ reduce_empty(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, ::Type{Any}) @ Base ./reduce.jl:361
│││││││││││││┌ mapreduce_empty(::typeof(identity), op::typeof(Base.add_sum), T::Type{Any}) @ Base ./reduce.jl:372
││││││││││││││┌ reduce_empty(::typeof(Base.add_sum), ::Type{Any}) @ Base ./reduce.jl:352
│││││││││││││││┌ reduce_empty(::typeof(+), ::Type{Any}) @ Base ./reduce.jl:343
││││││││││││││││┌ zero(::Type{Any}) @ Base ./missing.jl:106
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└────────────────────
```

\## Example 2
```julia
getprop(x) = x.nonexist;

report_call((Regex,)) do r
    getprop(r)
end
```

> Before
```julia
═════ 1 possible error found ═════
┌ @ REPL[30]:2 getprop(r)
│┌ @ REPL[29]:1 x.nonexist
││┌ @ Base.jl:37 Base.getfield(x, f)
│││ type Regex has no field nonexist
││└──────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ (::var"#3#4")(r::Regex) @ Main ./REPL[12]:2
│┌ getprop(x::Regex) @ Main ./REPL[11]:1
││┌ getproperty(x::Regex, f::Symbol) @ Base ./Base.jl:37
│││ type Regex has no field nonexist: Base.getfield(x::Regex, f::Symbol)
││└────────────────────
```
aviatesk added a commit that referenced this pull request May 30, 2023
Since the stacktrace view shown by Julia Base upon exception is more
familiar to general users, it would be better to use the same view for
showing JET's abstract stacktrace.

Previously JET tries to "infer" the textual code representation of the
call-sites of each stack-frame, but now JET does not need to do so, and
JET can show the method signature of each abstract stack-frame from
their `MethodInstance` that is already available. Therefore, this commit
may result in some performance improvement.

Note that JET still computes the textual code representation with type
annotations for each error point. We may replace that part with
TypedSyntax.jl in the future since it would be more robust and nicer.

\## Examples: `@report_call sum([])`

> Before
```julia
═════ 1 possible error found ═════
┌ @ reducedim.jl:996 Base.:(var"#sum#821")(:, pairs(NamedTuple()), #self#, a)
│┌ @ reducedim.jl:996 Base._sum(a, dims)
││┌ @ reducedim.jl:1000 Base.:(var"#_sum#823")(pairs(NamedTuple()), #self#, a, _3)
│││┌ @ reducedim.jl:1000 Base._sum(identity, a, :)
││││┌ @ reducedim.jl:1001 Base.:(var"#_sum#824")(pairs(NamedTuple()), #self#, f, a, _4)
│││││┌ @ reducedim.jl:1001 mapreduce(f, Base.add_sum, a)
││││││┌ @ reducedim.jl:357 Base.:(var"#mapreduce#814")(:, Base._InitialValue(), #self#, f, op, A)
│││││││┌ @ reducedim.jl:357 Base._mapreduce_dim(f, op, init, A, dims)
││││││││┌ @ reducedim.jl:365 Base._mapreduce(f, op, IndexStyle(A), A)
│││││││││┌ @ reduce.jl:432 Base.mapreduce_empty_iter(f, op, A, Base.IteratorEltype(A))
││││││││││┌ @ reduce.jl:380 Base.reduce_empty_iter(Base.MappingRF(f, op), itr, ItrEltype)
│││││││││││┌ @ reduce.jl:384 Base.reduce_empty(op, eltype(itr))
││││││││││││┌ @ reduce.jl:361 Base.mapreduce_empty(op.f, op.rf, T)
│││││││││││││┌ @ reduce.jl:372 Base.reduce_empty(op, T)
││││││││││││││┌ @ reduce.jl:352 Base.reduce_empty(+, T)
│││││││││││││││┌ @ reduce.jl:343 zero(T)
││││││││││││││││┌ @ missing.jl:106 Base.throw(Base.MethodError(zero, tuple(Base.Any)))
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└──────────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ sum(a::Vector{Any}) @ Base ./reducedim.jl:996
│┌ sum(a::Vector{Any}; dims::Colon, kw::Base.@kwargs{}) @ Base ./reducedim.jl:996
││┌ _sum(a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1000
│││┌ _sum(a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1000
││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1001
│││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1001
││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}) @ Base ./reducedim.jl:357
│││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}; dims::Colon, init::Base._InitialValue) @ Base ./reducedim.jl:357
││││││││┌ _mapreduce_dim(f::typeof(identity), op::typeof(Base.add_sum), ::Base._InitialValue, A::Vector{Any}, ::Colon) @ Base ./reducedim.jl:365
│││││││││┌ _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Any}) @ Base ./reduce.jl:432
││││││││││┌ mapreduce_empty_iter(f::typeof(identity), op::typeof(Base.add_sum), itr::Vector{Any}, ItrEltype::Base.HasEltype) @ Base ./reduce.jl:380
│││││││││││┌ reduce_empty_iter(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, itr::Vector{Any}, ::Base.HasEltype) @ Base ./reduce.jl:384
││││││││││││┌ reduce_empty(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, ::Type{Any}) @ Base ./reduce.jl:361
│││││││││││││┌ mapreduce_empty(::typeof(identity), op::typeof(Base.add_sum), T::Type{Any}) @ Base ./reduce.jl:372
││││││││││││││┌ reduce_empty(::typeof(Base.add_sum), ::Type{Any}) @ Base ./reduce.jl:352
│││││││││││││││┌ reduce_empty(::typeof(+), ::Type{Any}) @ Base ./reduce.jl:343
││││││││││││││││┌ zero(::Type{Any}) @ Base ./missing.jl:106
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└────────────────────
```

\## Example 2
```julia
getprop(x) = x.nonexist;

report_call((Regex,)) do r
    getprop(r)
end
```

> Before
```julia
═════ 1 possible error found ═════
┌ @ REPL[30]:2 getprop(r)
│┌ @ REPL[29]:1 x.nonexist
││┌ @ Base.jl:37 Base.getfield(x, f)
│││ type Regex has no field nonexist
││└──────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ (::var"#3#4")(r::Regex) @ Main ./REPL[12]:2
│┌ getprop(x::Regex) @ Main ./REPL[11]:1
││┌ getproperty(x::Regex, f::Symbol) @ Base ./Base.jl:37
│││ type Regex has no field nonexist: Base.getfield(x::Regex, f::Symbol)
││└────────────────────
```
aviatesk added a commit that referenced this pull request May 30, 2023
Since the stacktrace view shown by Julia Base upon exception is more
familiar to general users, it would be better to use the same view for
showing JET's abstract stacktrace.

Previously JET tries to "infer" the textual code representation of the
call-sites of each stack-frame, but now JET does not need to do so, and
JET can show the method signature of each abstract stack-frame from
their `MethodInstance` that is already available. Therefore, this commit
may result in some performance improvement.

Note that JET still computes the textual code representation with type
annotations for each error point. We may replace that part with
TypedSyntax.jl in the future since it would be more robust and nicer.

\## Examples: `@report_call sum([])`

> Before
```julia
═════ 1 possible error found ═════
┌ @ reducedim.jl:996 Base.:(var"#sum#821")(:, pairs(NamedTuple()), #self#, a)
│┌ @ reducedim.jl:996 Base._sum(a, dims)
││┌ @ reducedim.jl:1000 Base.:(var"#_sum#823")(pairs(NamedTuple()), #self#, a, _3)
│││┌ @ reducedim.jl:1000 Base._sum(identity, a, :)
││││┌ @ reducedim.jl:1001 Base.:(var"#_sum#824")(pairs(NamedTuple()), #self#, f, a, _4)
│││││┌ @ reducedim.jl:1001 mapreduce(f, Base.add_sum, a)
││││││┌ @ reducedim.jl:357 Base.:(var"#mapreduce#814")(:, Base._InitialValue(), #self#, f, op, A)
│││││││┌ @ reducedim.jl:357 Base._mapreduce_dim(f, op, init, A, dims)
││││││││┌ @ reducedim.jl:365 Base._mapreduce(f, op, IndexStyle(A), A)
│││││││││┌ @ reduce.jl:432 Base.mapreduce_empty_iter(f, op, A, Base.IteratorEltype(A))
││││││││││┌ @ reduce.jl:380 Base.reduce_empty_iter(Base.MappingRF(f, op), itr, ItrEltype)
│││││││││││┌ @ reduce.jl:384 Base.reduce_empty(op, eltype(itr))
││││││││││││┌ @ reduce.jl:361 Base.mapreduce_empty(op.f, op.rf, T)
│││││││││││││┌ @ reduce.jl:372 Base.reduce_empty(op, T)
││││││││││││││┌ @ reduce.jl:352 Base.reduce_empty(+, T)
│││││││││││││││┌ @ reduce.jl:343 zero(T)
││││││││││││││││┌ @ missing.jl:106 Base.throw(Base.MethodError(zero, tuple(Base.Any)))
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└──────────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ sum(a::Vector{Any}) @ Base ./reducedim.jl:996
│┌ sum(a::Vector{Any}; dims::Colon, kw::Base.@kwargs{}) @ Base ./reducedim.jl:996
││┌ _sum(a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1000
│││┌ _sum(a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1000
││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1001
│││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1001
││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}) @ Base ./reducedim.jl:357
│││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}; dims::Colon, init::Base._InitialValue) @ Base ./reducedim.jl:357
││││││││┌ _mapreduce_dim(f::typeof(identity), op::typeof(Base.add_sum), ::Base._InitialValue, A::Vector{Any}, ::Colon) @ Base ./reducedim.jl:365
│││││││││┌ _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Any}) @ Base ./reduce.jl:432
││││││││││┌ mapreduce_empty_iter(f::typeof(identity), op::typeof(Base.add_sum), itr::Vector{Any}, ItrEltype::Base.HasEltype) @ Base ./reduce.jl:380
│││││││││││┌ reduce_empty_iter(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, itr::Vector{Any}, ::Base.HasEltype) @ Base ./reduce.jl:384
││││││││││││┌ reduce_empty(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, ::Type{Any}) @ Base ./reduce.jl:361
│││││││││││││┌ mapreduce_empty(::typeof(identity), op::typeof(Base.add_sum), T::Type{Any}) @ Base ./reduce.jl:372
││││││││││││││┌ reduce_empty(::typeof(Base.add_sum), ::Type{Any}) @ Base ./reduce.jl:352
│││││││││││││││┌ reduce_empty(::typeof(+), ::Type{Any}) @ Base ./reduce.jl:343
││││││││││││││││┌ zero(::Type{Any}) @ Base ./missing.jl:106
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└────────────────────
```

\## Example 2
```julia
getprop(x) = x.nonexist;

report_call((Regex,)) do r
    getprop(r)
end
```

> Before
```julia
═════ 1 possible error found ═════
┌ @ REPL[30]:2 getprop(r)
│┌ @ REPL[29]:1 x.nonexist
││┌ @ Base.jl:37 Base.getfield(x, f)
│││ type Regex has no field nonexist
││└──────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ (::var"#3#4")(r::Regex) @ Main ./REPL[12]:2
│┌ getprop(x::Regex) @ Main ./REPL[11]:1
││┌ getproperty(x::Regex, f::Symbol) @ Base ./Base.jl:37
│││ type Regex has no field nonexist: Base.getfield(x::Regex, f::Symbol)
││└────────────────────
```
aviatesk added a commit that referenced this pull request May 30, 2023
* ui: use stacktrace-like view for showing reports

Since the stacktrace view shown by Julia Base upon exception is more
familiar to general users, it would be better to use the same view for
showing JET's abstract stacktrace.

Previously JET tries to "infer" the textual code representation of the
call-sites of each stack-frame, but now JET does not need to do so, and
JET can show the method signature of each abstract stack-frame from
their `MethodInstance` that is already available. Therefore, this commit
may result in some performance improvement.

Note that JET still computes the textual code representation with type
annotations for each error point. We may replace that part with
TypedSyntax.jl in the future since it would be more robust and nicer.

\## Examples: `@report_call sum([])`

> Before
```julia
═════ 1 possible error found ═════
┌ @ reducedim.jl:996 Base.:(var"#sum#821")(:, pairs(NamedTuple()), #self#, a)
│┌ @ reducedim.jl:996 Base._sum(a, dims)
││┌ @ reducedim.jl:1000 Base.:(var"#_sum#823")(pairs(NamedTuple()), #self#, a, _3)
│││┌ @ reducedim.jl:1000 Base._sum(identity, a, :)
││││┌ @ reducedim.jl:1001 Base.:(var"#_sum#824")(pairs(NamedTuple()), #self#, f, a, _4)
│││││┌ @ reducedim.jl:1001 mapreduce(f, Base.add_sum, a)
││││││┌ @ reducedim.jl:357 Base.:(var"#mapreduce#814")(:, Base._InitialValue(), #self#, f, op, A)
│││││││┌ @ reducedim.jl:357 Base._mapreduce_dim(f, op, init, A, dims)
││││││││┌ @ reducedim.jl:365 Base._mapreduce(f, op, IndexStyle(A), A)
│││││││││┌ @ reduce.jl:432 Base.mapreduce_empty_iter(f, op, A, Base.IteratorEltype(A))
││││││││││┌ @ reduce.jl:380 Base.reduce_empty_iter(Base.MappingRF(f, op), itr, ItrEltype)
│││││││││││┌ @ reduce.jl:384 Base.reduce_empty(op, eltype(itr))
││││││││││││┌ @ reduce.jl:361 Base.mapreduce_empty(op.f, op.rf, T)
│││││││││││││┌ @ reduce.jl:372 Base.reduce_empty(op, T)
││││││││││││││┌ @ reduce.jl:352 Base.reduce_empty(+, T)
│││││││││││││││┌ @ reduce.jl:343 zero(T)
││││││││││││││││┌ @ missing.jl:106 Base.throw(Base.MethodError(zero, tuple(Base.Any)))
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└──────────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ sum(a::Vector{Any}) @ Base ./reducedim.jl:996
│┌ sum(a::Vector{Any}; dims::Colon, kw::Base.@kwargs{}) @ Base ./reducedim.jl:996
││┌ _sum(a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1000
│││┌ _sum(a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1000
││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon) @ Base ./reducedim.jl:1001
│││││┌ _sum(f::typeof(identity), a::Vector{Any}, ::Colon; kw::Base.@kwargs{}) @ Base ./reducedim.jl:1001
││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}) @ Base ./reducedim.jl:357
│││││││┌ mapreduce(f::typeof(identity), op::typeof(Base.add_sum), A::Vector{Any}; dims::Colon, init::Base._InitialValue) @ Base ./reducedim.jl:357
││││││││┌ _mapreduce_dim(f::typeof(identity), op::typeof(Base.add_sum), ::Base._InitialValue, A::Vector{Any}, ::Colon) @ Base ./reducedim.jl:365
│││││││││┌ _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Any}) @ Base ./reduce.jl:432
││││││││││┌ mapreduce_empty_iter(f::typeof(identity), op::typeof(Base.add_sum), itr::Vector{Any}, ItrEltype::Base.HasEltype) @ Base ./reduce.jl:380
│││││││││││┌ reduce_empty_iter(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, itr::Vector{Any}, ::Base.HasEltype) @ Base ./reduce.jl:384
││││││││││││┌ reduce_empty(op::Base.MappingRF{typeof(identity), typeof(Base.add_sum)}, ::Type{Any}) @ Base ./reduce.jl:361
│││││││││││││┌ mapreduce_empty(::typeof(identity), op::typeof(Base.add_sum), T::Type{Any}) @ Base ./reduce.jl:372
││││││││││││││┌ reduce_empty(::typeof(Base.add_sum), ::Type{Any}) @ Base ./reduce.jl:352
│││││││││││││││┌ reduce_empty(::typeof(+), ::Type{Any}) @ Base ./reduce.jl:343
││││││││││││││││┌ zero(::Type{Any}) @ Base ./missing.jl:106
│││││││││││││││││ MethodError: no method matching zero(::Type{Any}): Base.throw(Base.MethodError(zero, tuple(Base.Any)::Tuple{DataType})::MethodError)
││││││││││││││││└────────────────────
```

\## Example 2
```julia
getprop(x) = x.nonexist;

report_call((Regex,)) do r
    getprop(r)
end
```

> Before
```julia
═════ 1 possible error found ═════
┌ @ REPL[30]:2 getprop(r)
│┌ @ REPL[29]:1 x.nonexist
││┌ @ Base.jl:37 Base.getfield(x, f)
│││ type Regex has no field nonexist
││└──────────────
```
> After
```julia
═════ 1 possible error found ═════
┌ (::var"#3#4")(r::Regex) @ Main ./REPL[12]:2
│┌ getprop(x::Regex) @ Main ./REPL[11]:1
││┌ getproperty(x::Regex, f::Symbol) @ Base ./Base.jl:37
│││ type Regex has no field nonexist: Base.getfield(x::Regex, f::Symbol)
││└────────────────────
```

* remove `annotate_types` configuration

* update example abstract stacktraces
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.

1 participant