Skip to content

Commit cc0041b

Browse files
oderskyWojciechMazur
authored andcommitted
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 [Cherry-picked fbffe7b]
1 parent 3581bfb commit cc0041b

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
/** Denotations represent the meaning of symbols and named types.
@@ -945,10 +946,9 @@ object Denotations {
945946
}
946947

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

953953
def staleSymbolMsg(using Context): String = {
954954
def ownerMsg = this match {
@@ -1356,9 +1356,19 @@ object Denotations {
13561356
else
13571357
NoSymbol
13581358

1359+
trait StaleSymbol extends Exception
1360+
13591361
/** An exception for accessing symbols that are no longer valid in current run */
1360-
class StaleSymbol(msg: => String) extends Exception {
1362+
class StaleSymbolException(msg: => String) extends Exception, StaleSymbol {
13611363
util.Stats.record("stale symbol")
13621364
override def getMessage(): String = msg
13631365
}
1366+
1367+
/** An exception that is at the same type a StaleSymbol and a TypeError.
1368+
* Sine it is a TypeError it can be reported as a nroaml error instead of crashing
1369+
* the compiler.
1370+
*/
1371+
class StaleSymbolTypeError(symbol: Symbol)(using Context) extends TypeError, StaleSymbol:
1372+
def toMessage(using Context) =
1373+
em"Cyclic macro dependency; macro refers to a toplevel symbol in ${symbol.source} from which the macro is called"
13641374
}

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)