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

Fix the scope to look-up the constant as the receiver type of the macro #5354

Merged

Conversation

makenowjust
Copy link
Contributor

Fixed #5343. It is another solution than #5349. I believe this PR is better than #5349.

Currently the constant in expansion inside macro is resolved by caller-scope, for example:

class Foo
  macro foo
    {{Baz}}
  end
end

class Bar
  class Baz
  end

  def self.foo
    Foo.foo
  end
end

p Bar.foo # => Bar::Baz

It is unexpected because the constant inside method is of course resolved by the receiver type of the method. And so, the second example in #5343 is caused.

This PR fixed scope to look-up the constant as the receiver type of the macro.

@RX14
Copy link
Contributor

RX14 commented Dec 6, 2017

@makenowjust say in that example the macro did want to access Baz, how would that be done?

@makenowjust
Copy link
Contributor Author

@RX14 Using Bar::Baz is the right way.

@makenowjust
Copy link
Contributor Author

It does not make a sense that this example works only if Foo.foo is called from the scope having Bar.

class Foo
  macro foo
    {{Baz}}
  end

  class Baz
  end
end

class Bar
  class Baz
  end

  def self.foo
    Foo.foo
  end
end

class FooBar
  def self.foo
    Foo.foo
  end
end

p Bar.foo # => Bar::Baz
p FooBar.foo # compilation error: undefined constant 'Baz'

Isn't it?

@RX14
Copy link
Contributor

RX14 commented Dec 6, 2017

@makenowjust but now you have to pass in the outer scope somehow? Macros can reference local variables and local methods, why not local types too.

@makenowjust
Copy link
Contributor Author

This example works. What is problem?

class Foo
  macro foo(x)
    {{x}}
  end

  macro bar
    Baz
  end
end

class Bar
  class Baz
  end

  def self.foo
    Foo.foo Baz
  end

  def self.bar
    Foo.bar
  end
end

p Bar.foo # => Bar::Baz
p Bar.bar # => Bar::Baz

This PR fixes the semantic in only macro expansion inside macro.

@RX14
Copy link
Contributor

RX14 commented Dec 6, 2017

@makenowjust ah yes never mind me I was just confused.

@bew
Copy link
Contributor

bew commented Dec 6, 2017

I think what @RX14 fears is that we may not be able to access a 'local' type from the macro system, as {% SomeType %}

module IncludeMe
  macro included
    STORAGE = [] of _ # Create a 'local' Type in the caller's (includer) scope
  end

  macro add(node)
    {% STORAGE << node %} # Access a 'local' type in the caller's scope, from the macro system
  end
end

class Foo
  include IncludeMe

  # Add some stuff from macros to a 'local' type
  add a + b
  add :bla
end

But it seems to still work, so 👍

@bew
Copy link
Contributor

bew commented Jul 23, 2018

Can this go forward?

@asterite
Copy link
Member

This fix is correct 👍

@RX14
Copy link
Contributor

RX14 commented Jul 23, 2018

needs a rebase, sorry for the delay merging

@makenowjust
Copy link
Contributor Author

I merged master into this on GitHub Web UI. Please do squash merge.

Copy link
Member

@sdogruyol sdogruyol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot @makenowjust 🙏

@sdogruyol sdogruyol merged commit 2aea034 into crystal-lang:master Jul 23, 2018
@sdogruyol sdogruyol added this to the Next milestone Jul 23, 2018
@makenowjust makenowjust deleted the fix/crystal/lookup-scope-in-macro branch July 23, 2018 19:27
@bew bew mentioned this pull request Jul 23, 2018
@RX14 RX14 modified the milestones: Next, 0.26.0 Jul 30, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bytes[1, 2] is broken when used in a class
6 participants