Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine handling of StaleSymbol type errors #19605

Merged
merged 1 commit into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Loading