diff --git a/src/differentials.jl b/src/differentials.jl index 1f048f6d6..ca1d91d8a 100644 --- a/src/differentials.jl +++ b/src/differentials.jl @@ -212,8 +212,17 @@ struct Thunk{F} <: AbstractThunk f::F end + +""" + @thunk expr + +Define a [`Thunk`](@ref) wrapping the `expr`, to lazily defer its evaluation. +""" macro thunk(body) - return :(Thunk(() -> $(esc(body)))) + # Basically `:(Thunk(() -> $(esc(body))))` but use the location where it is defined. + # so we get useful stack traces if it errors. + func = Expr(:->, Expr(:tuple), Expr(:block, __source__, body)) + return :(Thunk($(esc(func)))) end # have to define this here after `@thunk` and `Thunk` is defined diff --git a/test/differentials.jl b/test/differentials.jl index 570b09d88..51d80c596 100644 --- a/test/differentials.jl +++ b/test/differentials.jl @@ -66,6 +66,21 @@ @test (@thunk(3))() == 3 @test (@thunk(@thunk(3)))() isa Thunk end + + @testset "erroring thunks should include the source in the backtrack" begin + expected_line = (@__LINE__) + 2 # for testing it is at right palce + try + x = @thunk(error()) + extern(x) + catch err + err isa ErrorException || rethrow() + st = stacktrace(catch_backtrace()) + # Should be 2nd last line, as last line will be the `error` function + stackframe = st[2] + @test stackframe.line == expected_line + @test stackframe.file == Symbol(@__FILE__) + end + end end @testset "No ambiguities in $f" for f in (+, *)