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

previous_def seems to lose information regarding a double-splat when used in a macro. #13176

Open
icy-arctic-fox opened this issue Mar 10, 2023 · 1 comment

Comments

@icy-arctic-fox
Copy link
Contributor

Bug Report

I'm attempting to redefine a method and wrap its previous implementation. A macro reconstructs the signature and uses previous_def to call the original implementation. This doesn't seem to work correctly when combined with a double-splat parameter. The compiler gives an error similar to:

Error: wrong number of arguments for 'Foo#test' (given 2, expected 0..1)

Reduced code:

class Foo
  macro gen_previous
    previous_def
  end

  def test(name = nil, **kwargs)
    p! name, kwargs
  end

  def test(name = nil, **kwargs)
    gen_previous
  end
end

Foo.new.test 10, blah: "Fred"

Crystal 1.7.3

@HertzDevil
Copy link
Contributor

Because the call contains named arguments, by the same the normalizer sees the second Foo#test, it is actually looking at something like this:

def test:blah(name : Int32, blah __temp_1 : String)
  kwargs = {blah: __temp_1}
  gen_previous # becomes previous_def(name, __temp_1)
end

Normally this doesn't happen and the normalizer acts first, however macro expansion reverses this order. Thus, the named arguments get turned into positional ones, and adding a single splat will give incorrect results:

module Foo
  macro gen_previous
    previous_def
  end

  def self.foo(*args, **opts)
    {args, opts}
  end

  def self.foo(*args, **opts)
    gen_previous
  end
end

Foo.foo 1, 2, 3, a: 4, b: 5 # => {{1, 2, 3, 4, 5}, {}}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants