Skip to content

Commit f14d0a2

Browse files
Refine handling of StaleSymbol type errors (#19605)
Regular StaleSymbol can be caught and masked in some situations. Stale symbol type errors need to allow the same. Fixes #19604
2 parents 6af5189 + fbffe7b commit f14d0a2

File tree

5 files changed

+79
-5
lines changed

5 files changed

+79
-5
lines changed

compiler/src/dotty/tools/dotc/core/Denotations.scala

+15-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import config.Config
2222
import config.Printers.overload
2323
import util.common.*
2424
import typer.ProtoTypes.NoViewsAllowed
25+
import reporting.Message
2526
import collection.mutable.ListBuffer
2627

2728
import scala.compiletime.uninitialized
@@ -954,10 +955,9 @@ object Denotations {
954955
}
955956

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

962962
def staleSymbolMsg(using Context): String = {
963963
def ownerMsg = this match {
@@ -1365,9 +1365,19 @@ object Denotations {
13651365
else
13661366
NoSymbol
13671367

1368+
trait StaleSymbol extends Exception
1369+
13681370
/** An exception for accessing symbols that are no longer valid in current run */
1369-
class StaleSymbol(msg: => String) extends Exception {
1371+
class StaleSymbolException(msg: => String) extends Exception, StaleSymbol {
13701372
util.Stats.record("stale symbol")
13711373
override def getMessage(): String = msg
13721374
}
1375+
1376+
/** An exception that is at the same type a StaleSymbol and a TypeError.
1377+
* Sine it is a TypeError it can be reported as a nroaml error instead of crashing
1378+
* the compiler.
1379+
*/
1380+
class StaleSymbolTypeError(symbol: Symbol)(using Context) extends TypeError, StaleSymbol:
1381+
def toMessage(using Context) =
1382+
em"Cyclic macro dependency; macro refers to a toplevel symbol in ${symbol.source} from which the macro is called"
13731383
}

tests/pos/i19604/ZSet.scala

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// ZSet.scala
2+
// moving it to core.scala would lead to Recursion limit exceeded: find-member prelude.ZSetSyntax
3+
package prelude
4+
5+
import prelude.newtypes._
6+
7+
class ZSet[+A, +B]
8+
object ZSet
9+
trait ZSetSyntax {
10+
implicit final class ZSetMapOps[+A](self: Map[A, Natural])
11+
}

tests/pos/i19604/core.scala

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// core.scala
2+
package prelude
3+
4+
sealed trait Assertion[-A]
5+
object Assertion:
6+
def greaterThanOrEqualTo[A](value: A): Assertion[A] = ???
7+
8+
sealed trait AssertionError
9+
10+
abstract class NewtypeCustom[A] {
11+
type Type
12+
protected inline def validateInline(inline value: A): Unit
13+
14+
inline def apply(inline a1: A): Type = {
15+
validateInline(a1)
16+
a1.asInstanceOf[Type]
17+
}
18+
}
19+
abstract class Newtype[A] extends NewtypeCustom[A] {
20+
def assertion: Assertion[A] = ???
21+
protected inline def validateInline(inline value: A): Unit = ${
22+
Macros.validateInlineImpl[A]('assertion, 'value)
23+
}
24+
}
25+
26+
abstract class Subtype[A] extends Newtype[A] {
27+
type Type <: A
28+
}
29+
30+
31+
package object newtypes {
32+
type Natural = Natural.Type
33+
object Natural extends Subtype[Int] {
34+
override inline def assertion = Assertion.greaterThanOrEqualTo(0)
35+
val one: Natural = Natural(1) // triggers macro
36+
}
37+
}

tests/pos/i19604/macro.scala

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// macro.scala
2+
package prelude
3+
import scala.quoted.*
4+
5+
object Macros {
6+
def validateInlineImpl[A: Type](assertionExpr: Expr[Assertion[A]], a: Expr[A])(using Quotes): Expr[Unit] =
7+
'{ () }
8+
}

tests/pos/i19604/prelude.scala

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// prelude.scala
2+
3+
import prelude.newtypes.Natural
4+
5+
package object prelude extends ZSetSyntax {
6+
type MultiSet[+A] = ZSet[A, Natural]
7+
val MultiSet: ZSet.type = ZSet
8+
}

0 commit comments

Comments
 (0)