diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index cb5e8a7b314c..db523c879ea2 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -215,6 +215,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe case TailrecNestedCallID //errorNumber: 199 case FinalLocalDefID // errorNumber: 200 case NonNamedArgumentInJavaAnnotationID // errorNumber: 201 + case QuotedTypeMissingID // errorNumber: 202 def errorNumber = ordinal - 1 diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageKind.scala b/compiler/src/dotty/tools/dotc/reporting/MessageKind.scala index 10ad4f83d93d..bb02a08d2e46 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageKind.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageKind.scala @@ -22,6 +22,7 @@ enum MessageKind: case Compatibility case PotentialIssue case UnusedSymbol + case Staging /** Human readable message that will end up being shown to the user. * NOTE: This is only used in the situation where you have multiple words @@ -39,5 +40,6 @@ enum MessageKind: case MatchCaseUnreachable => "Match case Unreachable" case PotentialIssue => "Potential Issue" case UnusedSymbol => "Unused Symbol" + case Staging => "Staging Issue" case kind => kind.toString end MessageKind diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index d65f9a9857e2..97cd70113c2e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -108,6 +108,9 @@ end CyclicMsg abstract class ReferenceMsg(errorId: ErrorMessageID)(using Context) extends Message(errorId): def kind = MessageKind.Reference +abstract class StagingMessage(errorId: ErrorMessageID)(using Context) extends Message(errorId): + override final def kind = MessageKind.Staging + abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(using Context) extends SyntaxMsg(errNo) { def explain(using Context) = { @@ -3323,3 +3326,20 @@ class NonNamedArgumentInJavaAnnotation(using Context) extends SyntaxMsg(NonNamed """ end NonNamedArgumentInJavaAnnotation + +final class QuotedTypeMissing(tpe: Type)(using Context) extends StagingMessage(QuotedTypeMissingID): + + private def witness = defn.QuotedTypeClass.typeRef.appliedTo(tpe) + + override protected def msg(using Context): String = + i"Reference to $tpe within quotes requires a given ${witness} in scope" + + override protected def explain(using Context): String = + i"""Referencing `$tpe` inside a quoted expression requires a `${witness}` to be in scope. + |Since Scala is subject to erasure at runtime, the type information will be missing during the execution of the code. + |`${witness}` is therefore needed to carry `$tpe`'s type information into the quoted code. + |Without an implicit `${witness}`, the type `$tpe` cannot be properly referenced within the expression. + |To resolve this, ensure that a `${witness}` is available, either through a context-bound or explicitly. + |""" + +end QuotedTypeMissing diff --git a/compiler/src/dotty/tools/dotc/staging/HealType.scala b/compiler/src/dotty/tools/dotc/staging/HealType.scala index 5a26803c8137..a73f884fbac9 100644 --- a/compiler/src/dotty/tools/dotc/staging/HealType.scala +++ b/compiler/src/dotty/tools/dotc/staging/HealType.scala @@ -1,17 +1,19 @@ package dotty.tools.dotc package staging -import dotty.tools.dotc.core.Contexts.* -import dotty.tools.dotc.core.Decorators.* -import dotty.tools.dotc.core.Flags.* -import dotty.tools.dotc.core.StdNames.* -import dotty.tools.dotc.core.Symbols.* -import dotty.tools.dotc.core.Types.* -import dotty.tools.dotc.staging.StagingLevel.* -import dotty.tools.dotc.staging.QuoteTypeTags.* +import reporting.* -import dotty.tools.dotc.typer.Implicits.SearchFailureType -import dotty.tools.dotc.util.SrcPos +import core.Contexts.* +import core.Decorators.* +import core.Flags.* +import core.StdNames.* +import core.Symbols.* +import core.Types.* +import StagingLevel.* +import QuoteTypeTags.* + +import typer.Implicits.SearchFailureType +import util.SrcPos class HealType(pos: SrcPos)(using Context) extends TypeMap { @@ -98,9 +100,7 @@ class HealType(pos: SrcPos)(using Context) extends TypeMap { pos) tp case _ => - report.error(em"""Reference to $tp within quotes requires a given $reqType in scope. - | - |""", pos) + report.error(QuotedTypeMissing(tp), pos) tp } diff --git a/tests/neg/i21696.check b/tests/neg/i21696.check new file mode 100644 index 000000000000..9195263040b3 --- /dev/null +++ b/tests/neg/i21696.check @@ -0,0 +1,13 @@ +-- [E202] Staging Issue Error: tests/neg/i21696.scala:7:52 ------------------------------------------------------------- +7 |def foo[T](using Quotes): Expr[Thing[T]] = '{ Thing[T]() } // error + | ^ + | Reference to T within quotes requires a given scala.quoted.Type[T] in scope + |--------------------------------------------------------------------------------------------------------------------- + | Explanation (enabled by `-explain`) + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | Referencing `T` inside a quoted expression requires a `scala.quoted.Type[T]` to be in scope. + | Since Scala is subject to erasure at runtime, the type information will be missing during the execution of the code. + | `scala.quoted.Type[T]` is therefore needed to carry `T`'s type information into the quoted code. + | Without an implicit `scala.quoted.Type[T]`, the type `T` cannot be properly referenced within the expression. + | To resolve this, ensure that a `scala.quoted.Type[T]` is available, either through a context-bound or explicitly. + --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg/i21696.scala b/tests/neg/i21696.scala new file mode 100644 index 000000000000..7ec30a8a2e41 --- /dev/null +++ b/tests/neg/i21696.scala @@ -0,0 +1,7 @@ +//> using options -explain + +import scala.quoted.{Expr, Quotes} + +case class Thing[T]() + +def foo[T](using Quotes): Expr[Thing[T]] = '{ Thing[T]() } // error