Calling a macro in a function with `eval` fails on nightly

Hello,

I maintain the package JSONLines.jl package which has some syntactic sugar to define a StructType to read only specific columns. This fails on the Julia nightly with the following error:

readcols: Error During Test at /Users/runner/work/JSONLines.jl/JSONLines.jl/test/runtests.jl:55
  Got exception outside of a @test
  MethodError: no method matching JSONLines.var"##jsonlwebsite.jsonl#140"(::String)
  The type `JSONLines.var"##jsonlwebsite.jsonl#140"` exists, but no method is defined for this combination of argument types when trying to construct it.
  Closest candidates are:
    JSONLines.var"##jsonlwebsite.jsonl#140"() (method too new to be called from this world context.)
     @ JSONLines ~/work/JSONLines.jl/JSONLines.jl/src/sugar.jl:13
Full Stacktrace
readcols: Error During Test at /Users/runner/work/JSONLines.jl/JSONLines.jl/test/runtests.jl:55
  Got exception outside of a @test
  MethodError: no method matching JSONLines.var"##jsonlwebsite.jsonl#140"(::String)
  The type `JSONLines.var"##jsonlwebsite.jsonl#140"` exists, but no method is defined for this combination of argument types when trying to construct it.
  Closest candidates are:
    JSONLines.var"##jsonlwebsite.jsonl#140"() (method too new to be called from this world context.)
     @ JSONLines ~/work/JSONLines.jl/JSONLines.jl/src/sugar.jl:13
  Stacktrace:
    [1] construct
      @ ~/.julia/packages/StructTypes/PaLwj/src/StructTypes.jl:915 [inlined]
    [2] read(::StructTypes.UnorderedStruct, buf::SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}, pos::Int64, len::Int64, b::UInt8, ::Type{JSONLines.var"##jsonlwebsite.jsonl#140"}; ignore_extra_fields::Bool, kw::@Kwargs{})
      @ JSON3 ~/.julia/packages/JSON3/rT1w2/src/structs.jl:652
    [3] read(::StructTypes.UnorderedStruct, buf::SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}, pos::Int64, len::Int64, b::UInt8, ::Type{JSONLines.var"##jsonlwebsite.jsonl#140"})
      @ JSON3 ~/.julia/packages/JSON3/rT1w2/src/structs.jl:568
    [4] parse(str::JSON3.VectorString{SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}}, ::Type{JSONLines.var"##jsonlwebsite.jsonl#140"}; jsonlines::Bool, kw::@Kwargs{})
      @ JSON3 ~/.julia/packages/JSON3/rT1w2/src/structs.jl:40
    [5] kwcall(::@NamedTuple{jsonlines::Bool}, ::typeof(JSON3.parse), str::JSON3.VectorString{SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}}, ::Type{JSONLines.var"##jsonlwebsite.jsonl#140"})
      @ JSON3 ~/.julia/packages/JSON3/rT1w2/src/structs.jl:32
    [6] read(str::JSON3.VectorString{SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}}, ::Type{JSONLines.var"##jsonlwebsite.jsonl#140"}; jsonlines::Bool, kw::@Kwargs{})
      @ JSON3 ~/.julia/packages/JSON3/rT1w2/src/structs.jl:46
    [7] read(str::JSON3.VectorString{SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}}, ::Type{JSONLines.var"##jsonlwebsite.jsonl#140"})
      @ JSON3 ~/.julia/packages/JSON3/rT1w2/src/structs.jl:45
    [8] read(bytes::SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}, ::Type{JSONLines.var"##jsonlwebsite.jsonl#140"}; kw::@Kwargs{})
      @ JSON3 ~/.julia/packages/JSON3/rT1w2/src/structs.jl:14
    [9] read(bytes::SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}, ::Type{JSONLines.var"##jsonlwebsite.jsonl#140"})
      @ JSON3 ~/.julia/packages/JSON3/rT1w2/src/structs.jl:14
   [10] parserow(row::SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}, structtype::DataType)
      @ JSONLines ~/work/JSONLines.jl/JSONLines.jl/src/utils.jl:107
   [11] _materialize(buf::Vector{UInt8}, rows::Vector{Int64}, indices::UnitRange{Int64}, names::Tuple{Symbol}, structtype::Type)
      @ JSONLines ~/work/JSONLines.jl/JSONLines.jl/src/utils.jl:165
   [12] materialize(lines::LineIndex{JSONLines.var"##jsonlwebsite.jsonl#140"}, rows::UnitRange{Int64})
      @ JSONLines ~/work/JSONLines.jl/JSONLines.jl/src/LineIndex.jl:91
   [13] materialize
      @ ~/work/JSONLines.jl/JSONLines.jl/src/LineIndex.jl:88 [inlined]
   [14] |>(x::LineIndex{JSONLines.var"##jsonlwebsite.jsonl#140"}, f::typeof(materialize))
      @ Base ./operators.jl:973
   [15] top-level scope
      @ ~/work/JSONLines.jl/JSONLines.jl/test/runtests.jl:56
   [16] macro expansion
      @ ~/hostedtoolcache/julia/nightly/aarch64/share/julia/stdlib/v1.13/Test/src/Test.jl:1952 [inlined]
   [17] macro expansion
      @ ~/work/JSONLines.jl/JSONLines.jl/test/runtests.jl:56 [inlined]
   [18] include(mapexpr::Function, mod::Module, _path::String)
      @ Base ./Base.jl:309
   [19] top-level scope
      @ none:6
   [20] eval(m::Module, e::Any)
      @ Core ./boot.jl:489
   [21] exec_options(opts::Base.JLOptions)
      @ Base ./client.jl:296
   [22] _start()
      @ Base ./client.jl:563

Is there an easy fix using Base.invokelatest?

This is the failing code?

"""
@MStructType name fieldnames...

This macro gives a convenient syntax for declaring mutable `StructType`s for reading specific variables from a JSONLines file. Also defines `row[:col]` access for rows of the resulting type.

* `name`: Name of the `StructType`
* `fieldnames...`: Names of the variables to be read (must be the same as in the file)
"""
macro MStructType(name, fieldnames...)
quote
    mutable struct $name
        $(fieldnames...)
        $(esc(name))() = new(fill(missing, $(esc(length(fieldnames))))...)
    end
    StructTypes.StructType(::Type{$(esc(name))}) = StructTypes.Mutable()
    StructTypes.names(::Type{$(esc(name))}) = tuple()
    Base.getindex(x::$(esc(name)), col::Symbol) = getproperty(x, col)
end
end

function MStructType(name, vars...)
eval(:(@MStructType $name $(vars...)))
end


macro readcols(path::String, nworkers, cols...)
    name = gensym(basename(path))
    MStructType(name, cols...)
    quote
       LineIndex($path, structtype = $name, nworkers = $nworkers)
    end
end

"""
    readcols(path::String, cols...; nworkers = 1) => LineIndex

* `path`: Path to JSONLines file
* `cols...`: Columnnames to be selected
* Keyword Argument:
    * `nworkers=1`: Number of threads to use for operations on the resulting LineIndex
"""
function readcols(path::String, cols...; nworkers = 1)
    eval(:(@readcols $path $nworkers $(cols...)))
end

Edit:
it wasn’t the obvious: JSONLines.jl/src/sugar.jl at bf59d43ce0570fb74c40c668fa69093a8c34cc03 · dwinkler1/JSONLines.jl · GitHub

I don’t have answers to your questions, but I do have suggestions for how to make life of other people who may have the same issue easier.

Can you please copy here the full error message? CI logs are ephemeral (will disappear in a few months) and non-searchable on the Internet, which makes finding the same issue later impossible. Also, that would make your request for help self-sufficient, so that people motivate to help you don’t have to go and read some other pages.

That’s a non-permanent link, you want to link JSONLines.jl/src/sugar.jl at bf59d43ce0570fb74c40c668fa69093a8c34cc03 · dwinkler1/JSONLines.jl · GitHub instead (you can obtain this link by either pressing Y in your browser, the URL will be updated, or by clicking the three dots on the top-right corner of the page and then click on “Copy permalink”)

1 Like

Thank you for your suggestions! I’ve updated the post accordingly.

1 Like