Skip to content

Commit

Permalink
Backport "Error instead of StaleSymbol crash for certain cyclic macro…
Browse files Browse the repository at this point in the history
… dependencies" to LTS (#20867)

Backports #19549 to the LTS branch.

PR submitted by the release tooling.
[skip ci]
  • Loading branch information
WojciechMazur authored Jul 1, 2024
2 parents 56cb527 + a69ac87 commit 89ec44c
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 3 deletions.
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/Driver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ class Driver {
if (ctx.settings.XprintSuspension.value)
report.echo(i"compiling suspended $suspendedUnits%, %")
val run1 = compiler.newRun
for unit <- suspendedUnits do unit.suspended = false
run1.compileUnits(suspendedUnits)
run1.compileSuspendedUnits(suspendedUnits)
finish(compiler, run1)(using MacroClassLoader.init(ctx.fresh))

protected def initCtx: Context = (new ContextBase).initialCtx
Expand Down
11 changes: 11 additions & 0 deletions compiler/src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,17 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
compiling = false
}

private var myCompilingSuspended: Boolean = false

/** Is this run started via a compilingSuspended? */
def isCompilingSuspended: Boolean = myCompilingSuspended

/** Compile units `us` which were suspended in a previous run */
def compileSuspendedUnits(us: List[CompilationUnit]): Unit =
myCompilingSuspended = true
for unit <- us do unit.suspended = false
compileUnits(us)

/** Enter top-level definitions of classes and objects contained in source file `file`.
* The newly added symbols replace any previously entered symbols.
* If `typeCheck = true`, also run typer on the compilation unit, and set
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,10 @@ object Denotations {
}

def staleSymbolError(using Context): Nothing =
throw new StaleSymbol(staleSymbolMsg)
if symbol.isPackageObject && ctx.run != null && ctx.run.nn.isCompilingSuspended then
throw TypeError(em"Cyclic macro dependency; macro refers to a toplevel symbol in ${symbol.source} from which the macro is called")
else
throw new StaleSymbol(staleSymbolMsg)

def staleSymbolMsg(using Context): String = {
def ownerMsg = this match {
Expand Down
4 changes: 4 additions & 0 deletions tests/neg/i19351.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- Error: tests/neg/i19351/A.scala:3:35 --------------------------------------------------------------------------------
3 | inline def myMacro(): x.type = ${myMacroExpr} // error
| ^
|Cyclic macro dependency; macro refers to a toplevel symbol in tests/neg/i19351/A.scala from which the macro is called
5 changes: 5 additions & 0 deletions tests/neg/i19351/A.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//object A:
val x: Int = 1
inline def myMacro(): x.type = ${myMacroExpr} // error
def test = myMacro()

3 changes: 3 additions & 0 deletions tests/neg/i19351/B.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import scala.quoted.*
//import A.*
def myMacroExpr(using Quotes): Expr[x.type] = '{???}
12 changes: 12 additions & 0 deletions tests/neg/i19351a.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- Error: tests/neg/i19351a/Test.scala:8:34 ----------------------------------------------------------------------------
8 |inline def not(b: Bool): Bool = ${notMacro('b)} // error // error
| ^
|Cyclic macro dependency; macro refers to a toplevel symbol in tests/neg/i19351a/Test.scala from which the macro is called
-- [E046] Cyclic Error: tests/neg/i19351a/Test.scala:8:46 --------------------------------------------------------------
8 |inline def not(b: Bool): Bool = ${notMacro('b)} // error // error
| ^
| Cyclic reference involving method $anonfun
|
| Run with -explain-cyclic for more details.
|
| longer explanation available when compiling with `-explain`
13 changes: 13 additions & 0 deletions tests/neg/i19351a/Macro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Macro class
package test

import scala.quoted.*

def notMacro(bool: Expr[Bool])(using Quotes): Expr[Bool] =
'{$bool(False, True)}

def showMacro(bool: Expr[Bool])(using Quotes): Expr[String] =
'{$bool("TRUE", "FALSE")}

def foldMacro[T: Type](bool: Expr[Bool], t: Expr[T], f: Expr[T])(using Quotes): Expr[T] =
'{$bool($t, $f)}
15 changes: 15 additions & 0 deletions tests/neg/i19351a/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//Test class
package test

type Bool = [R] => (R, R) => R
val True: Bool = [R] => (t: R, _: R) => t
val False: Bool = [R] => (_: R, f: R) => f

inline def not(b: Bool): Bool = ${notMacro('b)} // error // error
inline def show(b: Bool): String = ${showMacro('b)}
//inline def not(b: Bool): Bool = ${foldMacro('b, 'False, 'True)}
//inline def show(b: Bool): String = ${foldMacro('b, '{"TRUE"}, '{"FALSE"})}


@main def testing =
println(show(not(True)))

0 comments on commit 89ec44c

Please sign in to comment.