-
Notifications
You must be signed in to change notification settings - Fork 2
Inline expr incorrectly translates by-value references to by-name #307
Comments
Oh and FYI, inspecting |
There's too much macro operation for me to see whether something is wrong here. What should have been the expected code in the 2nd and 3rd case? And what would be the expectation why and where that code would be generated? |
I'll try to clarify
The macro only does this following one line, and then prints out the output. val callSite = self.asTerm.underlying
Instead of new BUG.ApiWithMacros[scala.AnyRef]().remember(new scala.AnyRef()).remember(new scala.AnyRef()) which contains new scala.AnyRef() twice, it should be like the first example, like this: new BUG.ApiWithMacros[scala.AnyRef]().remember(n).remember(n) I've replaced
Sorry I don't understand this question. |
I guess it's the In any case you are dealing here with a low-level API for term plumbing. It seems that any expectations of call-by-name vs call-by-value are up to the macro. They are not guaranteed by the API. @nicolasstucki What is your opinion here? |
Ah that's interesting. For reference, using |
From a quick read though the issue it seems that As I understand, the code should recover the extension [A](inline self: ApiWithMacros[A]) inline def test: Unit =
${ macroDefinition('self) } |
I tried that out like this: - final inline def test: Unit =
- ${ macroDefinition('this) }
}
+ extension [A](inline self: ApiWithMacros[A]) inline def test: Unit =
+ ${ macroDefinition('self) }
+
def macroDefinition[A](self: Expr[ApiWithMacros[A]])(using Quotes): Expr[Unit] = {
import quotes.reflect.*
- val callSite = self.asTerm.underlying
+ val callSite = self.asTerm and now it works as expected
so thank you! 🎉 It's a great workaround. Now the question is should the use of an extension method be required? Shouldn't there be away to accomplish the same thing directly from the method in the trait? WDYT? |
The extension method solution is by design and not a workaround. The limitation we have is that we do not have a way to state that the class A:
// mimic extension method syntax to annotate the `this`
inline (inline this) def foo: Int = ... or class A:
@inlineThis inline def foo: Int = ... |
I think steering people towards extension methods in this case is fine. |
Should we move this to feature requests? |
Yes, we should move it to feature requests |
Understood. Thank you both for the help |
This is the fix/workaround for lampepfl/dotty-feature-requests#307
Compiler version
3.1.2
Minimized code
BUG.scala
:demo.scala
:Output
Each 3-line block above prints the following at compile-time:
Expectation
The 1st result is correct; we see two
Ident(n)
clauses which is correct becausen
is being referenced by-value.The 2nd and 3rd results are incorrect. You can see that
n
has been inlined to be effectively by-name, resulting in two separatenew AnyRef
calls. Imagine thatn
is something obviously-mutable likeList.newBuilder
and you can see how disastrous changing the semantics to by-name is.The text was updated successfully, but these errors were encountered: