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

Have a better error message when healing types #21711

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/MessageKind.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
20 changes: 20 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) = {
Expand Down Expand Up @@ -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
26 changes: 13 additions & 13 deletions compiler/src/dotty/tools/dotc/staging/HealType.scala
Original file line number Diff line number Diff line change
@@ -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 {

Expand Down Expand Up @@ -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
}

Expand Down
13 changes: 13 additions & 0 deletions tests/neg/i21696.check
Original file line number Diff line number Diff line change
@@ -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.
---------------------------------------------------------------------------------------------------------------------
7 changes: 7 additions & 0 deletions tests/neg/i21696.scala
Original file line number Diff line number Diff line change
@@ -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
Loading