Skip to content

Commit f2428bd

Browse files
Backport "Refine handling of StaleSymbol type errors" to LTS (#20898)
Backports #19605 to the LTS branch. PR submitted by the release tooling.
2 parents 9cd3bf0 + cc0041b commit f2428bd

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)