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

Top-Level verbatim macro behaves weirdly #13744

Closed
BlobCodes opened this issue Aug 12, 2023 · 1 comment
Closed

Top-Level verbatim macro behaves weirdly #13744

BlobCodes opened this issue Aug 12, 2023 · 1 comment

Comments

@BlobCodes
Copy link
Contributor

Bug Report

The following code raises a compile-time error (even with --prelude=empty):

def foo
end

{% verbatim do %}
  foo
{% end %}

This is the exception:

Crystal::Call#scope cannot be nil (NilAssertionError)
  from /crystal/src/compiler/crystal/program.cr:463:5 in 'lookup_macro'
  from /crystal/src/compiler/crystal/semantic/semantic_visitor.cr:301:19 in 'expand_macro:raise_on_missing_const'
  from /crystal/src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'
  from /crystal/src/compiler/crystal/semantic/ast.cr:649:5 in 'expand_inline_macro'
[...]
Error: you've found a bug in the Crystal compiler. [...]

This only happens when there is no callee (A.foo() or 10.to_s do not raise).
This happens regardless of arguments to the method, other macro code inside the verbatim, other crystal code inside the macro, etc.
This only happens using verbatim. Using {% begin %}\{% if true %}\{% end %}{% end %} does not cause an error.
However, wrapping the verbatim code inside another macro works:

def foo
end

{% if true %}
  {% verbatim do %}
    foo
  {% end %}
{% end %}

In general, using verbatim at top-level behaves weirdly.
This code:

{% puts 1 %}
{% verbatim do %}
  {% puts 2 %}
{% end %}
{% puts 3 %}

..prints the numbers "1 2 3 2 2 2" (in this order).

When running the above code with crystal run --stats, I get this output:

Parse:                             00:00:00.000374521 (   0.76MB)
1emantic (top level):             
2
3
Semantic (top level):              00:00:00.337099992 ( 106.28MB)
Semantic (new):                    00:00:00.001081401 ( 106.28MB)
2emantic (type declarations):     
2
Semantic (type declarations):      00:00:00.019435251 ( 106.28MB)
Semantic (abstract def check):     00:00:00.007088344 ( 106.28MB)
Semantic (restrictions augmenter): 00:00:00.006305759 ( 106.28MB)
Semantic (ivars initializers):     00:00:00.060938856 ( 106.28MB)
Semantic (cvars initializers):     00:00:00.053511380 ( 122.28MB)
2emantic (main):                  
Semantic (main):                   00:00:00.035419036 ( 138.28MB)
Semantic (cleanup):                00:00:00.000240346 ( 138.28MB)
Semantic (recursive struct check): 00:00:00.000607983 ( 138.28MB)
Codegen (crystal):                 00:00:00.366583250 ( 138.34MB)
Codegen (bc+obj):                  00:00:00.038621489 ( 138.34MB)
Codegen (linking):                 00:00:00.200052298 ( 138.34MB)

We can see that everything is executed normally once inside the Semantic (top level) phase.
But for some reason, the macro is executed again twice inside the Semantic (type declarations) phase.
And later, it is called again inside the Semantic (main) phase.


Of course, using verbatim here makes no sense.
This issue was also not found during actual development but while researching the compiler internals.
Because of this, a potential fix could be to make using verbatim raise a proper error when there is no existing macro context.
Still, it should be investigated why all this happens.


$ crystal -v
Crystal 1.9.2 [1908c816f] (2023-07-19)

LLVM: 15.0.7
Default target: x86_64-unknown-linux-gnu
@BlobCodes
Copy link
Contributor Author

Just found that this is a duplicate/extension of #9749, I shouldn't write these bug reports at night 😓

@BlobCodes BlobCodes closed this as not planned Won't fix, can't repro, duplicate, stale Aug 12, 2023
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

2 participants