Skip to content

Commit f03d0a3

Browse files
committed
Use new syntax
1 parent f6b48a5 commit f03d0a3

File tree

14 files changed

+45
-89
lines changed

14 files changed

+45
-89
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
103103
}
104104
case class Throw(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
105105
case class Quote(quoted: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
106-
case class Splice(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
106+
case class Splice(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree {
107+
def isInBrackets: Boolean = span.end != expr.span.end
108+
}
107109
case class TypSplice(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TypTree
108110
case class ForYield(enums: List[Tree], expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
109111
case class ForDo(enums: List[Tree], body: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree

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

Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -119,43 +119,27 @@ trait QuotesAndSplices {
119119
def typedAppliedSplice(tree: untpd.Apply, pt: Type)(using Context): Tree = {
120120
assert(ctx.mode.is(Mode.QuotedPattern))
121121
val untpd.Apply(splice: untpd.Splice, args) = tree
122-
if args.forall(_.isInstanceOf[untpd.Ident]) then
123-
val suggestionArgs = args match
124-
case arg :: Nil => arg.show
125-
case args => args.map(_.show).mkString("(", ", ", ")")
126-
val suggestion = s"$${${splice.expr.show}}{$suggestionArgs}"
127-
ctx.warning(s"""Possibly using open pattern syntax instead application pattern.
128-
|If this is a open pattern replace it with $suggestion.
129-
|""".stripMargin, tree.sourcePos)
130-
object HigherOrderQuasipatternArgs {
131-
/** Matches a args of splice of the form `${body}{<args*>}` */
132-
def unapply(args: List[untpd.Tree]): Option[List[untpd.Tree]] = args match
133-
case Block(Nil, untpd.Tuple(args)) :: Nil => Some(args)
134-
case Block(Nil, arg) :: Nil => Some(List(arg))
135-
case _ => None
136-
}
137122
if !isFullyDefined(pt, ForceDegree.flipBottom) then
138123
ctx.error(i"Type must be fully defined.", splice.sourcePos)
139124
tree.withType(UnspecifiedErrorType)
140-
else args match
141-
case HigherOrderQuasipatternArgs(args) =>
142-
val typedArgs = args.map {
143-
case arg: untpd.Ident =>
144-
typedExpr(arg)
145-
case arg =>
146-
ctx.error("Exprected an identifier", arg.sourcePos)
147-
EmptyTree
148-
}
149-
if args.isEmpty then
150-
ctx.error("Missing arguments for open pattern", tree.sourcePos)
151-
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
152-
val typedPat = typedSplice(splice, defn.FunctionOf(argTypes, pt))
153-
ref(defn.InternalQuotedMatcher_patternHigherOrderHole).appliedToType(pt).appliedTo(typedPat, SeqLiteral(typedArgs, TypeTree(defn.AnyType)))
154-
case _ =>
155-
val typedArgs = args.map(arg => typedExpr(arg))
156-
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
157-
val splice1 = typedSplice(splice, defn.FunctionOf(argTypes, pt))
158-
Apply(splice1.select(nme.apply), typedArgs).withType(pt).withSpan(tree.span)
125+
else if splice.isInBrackets then // ${x}(...) match an application
126+
val typedArgs = args.map(arg => typedExpr(arg))
127+
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
128+
val splice1 = typedSplice(splice, defn.FunctionOf(argTypes, pt))
129+
Apply(splice1.select(nme.apply), typedArgs).withType(pt).withSpan(tree.span)
130+
else // $x(...) higher-order quasipattern
131+
val typedArgs = args.map {
132+
case arg: untpd.Ident =>
133+
typedExpr(arg)
134+
case arg =>
135+
ctx.error("Open patttern exprected an identifier", arg.sourcePos)
136+
EmptyTree
137+
}
138+
if args.isEmpty then
139+
ctx.error("Missing arguments for open pattern", tree.sourcePos)
140+
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
141+
val typedPat = typedSplice(splice, defn.FunctionOf(argTypes, pt))
142+
ref(defn.InternalQuotedMatcher_patternHigherOrderHole).appliedToType(pt).appliedTo(typedPat, SeqLiteral(typedArgs, TypeTree(defn.AnyType)))
159143
}
160144

161145
/** Translate ${ t: Type[T] }` into type `t.splice` while tracking the quotation level in the context */

docs/docs/reference/metaprogramming/macros.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -757,17 +757,17 @@ then the rest of the quote can refer to this definition.
757757

758758
To match such a term we need to match the definition and the rest of the code, but we need to expicilty state that the rest of the code may refer to this definition.
759759
```scala
760-
case '{ val y: Int = $x; ${body}{y}: Int } =>
760+
case '{ val y: Int = $x; $body(y): Int } =>
761761
```
762-
Here `$x` will match any closed expression while `${body}{y}` will match expression that is closed under `y`. Then
762+
Here `$x` will match any closed expression while `$body(y)` will match expression that is closed under `y`. Then
763763
the subxpression of type `Expr[Int]` is bound to `body` as an `Expr[Int => Int]`. The extra argument represents the references to `y`. Usually this expression is used in compination with `Expr.betaReduce` to replace the extra argument.
764764

765765
```scala
766766
inline def eval(inline e: Int): Int = ${ evalExpr('e) }
767767

768768
private def evalExpr(using QuoteContext)(e: Expr[Int]): Expr[Int] = {
769769
e match {
770-
case '{ val y: Int = $x; ${body}{y}: Int } =>
770+
case '{ val y: Int = $x; $body(y): Int } =>
771771
// body: Expr[Int => Int] where the argument represents references to y
772772
evalExpr(Expr.betaReduce(body)(evalExpr(x)))
773773
case '{ ($x: Int) * ($y: Int) } =>
@@ -786,7 +786,8 @@ eval { // expands to the code: (16: Int)
786786
}
787787
```
788788

789-
We can also close over several bindings using `${b}{(a1, a2, ..., an)}`.
789+
We can also close over several bindings using `$b(a1, a2, ..., an)`.
790+
To match an actual application we can use brackets on the function part `${b}(a1, a2, ..., an)`.
790791

791792

792793
### More details

library/src/scala/internal/quoted/Matcher.scala

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ import scala.quoted._
9797
*/
9898
object Matcher {
9999

100-
// TODO move to internal.Quoted.Matcher
101100
/** A splice in a quoted pattern is desugared by the compiler into a call to this method */
102101
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternHole`")
103102
def patternHole[T]: T = ???
@@ -106,7 +105,6 @@ object Matcher {
106105
/** A higher order splice in a quoted pattern is desugared by the compiler into a call to this method */
107106
def patternHigherOrderHole[U](pat: Any, args: Any*): U = ???
108107

109-
// TODO move to internal.Quoted.Matcher
110108
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.higherOrderHole`")
111109
/** A higher order splice in a quoted pattern is desugared by the compiler into a call to this method */
112110
def higherOrderHole[U](args: Any*): U = ???
@@ -116,12 +114,10 @@ object Matcher {
116114
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternBindHole`")
117115
class patternBindHole extends Annotation
118116

119-
// TODO move to internal.Quoted.Matcher
120117
/** A splice of a name in a quoted pattern is that marks the definition of a type splice */
121118
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternType`")
122119
class patternType extends Annotation
123120

124-
// TODO move to internal.Quoted.Matcher
125121
/** A type pattern that must be aproximated from above */
126122
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.fromAbove`")
127123
class fromAbove extends Annotation
@@ -268,27 +264,6 @@ object Matcher {
268264
scrutinee.tpe <:< tpt.tpe =>
269265
matched(scrutinee.seal)
270266

271-
/* Higher order term hole */
272-
// Matches an open term and wraps it into a lambda that provides the free variables
273-
// DEPRECATED: replaced with `higherOrderHole`
274-
// TODO: remove case
275-
case (scrutinee, pattern @ Apply(Select(TypeApply(patternHole, List(Inferred())), "apply"), args0 @ IdentArgs(args)))
276-
if patternHole.symbol == internal.Definitions_InternalQuotedMatcher_patternHole =>
277-
def bodyFn(lambdaArgs: List[Tree]): Tree = {
278-
val argsMap = args.map(_.symbol).zip(lambdaArgs.asInstanceOf[List[Term]]).toMap
279-
new TreeMap {
280-
override def transformTerm(tree: Term)(using ctx: Context): Term =
281-
tree match
282-
case tree: Ident => summon[Env].get(tree.symbol).flatMap(argsMap.get).getOrElse(tree)
283-
case tree => super.transformTerm(tree)
284-
}.transformTree(scrutinee)
285-
}
286-
val names = args.map(_.name)
287-
val argTypes = args0.map(x => x.tpe.widenTermRefExpr)
288-
val resType = pattern.tpe
289-
val res = Lambda(MethodType(names)(_ => argTypes, _ => resType), bodyFn)
290-
matched(res.seal)
291-
292267
/* Higher order term hole */
293268
// Matches an open term and wraps it into a lambda that provides the free variables
294269
case (scrutinee, pattern @ Apply(TypeApply(Ident("higherOrderHole"), List(Inferred())), Repeated(args, _) :: Nil))

tests/neg-custom-args/fatal-warnings/quoted-pattern-old-open-expr.scala

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import scala.quoted._
22

33
def f(using QuoteContext)(x: Expr[Any]) = x match {
4-
case '{ identity(${y}{x}) } => // error: access to value x from wrong staging level
4+
case '{ identity($y(x)) } => // error: access to value x from wrong staging level
55
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import scala.quoted._
22

33
def f(using QuoteContext)(x: Expr[Any]) = x match {
4-
case '{ val a: Int = 3; ${y}{identity(a)} } => // error: Exprected an identifier
5-
case '{ identity(${y}{()}) } => // error: Missing arguments for open pattern
4+
case '{ val a: Int = 3; $y(identity(a)) } => // error: Exprected an identifier
5+
case '{ identity($y()) } => // error: Missing arguments for open pattern
66
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import scala.quoted._
22

33
def f(x: Expr[Int])(using QuoteContext) = x match {
4-
case '{ $f($a: Int): Int } =>
4+
case '{ ${f}($a: Int): Int } =>
55
val f1: Expr[Int => Int] = f
66
val a1: Expr[Int] = a
7-
case '{ def a: Int = $f($b: Int); () } =>
7+
case '{ def a: Int = ${f}($b: Int); () } =>
88
val f1: Expr[Int => Int] = f
99
val b1: Expr[Int] = b
10-
case '{ val a: Int = 3; $f(a): Int } =>
10+
case '{ val a: Int = 3; ${f}(a): Int } =>
1111
val f1: Expr[Int => Int] = f
1212
}

tests/run-macros/quote-matcher-symantics-2/quoted_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ object Macros {
2020

2121
case '{ ($x: DSL) * ($y: DSL) } => sym.times(lift(x), lift(y))
2222

23-
case '{ $f($x: DSL): DSL } => sym.app(liftFun(f), lift(x))
23+
case '{ ${f}($x: DSL): DSL } => sym.app(liftFun(f), lift(x))
2424

2525
case '{ val x: DSL = $value; $bodyFn(x): DSL } =>
2626
UnsafeExpr.open(bodyFn) { (body1, close) =>

tests/run-macros/quote-matcher-symantics-3/quoted_1.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,23 @@ object Macros {
3939
case '{ ($x: Int) <= ($y: Int) } =>
4040
'{ $sym.leq(${lift(x)}, ${lift(y)}).asInstanceOf[R[T]] }
4141

42-
case '{ $f($arg: $t): $u } =>
42+
case '{ ${f}($arg: $t): $u } =>
4343
'{ $sym.app[$t, $u](${lift(f)}, ${lift(arg)}).asInstanceOf[R[T]] }
4444

4545
case '{ (if ($cond) $thenp else $elsep): $t } =>
4646
'{ $sym.ifThenElse[$t](${lift(cond)}, ${lift(thenp)}, ${lift(elsep)}) }.asInstanceOf[Expr[R[T]]]
4747

48-
case '{ (x0: Int) => ${bodyFn}{x0}: Any } =>
48+
case '{ (x0: Int) => $bodyFn(x0): Any } =>
4949
val (i, nEnvVar) = freshEnvVar[Int]()
5050
val body2 = UnsafeExpr.open(bodyFn) { (body1, close) => close(body1)(nEnvVar) }
5151
'{ $sym.lam((x: R[Int]) => ${given Env = envWith(i, 'x)(using env); lift(body2)}).asInstanceOf[R[T]] }
5252

53-
case '{ (x0: Boolean) => ${bodyFn}{x0}: Any } =>
53+
case '{ (x0: Boolean) => $bodyFn(x0): Any } =>
5454
val (i, nEnvVar) = freshEnvVar[Boolean]()
5555
val body2 = UnsafeExpr.open(bodyFn) { (body1, close) => close(body1)(nEnvVar) }
5656
'{ $sym.lam((x: R[Boolean]) => ${given Env = envWith(i, 'x)(using env); lift(body2)}).asInstanceOf[R[T]] }
5757

58-
case '{ (x0: Int => Int) => ${bodyFn}{x0}: Any } =>
58+
case '{ (x0: Int => Int) => $bodyFn(x0): Any } =>
5959
val (i, nEnvVar) = freshEnvVar[Int => Int]()
6060
val body2 = UnsafeExpr.open(bodyFn) { (body1, close) => close(body1)(nEnvVar) }
6161
'{ $sym.lam((x: R[Int => Int]) => ${given Env = envWith(i, 'x)(using env); lift(body2)}).asInstanceOf[R[T]] }

tests/run-macros/quote-matching-open/Macro_1.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ object Macro {
66

77
def impl(x: Expr[Any])(using QuoteContext): Expr[Any] = {
88
x match {
9-
case '{ (x: Int) => ${body}{x}: Int } => UnsafeExpr.open(body) { (body, close) => close(body)(Expr(2)) }
10-
case '{ (x1: Int, x2: Int) => ${body}{(x1, x2)}: Int } => UnsafeExpr.open(body) { (body, close) => close(body)(Expr(2), Expr(3)) }
11-
case '{ (x1: Int, x2: Int, x3: Int) => ${body}{(x1, x2, x3)}: Int } => UnsafeExpr.open(body) { (body, close) => close(body)(Expr(2), Expr(3), Expr(4)) }
9+
case '{ (x: Int) => $body(x): Int } => UnsafeExpr.open(body) { (body, close) => close(body)(Expr(2)) }
10+
case '{ (x1: Int, x2: Int) => $body(x1, x2): Int } => UnsafeExpr.open(body) { (body, close) => close(body)(Expr(2), Expr(3)) }
11+
case '{ (x1: Int, x2: Int, x3: Int) => $body(x1, x2, x3): Int } => UnsafeExpr.open(body) { (body, close) => close(body)(Expr(2), Expr(3), Expr(4)) }
1212
}
1313
}
1414

tests/run-macros/quoted-pattern-open-expr-0/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ inline def test(inline e: Int): String = ${testExpr('e)}
44

55
private def testExpr(e: Expr[Int])(using QuoteContext): Expr[String] = {
66
e match {
7-
case '{ val y: Int = 4; ${body}{y}: Int } => Expr("Matched open\n" + body.show)
7+
case '{ val y: Int = 4; $body(y): Int } => Expr("Matched open\n" + body.show)
88
}
99
}

tests/run-macros/quoted-pattern-open-expr-simple-eval/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ inline def eval(inline e: Int): Int = ${ evalExpr('e) }
44

55
private def evalExpr(using QuoteContext)(e: Expr[Int]): Expr[Int] = {
66
e match {
7-
case '{ val y: Int = $x; ${body}{y}: Int } =>
7+
case '{ val y: Int = $x; $body(y): Int } =>
88
evalExpr(Expr.betaReduce(body)(evalExpr(x)))
99
case '{ ($x: Int) * ($y: Int) } =>
1010
(x, y) match

tests/run-macros/quoted-pattern-open-expr/Macro_1.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ inline def test(inline e: Int): String = ${testExpr('e)}
55
private def testExpr(e: Expr[Int])(using QuoteContext): Expr[String] = {
66
e match {
77
case '{ val y: Int = 4; $body } => Expr("Matched closed\n" + body.show)
8-
case '{ val y: Int = 4; ${body}{y}: Int } => Expr("Matched open\n" + body.show)
9-
case '{ val y: Int => Int = x => x + 1; ${body}{y}: Int } => Expr("Matched open\n" + body.show)
10-
case '{ def g(x: Int): Int = ${body}{(g, x)}; g(5) } => Expr("Matched open\n" + body.show)
8+
case '{ val y: Int = 4; $body(y): Int } => Expr("Matched open\n" + body.show)
9+
case '{ val y: Int => Int = x => x + 1; $body(y): Int } => Expr("Matched open\n" + body.show)
10+
case '{ def g(x: Int): Int = $body(g, x); g(5) } => Expr("Matched open\n" + body.show)
1111
}
1212
}

0 commit comments

Comments
 (0)