Skip to content

Compiler plugins cause REPL to crash #18381

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

Closed
mrdziuban opened this issue Aug 10, 2023 · 7 comments · Fixed by #18394
Closed

Compiler plugins cause REPL to crash #18381

mrdziuban opened this issue Aug 10, 2023 · 7 comments · Fixed by #18394

Comments

@mrdziuban
Copy link

Compiler version

3.3.0, also with the latest 3.3.1-RC4 and nightly 3.4.0-RC1-bin-20230809-c5adafc-NIGHTLY

Minimized code

https://github.com/mrdziuban/dotty-compiler-plugin-issue

After cloning that repo and running sbt package, you can reproduce the issue by running scala with the plugin:

scala -Xplugin:target/scala-3.3.0/example-compiler-plugin_3-0.1.0-SNAPSHOT.jar

and then by evaluating two statements:

scala> val x = 1
********* running example compiler plugin
val x: Int = 1

scala> val y = 2

Output

When evaluating the second statement, the REPL crashes:

Exception in thread "main" java.lang.AssertionError: assertion failed: phase example has already been used once; cannot be reused
	at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
	at dotty.tools.dotc.core.Phases$Phase.init(Phases.scala:403)
	at dotty.tools.dotc.core.Phases$Phase.init(Phases.scala:417)
	at dotty.tools.dotc.core.Phases$PhasesBase.usePhases(Phases.scala:168)
	at dotty.tools.dotc.core.Phases$PhasesBase.usePhases$(Phases.scala:37)
	at dotty.tools.dotc.core.Contexts$ContextBase.usePhases(Contexts.scala:836)
	at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:232)
	at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:280)
	at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:67)
	at dotty.tools.dotc.Run.compileUnits(Run.scala:280)
	at dotty.tools.dotc.Run.compileUnits(Run.scala:201)
	at dotty.tools.repl.ReplCompiler.compile(ReplCompiler.scala:87)
	at dotty.tools.repl.ReplDriver.compile(ReplDriver.scala:307)
	at dotty.tools.repl.ReplDriver.interpret(ReplDriver.scala:269)
	at dotty.tools.repl.ReplDriver.loop$1(ReplDriver.scala:169)
	at dotty.tools.repl.ReplDriver.runUntilQuit$$anonfun$1(ReplDriver.scala:172)
	at dotty.tools.repl.ReplDriver.withRedirectedOutput(ReplDriver.scala:211)
	at dotty.tools.repl.ReplDriver.runBody$$anonfun$1(ReplDriver.scala:185)
	at dotty.tools.runner.ScalaClassLoader$.asContext(ScalaClassLoader.scala:80)
	at dotty.tools.repl.ReplDriver.runBody(ReplDriver.scala:185)
	at dotty.tools.repl.ReplDriver.runUntilQuit(ReplDriver.scala:172)
	at dotty.tools.repl.ReplDriver.tryRunning(ReplDriver.scala:134)
	at dotty.tools.repl.Main$.main(Main.scala:7)
	at dotty.tools.MainGenericRunner$.run$1(MainGenericRunner.scala:193)
	at dotty.tools.MainGenericRunner$.process(MainGenericRunner.scala:270)
	at dotty.tools.MainGenericRunner$.main(MainGenericRunner.scala:281)
	at dotty.tools.MainGenericRunner.main(MainGenericRunner.scala)

Expectation

The REPL should handle compiler plugins and not crash

@mrdziuban mrdziuban added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Aug 10, 2023
@SethTisue
Copy link
Member

nice catch. compared to Scala 2, I think Scala 3 compiler plugins in are in much less wide use, so I'm not too surprised that something quite basic like this is broken (but it's dismaying nonetheless, of course)

@dwijnand dwijnand removed the stat:needs triage Every issue needs to have an "area" and "itype" label label Aug 10, 2023
@som-snytt
Copy link
Contributor

I'll take a quick look. At a glance, maybe the Run re-adds the plugin when the Context is built.

@som-snytt
Copy link
Contributor

som-snytt commented Aug 10, 2023

I took a look, and Scala 3 expects to instantiate phase objects per Run. The example incorrectly supplies the same phase object in init, where init allows a phase to optionally participate in the Run. It works correctly as:

  override def init(opts: List[String]): List[PluginPhase] = List(ExamplePhase())

  class ExamplePhase extends PluginPhase {

There is no trivial means to subvert this requirement (by overriding behavior).

Not closing in case there is documentation follow-up.

@som-snytt som-snytt removed their assignment Aug 10, 2023
@mrdziuban
Copy link
Author

mrdziuban commented Aug 10, 2023

Oooh, very good to know, thank you @som-snytt! Feel free to close this if you'd like, or reuse it for documenting the behavior if you think it's worthwhile sorry I see you already said this 😄

mrdziuban added a commit to mblink/nowarn-plugin that referenced this issue Aug 10, 2023
mrdziuban added a commit to mblink/disable-toString that referenced this issue Aug 10, 2023
@SethTisue
Copy link
Member

@mrdziuban was your sample plugin code copied from some upstream source where the bug could be corrected?

I am the author of (closed source) Scala 3 compiler plugin and I see that my plugin has this bug, so I'm glad to learn of it, thanks.

I see no indication of the requirement in the Scaladoc of StandardPlugin (or ResearchPlugin). We should document it.

@mrdziuban
Copy link
Author

Yeah I maintain a couple open source plugins at work, I just updated both of them a bit ago

@SethTisue
Copy link
Member

doc PR: #18394

Kordyjan pushed a commit that referenced this issue Dec 1, 2023
Kordyjan pushed a commit that referenced this issue Dec 7, 2023
Kordyjan pushed a commit that referenced this issue Dec 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants