Skip to content

Commit

Permalink
Refine handling of StaleSymbol type errors (scala#19605)
Browse files Browse the repository at this point in the history
Regular StaleSymbol can be caught and masked in some situations. Stale
symbol type errors need to allow the same.

Fixes scala#19604
  • Loading branch information
nicolasstucki committed Feb 5, 2024
2 parents 6af5189 + fbffe7b commit f14d0a2
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 5 deletions.
20 changes: 15 additions & 5 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import config.Config
import config.Printers.overload
import util.common.*
import typer.ProtoTypes.NoViewsAllowed
import reporting.Message
import collection.mutable.ListBuffer

import scala.compiletime.uninitialized
Expand Down Expand Up @@ -954,10 +955,9 @@ object Denotations {
}

def staleSymbolError(using Context): Nothing =
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)
if symbol.isPackageObject && ctx.run != null && ctx.run.nn.isCompilingSuspended
then throw StaleSymbolTypeError(symbol)
else throw StaleSymbolException(staleSymbolMsg)

def staleSymbolMsg(using Context): String = {
def ownerMsg = this match {
Expand Down Expand Up @@ -1365,9 +1365,19 @@ object Denotations {
else
NoSymbol

trait StaleSymbol extends Exception

/** An exception for accessing symbols that are no longer valid in current run */
class StaleSymbol(msg: => String) extends Exception {
class StaleSymbolException(msg: => String) extends Exception, StaleSymbol {
util.Stats.record("stale symbol")
override def getMessage(): String = msg
}

/** An exception that is at the same type a StaleSymbol and a TypeError.
* Sine it is a TypeError it can be reported as a nroaml error instead of crashing
* the compiler.
*/
class StaleSymbolTypeError(symbol: Symbol)(using Context) extends TypeError, StaleSymbol:
def toMessage(using Context) =
em"Cyclic macro dependency; macro refers to a toplevel symbol in ${symbol.source} from which the macro is called"
}
11 changes: 11 additions & 0 deletions tests/pos/i19604/ZSet.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// ZSet.scala
// moving it to core.scala would lead to Recursion limit exceeded: find-member prelude.ZSetSyntax
package prelude

import prelude.newtypes._

class ZSet[+A, +B]
object ZSet
trait ZSetSyntax {
implicit final class ZSetMapOps[+A](self: Map[A, Natural])
}
37 changes: 37 additions & 0 deletions tests/pos/i19604/core.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// core.scala
package prelude

sealed trait Assertion[-A]
object Assertion:
def greaterThanOrEqualTo[A](value: A): Assertion[A] = ???

sealed trait AssertionError

abstract class NewtypeCustom[A] {
type Type
protected inline def validateInline(inline value: A): Unit

inline def apply(inline a1: A): Type = {
validateInline(a1)
a1.asInstanceOf[Type]
}
}
abstract class Newtype[A] extends NewtypeCustom[A] {
def assertion: Assertion[A] = ???
protected inline def validateInline(inline value: A): Unit = ${
Macros.validateInlineImpl[A]('assertion, 'value)
}
}

abstract class Subtype[A] extends Newtype[A] {
type Type <: A
}


package object newtypes {
type Natural = Natural.Type
object Natural extends Subtype[Int] {
override inline def assertion = Assertion.greaterThanOrEqualTo(0)
val one: Natural = Natural(1) // triggers macro
}
}
8 changes: 8 additions & 0 deletions tests/pos/i19604/macro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// macro.scala
package prelude
import scala.quoted.*

object Macros {
def validateInlineImpl[A: Type](assertionExpr: Expr[Assertion[A]], a: Expr[A])(using Quotes): Expr[Unit] =
'{ () }
}
8 changes: 8 additions & 0 deletions tests/pos/i19604/prelude.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// prelude.scala

import prelude.newtypes.Natural

package object prelude extends ZSetSyntax {
type MultiSet[+A] = ZSet[A, Natural]
val MultiSet: ZSet.type = ZSet
}

0 comments on commit f14d0a2

Please sign in to comment.