Skip to content

Commit

Permalink
Compile quote patterns directly into QuotePattern AST
Browse files Browse the repository at this point in the history
Fixes #18125
  • Loading branch information
nicolasstucki committed Jul 4, 2023
1 parent 8abb383 commit cb2bdff
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 302 deletions.
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ object desugar {
tree match
case untpd.Block(stats, expr) =>
val (untpdTypeVariables, otherStats) = stats.span {
case tdef @ untpd.TypeDef(name, _) => name.isVarPattern
case tdef @ untpd.TypeDef(name, _) => !tdef.isBackquoted && name.isVarPattern
case _ => false
}
val pattern = if otherStats.isEmpty then expr else untpd.cpy.Block(tree)(otherStats, expr)
Expand Down
28 changes: 28 additions & 0 deletions compiler/src/dotty/tools/dotc/quoted/QuotePatterns.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import dotty.tools.dotc.core.NameKinds.PatMatGivenVarName
import dotty.tools.dotc.core.Names.*
import dotty.tools.dotc.core.StdNames.*
import dotty.tools.dotc.core.Symbols.*
import dotty.tools.dotc.core.TypeOps.*
import dotty.tools.dotc.core.Types.*
import dotty.tools.dotc.reporting.IllegalVariableInPatternAlternative
import dotty.tools.dotc.transform.SymUtils._
Expand All @@ -24,6 +25,33 @@ import scala.collection.mutable
object QuotePatterns:
import tpd._

/** Check for restricted patterns */
def checkPattern(quotePattern: QuotePattern)(using Context): Unit = new tpd.TreeTraverser {
def traverse(tree: Tree)(using Context): Unit = tree match {
case _: SplicePattern =>
case tdef: TypeDef if tdef.symbol.isClass =>
val kind = if tdef.symbol.is(Module) then "objects" else "classes"
report.error(em"Implementation restriction: cannot match $kind", tree.srcPos)
case tree: NamedDefTree =>
if tree.name.is(NameKinds.WildcardParamName) then
report.warning(
"Use of `_` for lambda in quoted pattern. Use explicit lambda instead or use `$_` to match any term.",
tree.srcPos)
if tree.name.isTermName && !tree.nameSpan.isSynthetic && tree.name != nme.ANON_FUN && tree.name.startsWith("$") then
report.error("Names cannot start with $ quote pattern", tree.namePos)
traverseChildren(tree)
case _: Match =>
report.error("Implementation restriction: cannot match `match` expressions", tree.srcPos)
case _: Try =>
report.error("Implementation restriction: cannot match `try` expressions", tree.srcPos)
case _: Return =>
report.error("Implementation restriction: cannot match `return` statements", tree.srcPos)
case _ =>
traverseChildren(tree)
}

}.traverse(quotePattern.body)

/** Encode the quote pattern into an `unapply` that the pattern matcher can handle.
*
* A quote pattern
Expand Down
367 changes: 67 additions & 300 deletions compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion tests/neg-macros/i6997b.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import scala.quoted.*
inline def mcr(x: => Any): Any = ${mcrImpl('x)}

def mcrImpl(body: Expr[Any])(using ctx: Quotes): Expr[Any] = {
val '{$x: $t} = body // error
val '{$x: $t} = body // error // error
'{
val tmp: $t = $x.asInstanceOf[$t] // error // error
println(tmp)
Expand Down
10 changes: 10 additions & 0 deletions tests/pos-macros/i18125.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import scala.quoted.*

final class Foo[T](ns: T)

def foo(using Quotes)(x: Expr[Any]): Unit =
x match
case '{ new Foo($y: b) } =>
case '{ new Foo($y: List[b]) } =>
case '{ type b; new Foo($y: b) } =>

23 changes: 23 additions & 0 deletions tests/pos-macros/i18125b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package oolong.phobos

import scala.quoted.*
import scala.compiletime.*
import scala.annotation.StaticAnnotation

final class xmlns[T](ns: T) extends StaticAnnotation
trait Namespace[T]{
val getNamespace: String
}

object common{
private def extractFeildNamespace(using Quotes)(
fieldAnnotations: List[Expr[Any]],
): Expr[Option[String]] = {
import quotes.reflect.*

fieldAnnotations.collect { case '{ xmlns($namespace: b) } =>
'{ Some(summonInline[Namespace[b]].getNamespace) }
}
???
}
}
11 changes: 11 additions & 0 deletions tests/pos-macros/mirrorQuotePattern.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import scala.deriving._
import scala.quoted._

private def derivedExpr[T](mirrorExpr: Expr[Mirror.Of[T]])(using Quotes, Type[T]): Expr[Any] = {
mirrorExpr match {
case '{ $mirrorExpr : Mirror.Sum { type MirroredElemTypes = mirroredElemTypes } } =>
'{ liftableSum[mirroredElemTypes]($mirrorExpr) }
}
}

def liftableSum[MElemTypes](mirror: Mirror.Sum { type MirroredElemTypes = MElemTypes }): Any = ???

0 comments on commit cb2bdff

Please sign in to comment.