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

Synonymous macro and method lookup broken when called with different/implicit scope #4722

Closed
straight-shoota opened this issue Jul 18, 2017 · 3 comments

Comments

@straight-shoota
Copy link
Member

Seems like I get to find all the bugs related to macro lookup these days...
This might be related to #4639 but it is a bit different and already present in versions prior to 0.23.0.

Given the following types:

module DSL
  macro foo
    {% p "macro" %}
  end
  def foo
    p "method"
  end
end

class Base
  include DSL
  
  def call_foo
    foo
  end
  
  def call_foo_from_block
    true.tap do |_|
      foo
    end
  end
end

This works as expected: https://carc.in/#/r/2dqy

b = Base.new
b.foo                         # => method
Base.new.foo                  # => method

But suddenly Base.new.foo refers to the macro: https://carc.in/#/r/2dr0

Base.new.foo                  # => macro
Base.new.call_foo             # => method

https://carc.in/#/r/2dqx

b = Base.new
b.foo                         # => macro
Base.new.foo                  # => method
Base.new.call_foo             # => method

And it keeps going...
https://carc.in/#/r/2dr1

Base.new.foo                  # => macro
Base.new.call_foo             # => macro
Base.new.call_foo_from_block  # => method

https://carc.in/#/r/2dqw

b = Base.new                  
b.foo                         # => macro
Base.new.foo                  # => macro
Base.new.call_foo             # => method
Base.new.call_foo_from_block  # => method

None of these calls should invoke the macro, all should point to the instance method in the implicit scope.
If the calls inside call_foo and call_foo_with_block are explicitly scoped, they are correctly mapped to the instance method.

@bew
Copy link
Contributor

bew commented Jul 18, 2017

I think that you're mixing compile-time printing and runtime printing, the macro ps will always be first as they happen during compilation.

Using the following snippet, I get what I expect:

module DSL
  macro foo
    "macro"
  end
  def foo
    "method"
  end
end

class Base
  include DSL
  
  def call_foo
    foo
  end
  
  def call_foo_from_block
    true.try do
      foo
    end
  end
  
  def call_self_foo
    self.foo
  end
end

b = Base.new
pp b.foo # => "method"
pp Base.new.foo # => "method"
pp Base.new.call_foo # => "macro"
pp Base.new.call_self_foo # => "method"
pp Base.new.call_foo_from_block # => "macro"

https://carc.in/#/r/2ds9

@straight-shoota
Copy link
Member Author

Dough, your're right. Because of compile and runtime output the order is changed. Sorry that I missed that.

But the modified code from your snippet does not behave as expected: the calls to call_foo and call_foo_from_block should both invoke the instance method, not the macro. There should be no difference between calling foo (with implicit scope self - which wrongly points to the macro) and self.foo (which correctly points to the method in explicit scope).
This has already been discussed in #236 but was not yet solved. I think I'm gonna open a new issue for this without the noise.

@bew
Copy link
Contributor

bew commented Jul 18, 2017

@straight-shoota In #236, what I understand about the direction taken is that it first lookup a macro then a method, then go up one parent level, and try again to find a macro, then a method, etc...
Here, foo the macro and foo the method are on the same level, so without explicitly calling the method, the macro is always matched first with the rule I gave above.

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

No branches or pull requests

2 participants