Skip to content

Commit bd869f1

Browse files
mbovelWojciechMazur
authored andcommitted
Emit an error for quoted pattern type variable after new
[Cherry-picked 05b26be]
1 parent 482959b commit bd869f1

File tree

6 files changed

+51
-1
lines changed

6 files changed

+51
-1
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
232232
case UnnecessaryNN // errorNumber: 216
233233
case ErasedNotPureID // errorNumber: 217
234234
case IllegalErasedDefID // errorNumber: 218
235+
case CannotInstantiateQuotedTypeVarID // errorNumber: 219
235236

236237
def errorNumber = ordinal - 1
237238

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3435,6 +3435,18 @@ final class QuotedTypeMissing(tpe: Type)(using Context) extends StagingMessage(Q
34353435

34363436
end QuotedTypeMissing
34373437

3438+
final class CannotInstantiateQuotedTypeVar(symbol: Symbol)(using patternCtx: Context) extends StagingMessage(CannotInstantiateQuotedTypeVarID):
3439+
override protected def msg(using Context): String =
3440+
i"""Quoted pattern type variable `${symbol.name}` cannot be instantiated.
3441+
|If you meant to refer to a class named `${symbol.name}`, wrap it in backticks.
3442+
|If you meant to introduce a binding, this is not allowed after `new`. You might
3443+
|want to use the lower-level `quotes.reflect` API instead.
3444+
|Read more about type variables in quoted pattern in the Scala documentation:
3445+
|https://docs.scala-lang.org/scala3/guides/macros/quotes.html#type-variables-in-quoted-patterns
3446+
"""
3447+
3448+
override protected def explain(using Context): String = ""
3449+
34383450
final class DeprecatedAssignmentSyntax(key: Name, value: untpd.Tree)(using Context) extends SyntaxMsg(DeprecatedAssignmentSyntaxID):
34393451
override protected def msg(using Context): String =
34403452
i"""Deprecated syntax: since 3.7 this is interpreted as a named tuple with one element,

compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ trait QuotesAndSplices {
222222
if ctx.mode.is(Mode.InPatternAlternative) then
223223
report.error(IllegalVariableInPatternAlternative(tree.name), tree.srcPos)
224224
val typeSym = inContext(quotePatternOuterContext(ctx)) {
225-
newSymbol(ctx.owner, tree.name.toTypeName, Case, typeSymInfo, NoSymbol, tree.span)
225+
newSymbol(ctx.owner, tree.name.toTypeName, Synthetic | Case, typeSymInfo, NoSymbol, tree.span)
226226
}
227227
addQuotedPatternTypeVariable(typeSym)
228228
Bind(typeSym, untpd.Ident(nme.WILDCARD).withType(typeSymInfo)).withSpan(tree.span)

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
12371237
case _ =>
12381238
var tpt1 = typedType(tree.tpt)
12391239
val tsym = tpt1.tpe.underlyingClassRef(refinementOK = false).typeSymbol
1240+
if ctx.mode.isQuotedPattern && tpt1.tpe.typeSymbol.isAllOf(Synthetic | Case) then
1241+
val errorTp = errorType(CannotInstantiateQuotedTypeVar(tpt1.tpe.typeSymbol), tpt1.srcPos)
1242+
return cpy.New(tree)(tpt1).withType(errorTp)
12401243
if tsym.is(Package) then
12411244
report error(em"$tsym cannot be instantiated", tpt1.srcPos)
12421245
tpt1 = tpt1.withType(ensureAccessible(tpt1.tpe, superAccess = false, tpt1.srcPos))

tests/neg-macros/i22616.check

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-- [E219] Staging Issue Error: tests/neg-macros/i22616.scala:13:22 -----------------------------------------------------
2+
13 | case '{ new caseName(${ Expr(name) }) } => Some(caseName(name)) // error // error
3+
| ^^^^^^^^
4+
| Quoted pattern type variable `caseName` cannot be instantiated.
5+
| If you meant to refer to a class named `caseName`, wrap it in backticks.
6+
| If you meant to introduce a binding, this is not allowed after `new`. You might
7+
| want to use the lower-level `quotes.reflect` API instead.
8+
| Read more about type variables in quoted pattern in the Scala documentation:
9+
| https://docs.scala-lang.org/scala3/guides/macros/quotes.html#type-variables-in-quoted-patterns
10+
|
11+
-- [E006] Not Found Error: tests/neg-macros/i22616.scala:13:67 ---------------------------------------------------------
12+
13 | case '{ new caseName(${ Expr(name) }) } => Some(caseName(name)) // error // error
13+
| ^^^^
14+
| Not found: name
15+
|
16+
| longer explanation available when compiling with `-explain`

tests/neg-macros/i22616.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import scala.quoted.*
2+
3+
final case class caseName(name: String) extends scala.annotation.Annotation
4+
object caseName {
5+
6+
given FromExpr[caseName] =
7+
new FromExpr[caseName] {
8+
override def unapply(x: Expr[caseName])(using Quotes): Option[caseName] =
9+
val y: Int = 42
10+
x match {
11+
case '{ caseName(${ Expr(name) }) } => Some(caseName(name))
12+
// with/without the following line...
13+
case '{ new caseName(${ Expr(name) }) } => Some(caseName(name)) // error // error
14+
case _ => println(x.show); None
15+
}
16+
}
17+
18+
}

0 commit comments

Comments
 (0)