Skip to content

Commit fbffe7b

Browse files
committed
Refine handling of StaleSymbol type errors
Regular StaleSymbol can be caught and masked in some situations. Stale symbol type errors need to allow the same. Fixes #19604
1 parent f15bbda commit fbffe7b

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)