-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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 scala 2 macros in traits with type parameters #18663
Conversation
I'm not sure why the CLA check is still failing, locally it looks to work
|
Tracking the CLA issue in scala/scala-dev#855 |
You could add an sbt project as a scripted test in sbt-test/scala2-compat/ (format for the |
I have added a "scripted" test for the bug, so it will actually try to use the macro once it compiles, however I hit a problem where scala 2.13.12 release refuses to read tasty files output by the scala 3 compiler from this repo. |
This is the same as dotty in that a 3.3.0 compiler can't read 3.4.0-RC1-SNAPSHOT produced tasty files. We could bake some escape hatch into the scala 2 compiler, but seeing as we don't have an escape hatch in Scala 3 it would be unprecedented. |
Thanks for the update @bishabosha and I suppose that means we have a decision to make Conservative:
Proactive:
In order to get this fix in (assuming the fix itself is approved) I would personally be happy with one of the conservative options, but as an outside observer I would be happy to look at getting the test to scrub the flag if it were deemed a reasonable approach, either in this PR or a separate one. |
update is I have looked into scrubbing the experimental flag from the tasty files as part of the test, and although it works well for the actual ones in the test, the scala 2 compiler still needs to use tasty files from scala-library_3 which could be scrubbed but it may make the test too expensive for its value. Scrubbing those would probably involve identifying the jar(s) on the classpath, unzipping them into a temporary directory, and scrubbing them there. So I'm leaning towards the escape hatch in scalac 2.13 as being the only workable option. |
You can replicate the issue with the following code: import scala.language.experimental.macros
import scala.quoted.{Quotes, Expr, Type}
class Foo[A]
object Foo {
def apply[A] = new Foo[A]
}
trait TraitWithTypeParam[A] {
protected inline def foo: Foo[A] = ${ MacrosImpl.fooImpl[A] }
protected def foo: Foo[A] = macro MacrosImpl.compatFooImpl[A]
}
// replication of scala.reflect.macros.blackbox.Context
class Ctx {
trait WeakTypeTag[T]
type Tree >: Null <: AnyRef with TreeApi
trait TreeApi extends Product { this: Tree => }
}
object MacrosImpl {
def fooImpl[A: Type](using quotes: Quotes): Expr[Foo[A]] = '{new Foo[A]}
def compatFooImpl[A: c.WeakTypeTag](c: Ctx): c.Tree = {
???
}
} this is all you need to test, I think its best to delete the sbt scripted test as it will be too fragile |
@bishabosha I will delete the scripted test as you suggest Regarding the simpler test - I can detect the bug with the test I've already committed in tests/pos-macros/i16630.scala import scala.language.experimental.macros
trait TraitWithTypeParam[A] {
protected inline def foo: Option[A] = ${ ??? }
protected def foo: Option[A] = macro ???
} Are you suggesting I replace my existing test (tests/pos-macros/i16630.scala) with the one you suggest, or is mine enough? |
4d1f51b
to
5c06bd4
Compare
Right I should have checked your test before I made the comment, then it's fine to keep your minimisation (and remove the scripted test) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fix looks good to me.
Could you also squash the commits into one?
tests/pos-macros/i16630.scala
Outdated
trait TraitWithTypeParam[A] { | ||
protected inline def foo: Option[A] = ${ ??? } | ||
protected def foo: Option[A] = macro ??? | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather minimize the test as
import scala.language.experimental.macros
trait TraitWithTypeParam[A] {
protected inline def foo: Foo[A] = ${ MacrosImpl.fooImpl[A] }
protected def foo: Foo[A] = macro MacrosImpl.compatFooImpl[A]
}
object MacrosImpl {
def fooImpl[A: Type](using quotes: Quotes): Expr[Foo[A]] = ???
def compatFooImpl[A: c.WeakTypeTag](c: scala.reflect.macros.blackbox.Context): c.Tree = ???
There are some extra checks on the macro MacrosImpl.compatFooImpl[A]
that might trigger other issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scala.reflect.macros.blackbox.Context
isn't on the classpath, which is why I made my minimisation above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. You can create a dummy interface to test this. Here is an example https://github.com/lampepfl/dotty/blob/main/tests/pos-macros/i8945.scala#L2-L11
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all the pointers both of you. I have updated the test roughly as per your suggestions. Next I will work out how to squash the commits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. @johnduffell you should squash the 3 commits into 1 before we merge this PR.
…ype params) have been completed
5368179
to
974e4d3
Compare
thanks, I have managed squashing now - took a bit to work out how to do it. Apparently you could also "squash and merge" directly in github which may save time in future. |
@Kordyjan I see this is one of PRs still marked as "needs assessment" for LTS backport. Offhand, it seems to me a like a good candidate, and affects a notable library? Is this PR one you've looked at at all yet? |
Not yet. Everything that is merged to the main is automatically marked as "needs assessment". I'll look at this PR before 3.3.3-RC1, which probably will have all backportable fixes that have made into 3.4. And by the way, our plan is still to get 3.4.0-RC1 out before the winter vacation season. |
Just to note that this also affects play-json library. As expected it's working in 3.4.0 but not 3.3.1 or 3.3.2. For more detail read on: If you try to compile this trait with the scala 3 compiler
|
Fixes #16630
This PR fixes the above issue which affects cross scala2/3 projects that use a common macro library as per https://docs.scala-lang.org/scala3/guides/migration/tutorial-macro-mixing.html , e.g. scala-logging is blocked from fixing this issue lightbend-labs/scala-logging#317
The fix makes the scala 2 macro check read the Erased flag from the initial flags rather than completing the RHS first. This will work in the case of scala 2 macros because the erased flag is explicitly added rather than being in the source code. However it relies on using an "UNSAFE" value.
More background on my investigation:
https://github.com/lampepfl/dotty/blob/f2aa33c3643655fd9a48a1e448d7d79e6e52ea79/compiler/src/dotty/tools/dotc/ast/Desugar.scala#L275
https://github.com/lampepfl/dotty/blob/7c0a848d0ed6330873a39129e6d02da169150fa7/compiler/src/dotty/tools/dotc/typer/Namer.scala#L1458-L1461
https://github.com/lampepfl/dotty/blob/7c0a848d0ed6330873a39129e6d02da169150fa7/compiler/src/dotty/tools/dotc/typer/Namer.scala#L307-L308
https://github.com/lampepfl/dotty/blob/e1a136a0076e260d1e12ca397f0a2816cbdc9015/compiler/src/dotty/tools/dotc/core/SymDenotations.scala#L128
https://github.com/lampepfl/dotty/blob/9464bf008694506250f3fd061d7de27f1dea5d38/compiler/src/dotty/tools/dotc/typer/Typer.scala#L2133
I think the fix without any restructuring must be to check the Erased flag without needing to call ensureCompleted on the symbol, but I'm not sure if there's a better way to identify scala 2 macros at this point in the code.
I managed to get it to compile by any of these:
i.e. add
symbolOfTree(constr).ensureCompleted()
between these two lineshttps://github.com/lampepfl/dotty/blob/7c0a848d0ed6330873a39129e6d02da169150fa7/compiler/src/dotty/tools/dotc/typer/Namer.scala#L1458-L1459
https://github.com/lampepfl/dotty/blob/6ff1774363208cfdd7e4d7f4eac60aad68c52cb1/compiler/src/dotty/tools/dotc/core/Flags.scala#L466
I have added a minimal test to the macros suite, which now passes. I managed to make something that detects the bug and doesn't depend on scala-reflect library, however beyond compiling we don't know if it actually did something useful. Tips on making a better test case would be appreciated!
Any tips or corrections would be useful