Skip to content

Commit 62d64b7

Browse files
committed
Compile quote patterns directly into QuotePattern AST
Fixes #14708 Fixes #18125
1 parent 8abb383 commit 62d64b7

File tree

8 files changed

+156
-300
lines changed

8 files changed

+156
-300
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ object desugar {
381381
tree match
382382
case untpd.Block(stats, expr) =>
383383
val (untpdTypeVariables, otherStats) = stats.span {
384-
case tdef @ untpd.TypeDef(name, _) => name.isVarPattern
384+
case tdef @ untpd.TypeDef(name, _) => !tdef.isBackquoted && name.isVarPattern
385385
case _ => false
386386
}
387387
val pattern = if otherStats.isEmpty then expr else untpd.cpy.Block(tree)(otherStats, expr)

compiler/src/dotty/tools/dotc/quoted/QuotePatterns.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import dotty.tools.dotc.core.NameKinds.PatMatGivenVarName
1515
import dotty.tools.dotc.core.Names.*
1616
import dotty.tools.dotc.core.StdNames.*
1717
import dotty.tools.dotc.core.Symbols.*
18+
import dotty.tools.dotc.core.TypeOps.*
1819
import dotty.tools.dotc.core.Types.*
1920
import dotty.tools.dotc.reporting.IllegalVariableInPatternAlternative
2021
import dotty.tools.dotc.transform.SymUtils._
@@ -24,6 +25,33 @@ import scala.collection.mutable
2425
object QuotePatterns:
2526
import tpd._
2627

28+
/** Check for restricted patterns */
29+
def checkPattern(quotePattern: QuotePattern)(using Context): Unit = new tpd.TreeTraverser {
30+
def traverse(tree: Tree)(using Context): Unit = tree match {
31+
case _: SplicePattern =>
32+
case tdef: TypeDef if tdef.symbol.isClass =>
33+
val kind = if tdef.symbol.is(Module) then "objects" else "classes"
34+
report.error(em"Implementation restriction: cannot match $kind", tree.srcPos)
35+
case tree: NamedDefTree =>
36+
if tree.name.is(NameKinds.WildcardParamName) then
37+
report.warning(
38+
"Use of `_` for lambda in quoted pattern. Use explicit lambda instead or use `$_` to match any term.",
39+
tree.srcPos)
40+
if tree.name.isTermName && !tree.nameSpan.isSynthetic && tree.name != nme.ANON_FUN && tree.name.startsWith("$") then
41+
report.error("Names cannot start with $ quote pattern", tree.namePos)
42+
traverseChildren(tree)
43+
case _: Match =>
44+
report.error("Implementation restriction: cannot match `match` expressions", tree.srcPos)
45+
case _: Try =>
46+
report.error("Implementation restriction: cannot match `try` expressions", tree.srcPos)
47+
case _: Return =>
48+
report.error("Implementation restriction: cannot match `return` statements", tree.srcPos)
49+
case _ =>
50+
traverseChildren(tree)
51+
}
52+
53+
}.traverse(quotePattern.body)
54+
2755
/** Encode the quote pattern into an `unapply` that the pattern matcher can handle.
2856
*
2957
* A quote pattern

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

Lines changed: 70 additions & 298 deletions
Large diffs are not rendered by default.

tests/neg-macros/i6997b.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import scala.quoted.*
55
inline def mcr(x: => Any): Any = ${mcrImpl('x)}
66

77
def mcrImpl(body: Expr[Any])(using ctx: Quotes): Expr[Any] = {
8-
val '{$x: $t} = body // error
8+
val '{$x: $t} = body // error // error
99
'{
1010
val tmp: $t = $x.asInstanceOf[$t] // error // error
1111
println(tmp)

tests/pos-macros/i14708.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import scala.quoted.*
2+
3+
object Main {
4+
def foo(a: Expr[Any])(using Quotes) = {
5+
a match {
6+
case '{ ($x: Set[t]).toSet } =>
7+
case _ =>
8+
}
9+
}
10+
}

tests/pos-macros/i18125.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import scala.quoted.*
2+
3+
final class Foo[T](ns: T)
4+
5+
def foo(using Quotes)(x: Expr[Any]): Unit =
6+
x match
7+
case '{ new Foo($y: b) } =>
8+
case '{ new Foo($y: List[b]) } =>
9+
case '{ type b; new Foo($y: b) } =>
10+

tests/pos-macros/i18125b.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package oolong.phobos
2+
3+
import scala.quoted.*
4+
import scala.compiletime.*
5+
import scala.annotation.StaticAnnotation
6+
7+
final class xmlns[T](ns: T) extends StaticAnnotation
8+
trait Namespace[T]{
9+
val getNamespace: String
10+
}
11+
12+
object common{
13+
private def extractFeildNamespace(using Quotes)(
14+
fieldAnnotations: List[Expr[Any]],
15+
): Expr[Option[String]] = {
16+
import quotes.reflect.*
17+
18+
fieldAnnotations.collect { case '{ xmlns($namespace: b) } =>
19+
'{ Some(summonInline[Namespace[b]].getNamespace) }
20+
}
21+
???
22+
}
23+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import scala.deriving._
2+
import scala.quoted._
3+
4+
private def derivedExpr[T](mirrorExpr: Expr[Mirror.Of[T]])(using Quotes, Type[T]): Expr[Any] = {
5+
mirrorExpr match {
6+
case '{ $mirrorExpr : Mirror.Sum { type MirroredElemTypes = mirroredElemTypes } } =>
7+
'{ liftableSum[mirroredElemTypes]($mirrorExpr) }
8+
case '{ type mirroredElemTypes; $mirrorExpr : Mirror.Sum { type MirroredElemTypes = mirroredElemTypes } } =>
9+
'{ liftableSum[mirroredElemTypes]($mirrorExpr) }
10+
}
11+
}
12+
13+
def liftableSum[MElemTypes](mirror: Mirror.Sum { type MirroredElemTypes = MElemTypes }): Any = ???

0 commit comments

Comments
 (0)