Skip to content

Commit 667a565

Browse files
Merge pull request #14 from scala/backport-lts-3.3-21711
Backport "Have a better error message when healing types" to LTS
2 parents 59de925 + e57c77b commit 667a565

File tree

6 files changed

+57
-13
lines changed

6 files changed

+57
-13
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
214214
case UnusedSymbolID // errorNumber: 198
215215
case TailrecNestedCallID //errorNumber: 199 - unused in LTS
216216
case FinalLocalDefID // errorNumber: 200
217+
case NonNamedArgumentInJavaAnnotationID // errorNumber: 201 - unused in LTS
218+
case QuotedTypeMissingID // errorNumber: 202
217219

218220
def errorNumber = ordinal - 1
219221

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
@@ -107,6 +107,9 @@ end CyclicMsg
107107
abstract class ReferenceMsg(errorId: ErrorMessageID)(using Context) extends Message(errorId):
108108
def kind = MessageKind.Reference
109109

110+
abstract class StagingMessage(errorId: ErrorMessageID)(using Context) extends Message(errorId):
111+
override final def kind = MessageKind.Staging
112+
110113
abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(using Context)
111114
extends SyntaxMsg(errNo) {
112115
def explain(using Context) = {
@@ -3165,3 +3168,20 @@ object UnusedSymbol {
31653168
def privateMembers(using Context): UnusedSymbol = new UnusedSymbol(i"unused private member")
31663169
def patVars(using Context): UnusedSymbol = new UnusedSymbol(i"unused pattern variable")
31673170
}
3171+
3172+
final class QuotedTypeMissing(tpe: Type)(using Context) extends StagingMessage(QuotedTypeMissingID):
3173+
3174+
private def witness = defn.QuotedTypeClass.typeRef.appliedTo(tpe)
3175+
3176+
override protected def msg(using Context): String =
3177+
i"Reference to $tpe within quotes requires a given ${witness} in scope"
3178+
3179+
override protected def explain(using Context): String =
3180+
i"""Referencing `$tpe` inside a quoted expression requires a `${witness}` to be in scope.
3181+
|Since Scala is subject to erasure at runtime, the type information will be missing during the execution of the code.
3182+
|`${witness}` is therefore needed to carry `$tpe`'s type information into the quoted code.
3183+
|Without an implicit `${witness}`, the type `$tpe` cannot be properly referenced within the expression.
3184+
|To resolve this, ensure that a `${witness}` is available, either through a context-bound or explicitly.
3185+
|"""
3186+
3187+
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)