Skip to content

Fix #9227: Do not suspend REPL compilation unit #9232

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

Merged
merged 3 commits into from
Jun 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/dotc/CompilationUnit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class CompilationUnit protected (val source: SourceFile) {

var tpdTree: tpd.Tree = tpd.EmptyTree

/** Is this the compilation unit of a Java file */
def isJava: Boolean = source.file.name.endsWith(".java")

/** The source version for this unit, as determined by a language import */
Expand All @@ -47,7 +48,14 @@ class CompilationUnit protected (val source: SourceFile) {

var suspended: Boolean = false

/** Can this compilation unit be suspended */
def isSuspendable: Boolean = true

/** Suspends the compilation unit by thowing a SuspendException
* and recoring the suspended compilation unit
*/
def suspend()(using Context): Nothing =
assert(isSuspendable)
if !suspended then
if (ctx.settings.XprintSuspension.value)
ctx.echo(i"suspended: $this")
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Splicer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ object Splicer {
ex.getTargetException match {
case ex: scala.quoted.Reporting.StopQuotedContext =>
throw ex
case MissingClassDefinedInCurrentRun(sym) =>
case MissingClassDefinedInCurrentRun(sym) if ctx.compilationUnit.isSuspendable =>
if (ctx.settings.XprintSuspension.value)
ctx.echo(i"suspension triggered by a dependency on $sym", pos)
ctx.compilationUnit.suspend() // this throws a SuspendException
Expand Down
7 changes: 4 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1407,14 +1407,15 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
assert(level == 0)
val inlinedFrom = enclosingInlineds.last
val dependencies = macroDependencies(body)

val suspendable = ctx.compilationUnit.isSuspendable
if dependencies.nonEmpty && !ctx.reporter.errorsReported then
for sym <- dependencies do
if ctx.compilationUnit.source.file == sym.associatedFile then
ctx.error(em"Cannot call macro $sym defined in the same source file", call.sourcePos)
if (ctx.settings.XprintSuspension.value)
if (suspendable && ctx.settings.XprintSuspension.value)
ctx.echo(i"suspension triggered by macro call to ${sym.showLocated} in ${sym.associatedFile}", call.sourcePos)
ctx.compilationUnit.suspend() // this throws a SuspendException
if suspendable then
ctx.compilationUnit.suspend() // this throws a SuspendException

val evaluatedSplice = inContext(tastyreflect.MacroExpansion.context(inlinedFrom)) {
Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/repl/ReplCompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class ReplCompiler extends Compiler {
val objectTermName = ctx.source.file.toString.toTermName
objectNames.update(defs.state.objectIndex, objectTermName)

val unit = CompilationUnit(ctx.source)
val unit = new ReplCompilationUnit(ctx.source)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: I would use an anonymous class

Suggested change
val unit = new ReplCompilationUnit(ctx.source)
val unit = new CompilationUnit(ctx.source) {
override def isSuspendable: Boolean = false
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to make it possible to identify a REPL compilation unit simply. I remember seeing places where we identify them by the name of the file which we could simplify with this scheme.

unit.untpdTree = wrapped(defs, objectTermName, span)
unit
}
Expand Down
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/repl/ReplCompillationUnit.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package dotty.tools.repl

import dotty.tools.dotc.CompilationUnit
import dotty.tools.dotc.util.SourceFile


class ReplCompilationUnit(source: SourceFile) extends CompilationUnit(source):
override def isSuspendable: Boolean = false
5 changes: 5 additions & 0 deletions compiler/test-resources/repl/i9227
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
scala> import scala.quoted._; inline def myMacro[T]: Unit = ${ myMacroImpl[T] }; def myMacroImpl[T](using qctx: QuoteContext): Expr[Unit] = '{}; println(myMacro[Int])
1 | import scala.quoted._; inline def myMacro[T]: Unit = ${ myMacroImpl[T] }; def myMacroImpl[T](using qctx: QuoteContext): Expr[Unit] = '{}; println(myMacro[Int])
| ^^^^^^^^^^^^
| Cannot call macro method myMacroImpl defined in the same source file
| This location contains code that was inlined from rs$line$1:1