Skip to content

Commit 6ceaab5

Browse files
authored
Have a better error message when healing types (#21711)
Closes #21696
2 parents d2b418c + c3f1307 commit 6ceaab5

File tree

6 files changed

+56
-13
lines changed

6 files changed

+56
-13
lines changed

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

+1
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
215215
case TailrecNestedCallID //errorNumber: 199
216216
case FinalLocalDefID // errorNumber: 200
217217
case NonNamedArgumentInJavaAnnotationID // errorNumber: 201
218+
case QuotedTypeMissingID // errorNumber: 202
218219

219220
def errorNumber = ordinal - 1
220221

compiler/src/dotty/tools/dotc/reporting/MessageKind.scala

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum MessageKind:
2222
case Compatibility
2323
case PotentialIssue
2424
case UnusedSymbol
25+
case Staging
2526

2627
/** Human readable message that will end up being shown to the user.
2728
* NOTE: This is only used in the situation where you have multiple words
@@ -39,5 +40,6 @@ enum MessageKind:
3940
case MatchCaseUnreachable => "Match case Unreachable"
4041
case PotentialIssue => "Potential Issue"
4142
case UnusedSymbol => "Unused Symbol"
43+
case Staging => "Staging Issue"
4244
case kind => kind.toString
4345
end MessageKind

compiler/src/dotty/tools/dotc/reporting/messages.scala

+20
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ end CyclicMsg
108108
abstract class ReferenceMsg(errorId: ErrorMessageID)(using Context) extends Message(errorId):
109109
def kind = MessageKind.Reference
110110

111+
abstract class StagingMessage(errorId: ErrorMessageID)(using Context) extends Message(errorId):
112+
override final def kind = MessageKind.Staging
113+
111114
abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(using Context)
112115
extends SyntaxMsg(errNo) {
113116
def explain(using Context) = {
@@ -3323,3 +3326,20 @@ class NonNamedArgumentInJavaAnnotation(using Context) extends SyntaxMsg(NonNamed
33233326
"""
33243327

33253328
end NonNamedArgumentInJavaAnnotation
3329+
3330+
final class QuotedTypeMissing(tpe: Type)(using Context) extends StagingMessage(QuotedTypeMissingID):
3331+
3332+
private def witness = defn.QuotedTypeClass.typeRef.appliedTo(tpe)
3333+
3334+
override protected def msg(using Context): String =
3335+
i"Reference to $tpe within quotes requires a given ${witness} in scope"
3336+
3337+
override protected def explain(using Context): String =
3338+
i"""Referencing `$tpe` inside a quoted expression requires a `${witness}` to be in scope.
3339+
|Since Scala is subject to erasure at runtime, the type information will be missing during the execution of the code.
3340+
|`${witness}` is therefore needed to carry `$tpe`'s type information into the quoted code.
3341+
|Without an implicit `${witness}`, the type `$tpe` cannot be properly referenced within the expression.
3342+
|To resolve this, ensure that a `${witness}` is available, either through a context-bound or explicitly.
3343+
|"""
3344+
3345+
end QuotedTypeMissing

compiler/src/dotty/tools/dotc/staging/HealType.scala

+13-13
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
package dotty.tools.dotc
22
package staging
33

4-
import dotty.tools.dotc.core.Contexts.*
5-
import dotty.tools.dotc.core.Decorators.*
6-
import dotty.tools.dotc.core.Flags.*
7-
import dotty.tools.dotc.core.StdNames.*
8-
import dotty.tools.dotc.core.Symbols.*
9-
import dotty.tools.dotc.core.Types.*
10-
import dotty.tools.dotc.staging.StagingLevel.*
11-
import dotty.tools.dotc.staging.QuoteTypeTags.*
4+
import reporting.*
125

13-
import dotty.tools.dotc.typer.Implicits.SearchFailureType
14-
import dotty.tools.dotc.util.SrcPos
6+
import core.Contexts.*
7+
import core.Decorators.*
8+
import core.Flags.*
9+
import core.StdNames.*
10+
import core.Symbols.*
11+
import core.Types.*
12+
import StagingLevel.*
13+
import QuoteTypeTags.*
14+
15+
import typer.Implicits.SearchFailureType
16+
import util.SrcPos
1517

1618
class HealType(pos: SrcPos)(using Context) extends TypeMap {
1719

@@ -98,9 +100,7 @@ class HealType(pos: SrcPos)(using Context) extends TypeMap {
98100
pos)
99101
tp
100102
case _ =>
101-
report.error(em"""Reference to $tp within quotes requires a given $reqType in scope.
102-
|
103-
|""", pos)
103+
report.error(QuotedTypeMissing(tp), pos)
104104
tp
105105
}
106106

tests/neg/i21696.check

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- [E202] Staging Issue Error: tests/neg/i21696.scala:7:52 -------------------------------------------------------------
2+
7 |def foo[T](using Quotes): Expr[Thing[T]] = '{ Thing[T]() } // error
3+
| ^
4+
| Reference to T within quotes requires a given scala.quoted.Type[T] in scope
5+
|---------------------------------------------------------------------------------------------------------------------
6+
| Explanation (enabled by `-explain`)
7+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8+
| Referencing `T` inside a quoted expression requires a `scala.quoted.Type[T]` to be in scope.
9+
| Since Scala is subject to erasure at runtime, the type information will be missing during the execution of the code.
10+
| `scala.quoted.Type[T]` is therefore needed to carry `T`'s type information into the quoted code.
11+
| Without an implicit `scala.quoted.Type[T]`, the type `T` cannot be properly referenced within the expression.
12+
| To resolve this, ensure that a `scala.quoted.Type[T]` is available, either through a context-bound or explicitly.
13+
---------------------------------------------------------------------------------------------------------------------

tests/neg/i21696.scala

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//> using options -explain
2+
3+
import scala.quoted.{Expr, Quotes}
4+
5+
case class Thing[T]()
6+
7+
def foo[T](using Quotes): Expr[Thing[T]] = '{ Thing[T]() } // error

0 commit comments

Comments
 (0)