From ae68ec7c0995250a38f051b487dfd7736a01fe14 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 24 Jun 2020 09:46:19 +0200 Subject: [PATCH 1/3] Fix #9227: Do not suspend REPL compilation unit --- compiler/src/dotty/tools/dotc/CompilationUnit.scala | 3 +++ compiler/src/dotty/tools/dotc/typer/Inliner.scala | 7 ++++--- compiler/test-resources/repl/i9227 | 5 +++++ 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 compiler/test-resources/repl/i9227 diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 13ae18141c67..05b507554c67 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -14,6 +14,7 @@ import typer.Nullables import transform.SymUtils._ import core.Decorators.{given _} import config.SourceVersion +import StdNames.str class CompilationUnit protected (val source: SourceFile) { @@ -25,6 +26,8 @@ class CompilationUnit protected (val source: SourceFile) { def isJava: Boolean = source.file.name.endsWith(".java") + def isREPL: Boolean = source.file.name.startsWith(str.REPL_SESSION_LINE) + /** The source version for this unit, as determined by a language import */ var sourceVersion: Option[SourceVersion] = None diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index e9e9d9420041..e733ced9bf9a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -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 inREPL = ctx.compilationUnit.isREPL 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 (ctx.settings.XprintSuspension.value && !inREPL) ctx.echo(i"suspension triggered by macro call to ${sym.showLocated} in ${sym.associatedFile}", call.sourcePos) - ctx.compilationUnit.suspend() // this throws a SuspendException + if !inREPL then + ctx.compilationUnit.suspend() // this throws a SuspendException val evaluatedSplice = inContext(tastyreflect.MacroExpansion.context(inlinedFrom)) { Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext) diff --git a/compiler/test-resources/repl/i9227 b/compiler/test-resources/repl/i9227 new file mode 100644 index 000000000000..97f9caab6bca --- /dev/null +++ b/compiler/test-resources/repl/i9227 @@ -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 From 8497e46a5ca9c92654d92560709bd7158611fcf5 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 25 Jun 2020 09:38:24 +0200 Subject: [PATCH 2/3] Add CompilationUnit.isSuspendable --- compiler/src/dotty/tools/dotc/CompilationUnit.scala | 9 +++++++++ compiler/src/dotty/tools/dotc/transform/Splicer.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Inliner.scala | 6 +++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 05b507554c67..4d53579e0d30 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -24,8 +24,10 @@ 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") + /** Is this the compilation unit of a REPL input */ def isREPL: Boolean = source.file.name.startsWith(str.REPL_SESSION_LINE) /** The source version for this unit, as determined by a language import */ @@ -50,7 +52,14 @@ class CompilationUnit protected (val source: SourceFile) { var suspended: Boolean = false + /** Can this compilation unit be suspended */ + def isSuspendable: Boolean = !isREPL + + /** 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") diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index 62fe2d8fe79f..386c63a08a1c 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -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 diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index e733ced9bf9a..6355bd53d34d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -1407,14 +1407,14 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { assert(level == 0) val inlinedFrom = enclosingInlineds.last val dependencies = macroDependencies(body) - val inREPL = ctx.compilationUnit.isREPL + 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 && !inREPL) + if (suspendable && ctx.settings.XprintSuspension.value) ctx.echo(i"suspension triggered by macro call to ${sym.showLocated} in ${sym.associatedFile}", call.sourcePos) - if !inREPL then + if suspendable then ctx.compilationUnit.suspend() // this throws a SuspendException val evaluatedSplice = inContext(tastyreflect.MacroExpansion.context(inlinedFrom)) { From 763bb08985d5aed4f9490bd65c2bb4f3e35cad0e Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 25 Jun 2020 11:03:09 +0200 Subject: [PATCH 3/3] Add ReplCompilationUnit --- compiler/src/dotty/tools/dotc/CompilationUnit.scala | 6 +----- compiler/src/dotty/tools/repl/ReplCompiler.scala | 2 +- compiler/src/dotty/tools/repl/ReplCompillationUnit.scala | 8 ++++++++ 3 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 compiler/src/dotty/tools/repl/ReplCompillationUnit.scala diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 4d53579e0d30..2ffb201609b1 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -14,7 +14,6 @@ import typer.Nullables import transform.SymUtils._ import core.Decorators.{given _} import config.SourceVersion -import StdNames.str class CompilationUnit protected (val source: SourceFile) { @@ -27,9 +26,6 @@ class CompilationUnit protected (val source: SourceFile) { /** Is this the compilation unit of a Java file */ def isJava: Boolean = source.file.name.endsWith(".java") - /** Is this the compilation unit of a REPL input */ - def isREPL: Boolean = source.file.name.startsWith(str.REPL_SESSION_LINE) - /** The source version for this unit, as determined by a language import */ var sourceVersion: Option[SourceVersion] = None @@ -53,7 +49,7 @@ class CompilationUnit protected (val source: SourceFile) { var suspended: Boolean = false /** Can this compilation unit be suspended */ - def isSuspendable: Boolean = !isREPL + def isSuspendable: Boolean = true /** Suspends the compilation unit by thowing a SuspendException * and recoring the suspended compilation unit diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 96eb187b2eac..7947022444aa 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -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) unit.untpdTree = wrapped(defs, objectTermName, span) unit } diff --git a/compiler/src/dotty/tools/repl/ReplCompillationUnit.scala b/compiler/src/dotty/tools/repl/ReplCompillationUnit.scala new file mode 100644 index 000000000000..d3f2cee7e207 --- /dev/null +++ b/compiler/src/dotty/tools/repl/ReplCompillationUnit.scala @@ -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