Skip to content

Commit 9d45597

Browse files
authored
Merge pull request #541 from scala/backport-lts-3.3-23618
Backport "Emit an error for quoted pattern type variable after `new`" to 3.3 LTS
2 parents 8925be8 + 49a9b53 commit 9d45597

File tree

9 files changed

+108
-0
lines changed

9 files changed

+108
-0
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
229229
case PointlessAppliedConstructorTypeID // errorNumber: 213
230230
case IllegalContextBoundsID // errorNumber: 214
231231
case NamedPatternNotApplicableID // errorNumber: 215
232+
case UnnecessaryNN // errorNumber: 216
233+
case ErasedNotPureID // errorNumber: 217
234+
case IllegalErasedDefID // errorNumber: 218
235+
case CannotInstantiateQuotedTypeVarID // errorNumber: 219
232236

233237
def errorNumber = ordinal - 1
234238

tests/neg-macros/i22616b.check

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- [E007] Type Mismatch Error: tests/neg-macros/i22616b.scala:17:18 ----------------------------------------------------
2+
17 | case '{ Foo($y: t) } => // error
3+
| ^^^^^
4+
| Found: t
5+
| Required: String
6+
|
7+
| longer explanation available when compiling with `-explain`
8+
-- [E006] Not Found Error: tests/neg-macros/i22616b.scala:18:19 --------------------------------------------------------
9+
18 | '{type S = t; ()} // error
10+
| ^
11+
| Not found: type t
12+
|
13+
| longer explanation available when compiling with `-explain`

tests/neg-macros/i22616b.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// This test illustrates a current limitation of quoted pattern type variables,
2+
// which has been discussed in https://github.com/scala/scala3/issues/22616#issuecomment-3012534064:
3+
// These type variables do not have bound in general (see `typedQuotedTypeVar`),
4+
// so they might not conform to the expected type. Here, `t` does not conform
5+
// to `String`.
6+
7+
import scala.quoted.{FromExpr, Expr, Quotes}
8+
9+
case class Foo(x: String)
10+
11+
object Macro:
12+
inline def myMacro(): Unit =
13+
${ myMacroImpl('{Foo("hello")}) }
14+
15+
def myMacroImpl(x: Expr[Foo])(using Quotes): Expr[Unit] =
16+
x match
17+
case '{ Foo($y: t) } => // error
18+
'{type S = t; ()} // error
19+
case _ =>
20+
println("not a foo")
21+
22+
'{()}

tests/run-macros/i22616c.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
_B_
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import scala.quoted.*
2+
3+
object Macro:
4+
inline def myMacro[T](): String =
5+
${ myMacroImpl[T]() }
6+
7+
def myMacroImpl[T: Type]()(using Quotes): Expr[String] =
8+
import quotes.reflect.*
9+
val myTypeRepr = MyTypeRepr(TypeRepr.of[T])
10+
val `caseName`(name) = myTypeRepr.requiredAnnotationValue[caseName]
11+
Expr(name)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import scala.quoted.*
2+
3+
final class MyTypeRepr(using val quotes: Quotes)(val unwrap: quotes.reflect.TypeRepr) {
4+
import quotes.reflect.*
5+
6+
def getAnnotation(annotTpe: quotes.reflect.Symbol): Option[quotes.reflect.Term] =
7+
unwrap.typeSymbol.getAnnotation(annotTpe)
8+
9+
def optionalAnnotation[Annot: Type]: Option[Expr[Annot]] = {
10+
val annotTpe = TypeRepr.of[Annot]
11+
val annotFlags = annotTpe.typeSymbol.flags
12+
13+
if (annotFlags.is(Flags.Abstract) || annotFlags.is(Flags.Trait))
14+
report.errorAndAbort(s"Bad annotation type ${annotTpe.show} is abstract")
15+
16+
this.getAnnotation(annotTpe.typeSymbol) match
17+
case Some(tree) if tree.tpe <:< annotTpe => Some(tree.asExprOf[Annot])
18+
case _ => None
19+
}
20+
21+
def requiredAnnotation[Annot: Type]: Expr[Annot] =
22+
optionalAnnotation[Annot].getOrElse(report.errorAndAbort(s"Missing required annotation `${TypeRepr.of[Annot].show}` for `$this`"))
23+
24+
def optionalAnnotationValue[Annot: {Type, FromExpr}]: Option[Annot] =
25+
optionalAnnotation[Annot].map { expr =>
26+
expr.value.getOrElse(report.errorAndAbort(s"Found annotation `${TypeRepr.of[Annot].show}` for `$this`, but are unable to extract Expr.value\n${expr.show}"))
27+
}
28+
29+
def requiredAnnotationValue[Annot: {Type, FromExpr}]: Annot = {
30+
val expr = requiredAnnotation[Annot]
31+
expr.value.getOrElse(report.errorAndAbort(s"Found annotation `${TypeRepr.of[Annot].show}` for `$this`, but are unable to extract Expr.value\n${expr.show}"))
32+
}
33+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
sealed trait SealedTrait3[+A, +B]
2+
object SealedTrait3 {
3+
final case class AB1[+B, +A](a: B, b: A) extends SealedTrait3[B, A]
4+
final case class AB2[+C, +D](a: C, b: D) extends SealedTrait3[D, C]
5+
final case class A[+T](a: T) extends SealedTrait3[T, Nothing]
6+
@caseName("_B_") final case class B[+T](b: T) extends SealedTrait3[Nothing, T]
7+
case object Neither extends SealedTrait3[Nothing, Nothing]
8+
}

tests/run-macros/i22616c/Test_5.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@main def Test =
2+
println(Macro.myMacro[SealedTrait3.B[Any]]())
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.quoted.*
2+
3+
final case class caseName(name: String) extends scala.annotation.Annotation
4+
object caseName {
5+
// This demonstrates a workaround for issue #22616.
6+
given FromExpr[caseName] =
7+
new FromExpr[caseName] {
8+
override def unapply(x: Expr[caseName])(using Quotes): Option[caseName] =
9+
x match {
10+
case '{ new `caseName`(${ Expr(name) }) } => Some(caseName(name))
11+
case _ => println(x.show); None
12+
}
13+
}
14+
}

0 commit comments

Comments
 (0)