JuliaDebug / JuliaDebug/Cthulhu.jl

TypedSyntax: a macro call inside an expression leaves the enclosing calls unmapped

Open
#712 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Julia
Stars
709
Forks
46
Avg merge
1d 13h
Merged PRs (30d)
2

Description

When a macro call appears inside an expression, the statements for the enclosing calls on that line — the ones the user wrote, not the macro's expansion — get no source node. Shape from ApproxFunBase's _default_Fun:

struct Coefs; coefficients::Vector{Float64}; end
function macroline(cf::Coefs, bs::Int)
    m = maximum(abs, cf.coefficients)
    maximum(abs, @view cf.coefficients[bs:end]) < 10m
end

Repro (TypedSyntax 1.5.4, Julia 1.13.0):

using TypedSyntax, JuliaSyntax
using JuliaSyntax: kind, sourcetext
macroline(Coefs(rand(3)), 1)
mi = only(Base.method_instances(macroline, (Coefs, Int), Base.get_world_counter()))
src, rt = TypedSyntax.code_typed1_tsn(mi)
tsn, mappings = TypedSyntax.tsn_and_mappings(mi, src, rt)
for (i, nodes) in enumerate(mappings)
    st = src.code[i]
    (st isa Core.ReturnNode || st isa Core.GotoIfNot || st isa Core.GotoNode) && continue
    println(i, "  ", st, " -> ", isempty(nodes) ? "(nothing)" : [string(kind(n), " `", sourcetext(n), "`") for n in nodes])
end

Output:

  1  Main.maximum                                 -> Identifier `maximum`
  2  Main.abs                                     -> Identifier `abs`
  3  Base.getproperty(_2, :coefficients)          -> . `cf.coefficients`
  4  _5 = (%1)(%2, %3)                            -> call `maximum(abs, cf.coefficients)`
  5  Main.:<                                      -> Identifier `<`
  6  Main.maximum                                 -> Identifier `maximum`
  7  Main.abs                                     -> Identifier `abs`
  8  _4 = Base.getproperty(_2, :coefficients)     -> . `cf.coefficients`
  9  _4                                           -> (nothing)
 10  Main.:(:)                                    -> (nothing)
 11  _4                                           -> (nothing)
 12  (lastindex)(%11)                             -> (nothing)
 13  (%10)(_3, %12)                               -> (nothing)
 14  (view)(%9, %13)                              -> (nothing)
 15  (%6)(%7, %14)                                -> (nothing)
 16  Main.:*                                      -> (nothing)
 17  _5                                           -> (nothing)
 18  (%16)(10, %17)                               -> (nothing)
 19  (%5)(%15, %18)                               -> (nothing)

The first line maps completely. On the second line only the leaf identifiers and cf.coefficients map; the @view expansion (lastindex, :, view) is understandably unmapped, but so are the calls around it that the source spells verbatim — maximum(abs, ...), <, 10m — so the whole expression comes back untyped and none of those callsites can be located in the source.

In the original (maximum(abs, @view cf.coefficients[bs:end]) < 10tol*maxabsc in ApproxFunBase, seen through Cthulhu) the outcome was slightly different: the maximum statement was attributed to the macrocall node itself rather than dropped, so the maximum callsite was located at the @view node. I could not reduce that variant to a standalone repro; the drop above is the reproducible form of the same thing.

Related: #710 (a macro call in argument position sends the enclosing call to the assignment target).


🤖 Filed using Claude Code. The reproduction was run locally on the stated versions and the output is quoted verbatim.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the standalone reproduction with TypedSyntax 1.5.4 and Julia 1.13.0, starting at TypedSyntax.tsn_and_mappings and the printed mappings. Compare the first and second expression and related issue #710; done means source-spelled enclosing calls such as maximum, <, and 10m receive source nodes while macro-expansion nodes may remain unmapped.

Written by the indexing model from the issue text.

Assessment

Tech stack
julia
Domain
developer-experience, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.