Skip to content

Commit 8c63097

Browse files
committed
Introduce Typed abstraction that supports patterns
1 parent 19a285a commit 8c63097

File tree

16 files changed

+131
-38
lines changed

16 files changed

+131
-38
lines changed

compiler/src/scala/quoted/runtime/impl/Matcher.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ object Matcher {
178178

179179
/* Term hole */
180180
// Match a scala.internal.Quoted.patternHole typed as a repeated argument and return the scrutinee tree
181-
case (scrutinee @ Typed(s: Term, tpt1), Typed(TypeApply(patternHole, tpt :: Nil), tpt2))
181+
case (scrutinee @ Typed(s, tpt1), Typed(TypeApply(patternHole, tpt :: Nil), tpt2))
182182
if patternHole.symbol == patternHoleSymbol &&
183183
s.tpe <:< tpt.tpe &&
184184
tpt2.tpe.derivesFrom(defn.RepeatedParamClass) =>

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

+37-2
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,18 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
333333

334334
object TermTypeTest extends TypeTest[Tree, Term]:
335335
def unapply(x: Tree): Option[Term & x.type] = x match
336+
case x: (tpd.Ident & x.type) =>
337+
if x.isTerm && x.name != nme.WILDCARD then Some(x)
338+
else None
339+
case x: (tpd.Typed & x.type) =>
340+
// Matches `Typed` butt not `TypedTree`
341+
TypedTypeTest.unapply(x)
336342
case x: (tpd.SeqLiteral & x.type) => Some(x)
337343
case x: (tpd.Inlined & x.type) => Some(x)
338344
case x: (tpd.NamedArg & x.type) => Some(x)
339-
case _ => if x.isTerm then Some(x) else None
345+
case _ =>
346+
if x.isTerm then Some(x)
347+
else None
340348
end TermTypeTest
341349

342350
object Term extends TermModule:
@@ -646,7 +654,10 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
646654

647655
object TypedTypeTest extends TypeTest[Tree, Typed]:
648656
def unapply(x: Tree): Option[Typed & x.type] = x match
649-
case x: (tpd.Typed & x.type) => Some(x)
657+
case x: (tpd.Typed & x.type) =>
658+
x.expr match
659+
case TermTypeTest(_) => Some(x)
660+
case _ => None
650661
case _ => None
651662
end TypedTypeTest
652663

@@ -1412,6 +1423,30 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
14121423
def unapply(pattern: Wildcard): true = true
14131424
end Wildcard
14141425

1426+
type TypedTree = tpd.Typed
1427+
1428+
object TypedTreeTypeTest extends TypeTest[Tree, TypedTree]:
1429+
def unapply(x: Tree): Option[TypedTree & x.type] = x match
1430+
case x: (tpd.Typed & x.type) => Some(x)
1431+
case _ => None
1432+
end TypedTreeTypeTest
1433+
1434+
object TypedTree extends TypedTreeModule:
1435+
def apply(expr: Term, tpt: TypeTree): Typed =
1436+
withDefaultPos(tpd.Typed(xCheckMacroValidExpr(expr), tpt))
1437+
def copy(original: Tree)(expr: Term, tpt: TypeTree): Typed =
1438+
tpd.cpy.Typed(original)(xCheckMacroValidExpr(expr), tpt)
1439+
def unapply(x: Typed): (Term, TypeTree) =
1440+
(x.expr, x.tpt)
1441+
end TypedTree
1442+
1443+
given TypedTreeMethods: TypedTreeMethods with
1444+
extension (self: Typed)
1445+
def tree: Tree = self.expr
1446+
def tpt: TypeTree = self.tpt
1447+
end extension
1448+
end TypedTreeMethods
1449+
14151450
type Bind = tpd.Bind
14161451

14171452
object BindTypeTest extends TypeTest[Tree, Bind]:

compiler/src/scala/quoted/runtime/impl/printers/Extractors.scala

+2
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ object Extractors {
173173
this += "Unapply(" += fun += ", " ++= implicits += ", " ++= patterns += ")"
174174
case Alternatives(patterns) =>
175175
this += "Alternatives(" ++= patterns += ")"
176+
case TypedTree(tree, tpt) =>
177+
this += "TypedTree(" += tree += ", " += tpt += ")"
176178
}
177179

178180
def visitConstant(x: Constant): this.type = x match {

compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala

+16-3
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,15 @@ object SourceCode {
453453
printTypeOrAnnots(tpt.tpe)
454454
}
455455
}
456+
case TypedTree(tree1, tpt) =>
457+
printPattern(tree1)
458+
tree1 match
459+
case Wildcard() =>
460+
this += ":"
461+
printType(tpt.tpe)
462+
case _ => // Alternatives, Unapply, Bind
463+
this
464+
456465

457466
case Assign(lhs, rhs) =>
458467
printTree(lhs)
@@ -928,9 +937,13 @@ object SourceCode {
928937
case Alternatives(trees) =>
929938
inParens(printPatterns(trees, " | "))
930939

931-
case Typed(Wildcard(), tpt) =>
932-
this += "_: "
933-
printTypeTree(tpt)
940+
case TypedTree(tree1, tpt) =>
941+
tree1 match
942+
case Wildcard() =>
943+
this += "_: "
944+
printTypeTree(tpt)
945+
case _ =>
946+
printPattern(tree1)
934947

935948
case v: Term =>
936949
printTree(v)

library/src/scala/quoted/ExprMap.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ trait ExprMap:
5656
tree
5757
case New(tpt) =>
5858
New.copy(tree)(transformTypeTree(tpt)(owner))
59-
case Typed(expr: Term, tpt) =>
59+
case Typed(expr, tpt) =>
6060
val tp = tpt.tpe match
6161
case AppliedType(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "<repeated>"), List(tp0: TypeRepr)) =>
6262
TypeRepr.of[Seq].appliedTo(tp0)

library/src/scala/quoted/FromExpr.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ object FromExpr {
8686
def rec(tree: Term): Option[T] = tree match {
8787
case Block(stats, e) => if stats.isEmpty then rec(e) else None
8888
case Inlined(_, bindings, e) => if bindings.isEmpty then rec(e) else None
89-
case Typed(e: Term, _) => rec(e)
89+
case Typed(e, _) => rec(e)
9090
case _ =>
9191
tree.tpe.widenTermRefByName match
9292
case ConstantType(c) => Some(c.value.asInstanceOf[T])

library/src/scala/quoted/Quotes.scala

+61-18
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
122122
* | +- Apply
123123
* | +- TypeApply
124124
* | +- Super
125-
* | +- Typed
126125
* | +- Assign
127126
* | +- Block
128127
* | +- Closure
@@ -135,7 +134,16 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
135134
* | +- Inlined
136135
* | +- SelectOuter
137136
* | +- While
137+
* | +---+- Typed
138+
* | /
139+
* +- TypedTree +------------------·
140+
* +- Wildcard
141+
* +- Bind
142+
* +- Unapply
143+
* +- Alternatives
138144
* |
145+
* +- CaseDef
146+
* +- TypeCaseDef
139147
* |
140148
* +- TypeTree ----+- Inferred
141149
* | +- TypeIdent
@@ -153,14 +161,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
153161
* |
154162
* +- TypeBoundsTree
155163
* +- WildcardTypeTree
156-
* |
157-
* +- CaseDef
158-
* |
159-
* +- TypeCaseDef
160-
* +- Wildcard
161-
* +- Bind
162-
* +- Unapply
163-
* +- Alternatives
164164
*
165165
* +- ParamClause -+- TypeParamClause
166166
* +- TermParamClause
@@ -1092,22 +1092,26 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
10921092
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `Typed` */
10931093
given TypedTypeTest: TypeTest[Tree, Typed]
10941094

1095-
/** Tree representing a type ascription `x: T` in the source code */
1096-
type Typed <: Term
1095+
/** Tree representing a type ascription `x: T` in the source code.
1096+
*
1097+
* Also represents a pattern that contains a term `x`.
1098+
* Other `: T` patterns use the more general `TypeTree`.
1099+
*/
1100+
type Typed <: Term & TypeTree
10971101

10981102
/** Module object of `type Typed` */
10991103
val Typed: TypedModule
11001104

11011105
/** Methods of the module object `val Typed` */
11021106
trait TypedModule { this: Typed.type =>
11031107

1104-
/** Create a type ascription `<x: Tree>: <tpt: TypeTree>` */
1105-
def apply(expr: Tree, tpt: TypeTree): Typed
1108+
/** Create a type ascription `<x: Term>: <tpt: TypeTree>` */
1109+
def apply(expr: Term, tpt: TypeTree): Typed
11061110

1107-
def copy(original: Tree)(expr: Tree, tpt: TypeTree): Typed
1111+
def copy(original: Tree)(expr: Term, tpt: TypeTree): Typed
11081112

1109-
/** Matches `<expr: Tree>: <tpt: TypeTree>` */
1110-
def unapply(x: Typed): (Tree, TypeTree)
1113+
/** Matches `<expr: Term>: <tpt: TypeTree>` */
1114+
def unapply(x: Typed): (Term, TypeTree)
11111115
}
11121116

11131117
/** Makes extension methods on `Typed` available without any imports */
@@ -1116,7 +1120,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
11161120
/** Extension methods of `Typed` */
11171121
trait TypedMethods:
11181122
extension (self: Typed)
1119-
def expr: Tree
1123+
def expr: Term
11201124
def tpt: TypeTree
11211125
end extension
11221126
end TypedMethods
@@ -2036,6 +2040,41 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
20362040
def unapply(pattern: Wildcard): true
20372041
}
20382042

2043+
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `TypedTree` */
2044+
given TypedTreeTypeTest: TypeTest[Tree, TypedTree]
2045+
2046+
/** Tree representing a type ascription or pattern `x: T` in the source code
2047+
*
2048+
* The tree `x` may contain a `Constant`, `Ref`, `Wildcard`, `Bind`, `Unapply` or `Alternatives`.
2049+
*/
2050+
type TypedTree <: Term
2051+
2052+
/** Module object of `type TypedTree` */
2053+
val TypedTree: TypedTreeModule
2054+
2055+
/** Methods of the module object `val TypedTree` */
2056+
trait TypedTreeModule { this: TypedTree.type =>
2057+
2058+
/** Create a type ascription `<x: Tree>: <tpt: TypeTree>` */
2059+
def apply(expr: Tree, tpt: TypeTree): TypedTree
2060+
2061+
def copy(original: Tree)(expr: Tree, tpt: TypeTree): TypedTree
2062+
2063+
/** Matches `<expr: Tree>: <tpt: TypeTree>` */
2064+
def unapply(x: TypedTree): (Tree, TypeTree)
2065+
}
2066+
2067+
/** Makes extension methods on `TypedTree` available without any imports */
2068+
given TypedTreeMethods: TypedTreeMethods
2069+
2070+
/** Extension methods of `TypedTree` */
2071+
trait TypedTreeMethods:
2072+
extension (self: TypedTree)
2073+
def tree: Tree
2074+
def tpt: TypeTree
2075+
end extension
2076+
end TypedTreeMethods
2077+
20392078
/** Pattern representing a `_ @ _` binding. */
20402079
type Bind <: Tree
20412080

@@ -4263,6 +4302,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
42634302
case Bind(_, body) => foldTree(x, body)(owner)
42644303
case Unapply(fun, implicits, patterns) => foldTrees(foldTrees(foldTree(x, fun)(owner), implicits)(owner), patterns)(owner)
42654304
case Alternatives(patterns) => foldTrees(x, patterns)(owner)
4305+
case TypedTree(tree1, tpt) => foldTree(foldTree(x, tree1)(owner), tpt)(owner)
4306+
42664307
}
42674308
}
42684309
end TreeAccumulator
@@ -4327,6 +4368,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
43274368
Unapply.copy(pattern)(transformTerm(pattern.fun)(owner), transformSubTrees(pattern.implicits)(owner), transformTrees(pattern.patterns)(owner))
43284369
case pattern: Alternatives =>
43294370
Alternatives.copy(pattern)(transformTrees(pattern.patterns)(owner))
4371+
case TypedTree(expr, tpt) =>
4372+
TypedTree.copy(tree)(transformTree(expr)(owner), transformTypeTree(tpt)(owner))
43304373
}
43314374
}
43324375

@@ -4377,7 +4420,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
43774420
case New(tpt) =>
43784421
New.copy(tree)(transformTypeTree(tpt)(owner))
43794422
case Typed(expr, tpt) =>
4380-
Typed.copy(tree)(transformTree(expr)(owner), transformTypeTree(tpt)(owner))
4423+
Typed.copy(tree)(transformTerm(expr)(owner), transformTypeTree(tpt)(owner))
43814424
case tree: NamedArg =>
43824425
NamedArg.copy(tree)(tree.name, transformTerm(tree.value)(owner))
43834426
case Assign(lhs, rhs) =>

library/src/scala/quoted/Varargs.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ object Varargs {
4242
import quotes.reflect._
4343
def rec(tree: Term): Option[Seq[Expr[T]]] = tree match {
4444
case Repeated(elems, _) => Some(elems.map(x => x.asExpr.asInstanceOf[Expr[T]]))
45-
case Typed(e: Term, _) => rec(e)
45+
case Typed(e, _) => rec(e)
4646
case Block(Nil, e) => rec(e)
4747
case Inlined(_, Nil, e) => rec(e)
4848
case _ => None

tests/neg-macros/i11483/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ object X {
5151
)
5252
case Apply(f,List()) =>
5353
Apply(TypeApply(Select.unique(m,"pure"),List(Inferred(t.tpe.widen))),List(t))
54-
case Typed(x: Term,tp) => Typed(processTree(x,m), Inferred(TypeRepr.of[F].appliedTo(tp.tpe)) )
54+
case Typed(x,tp) => Typed(processTree(x,m), Inferred(TypeRepr.of[F].appliedTo(tp.tpe)) )
5555
case _ => throw new RuntimeException(s"tree not recoginized: $t")
5656
r
5757

tests/pos-macros/i10910/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ object X:
4848
case Inlined(x,bindings,body) => transform(body) match
4949
case Left(unchanged) => Left(term)
5050
case Right(changed) => Right(Inlined(x,bindings,changed))
51-
case Typed(arg: Term,tp) => transform(arg)
51+
case Typed(arg,tp) => transform(arg)
5252
case Ident(x) => Left(term)
5353
case l@Literal(x) => Left(l)
5454
case other =>

tests/pos-macros/i11401/X_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ object X:
5353
val nFun = processLambda[T](fun)
5454
Apply(Apply(TypeApply(Select.unique(x,"fold_async"),targs),List(state)),List(nFun))
5555
case Apply(TypeApply(Ident("await"),targs),List(body)) => body
56-
case Typed(x: Term,tp) => Typed(processTree(x), Inferred(TypeRepr.of[Future].appliedTo(tp.tpe)) )
56+
case Typed(x,tp) => Typed(processTree(x), Inferred(TypeRepr.of[Future].appliedTo(tp.tpe)) )
5757
case _ => throw new RuntimeException(s"tree not recoginized: $t")
5858
val checker = new TreeMap() {}
5959
checker.transformTerm(r)(Symbol.spliceOwner)

tests/pos-macros/i12188c/Macro_1.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ object MatchTest {
88
val matchTree = Match(a.asTerm, List(
99
CaseDef(Literal(IntConstant(1)), None, Block(Nil, Literal(UnitConstant()))),
1010
CaseDef(Alternatives(List(Literal(IntConstant(2)), Literal(IntConstant(3)), Literal(IntConstant(4)))), None, Block(Nil, Literal(UnitConstant()))),
11-
CaseDef(Typed(Alternatives(List(Literal(IntConstant(4)), Literal(IntConstant(5)))), TypeIdent(defn.IntClass)), None, Block(Nil, Literal(UnitConstant()))),
12-
CaseDef(Typed(Wildcard(), TypeIdent(defn.IntClass)), None, Block(Nil, Literal(UnitConstant())))))
11+
CaseDef(TypedTree(Alternatives(List(Literal(IntConstant(4)), Literal(IntConstant(5)))), TypeIdent(defn.IntClass)), None, Block(Nil, Literal(UnitConstant()))),
12+
CaseDef(TypedTree(Wildcard(), TypeIdent(defn.IntClass)), None, Block(Nil, Literal(UnitConstant())))))
1313
matchTree.asExprOf[Unit]
1414
}
1515
}

tests/run-custom-args/tasty-interpreter/interpreter/TreeInterpreter.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ abstract class TreeInterpreter[Q <: Quotes & Singleton](using val q: Q) {
152152
case While(cond, body) => log("interpretWhile", tree)(interpretWhile(cond, body))
153153
case Block(stats, expr) => log("interpretBlock", tree)(interpretBlock(stats, expr))
154154
case Literal(const) => log("interpretLiteral", tree)(interpretLiteral(const))
155-
case Typed(expr: Term, _) => log("<interpretTyped>", tree)(eval(expr))
155+
case Typed(expr, _) => log("<interpretTyped>", tree)(eval(expr))
156156
case Repeated(elems, _) => log("<interpretRepeated>", tree)(interpretRepeated(elems.map(elem => eval(elem))))
157157

158158
case _ => throw new MatchError(tree.show(using Printer.TreeStructure))

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ object Const {
132132
case NullConstant() | UnitConstant() | ClassOfConstant(_) => None
133133
case _ => Some(c.value.asInstanceOf[T])
134134
case Block(Nil, e) => rec(e)
135-
case Typed(e: Term, _) => rec(e)
135+
case Typed(e, _) => rec(e)
136136
case Inlined(_, Nil, e) => rec(e)
137137
case _ => None
138138
}

tests/run-macros/tasty-extractors-1.check

+3-3
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,16 @@ TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
4343
Inlined(None, Nil, Match(Literal(StringConstant("b")), List(CaseDef(Bind("n", Wildcard()), None, Block(Nil, Literal(UnitConstant()))))))
4444
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
4545

46-
Inlined(None, Nil, Match(Literal(StringConstant("c")), List(CaseDef(Bind("n", Typed(Wildcard(), TypeIdent("String"))), None, Block(Nil, Literal(UnitConstant()))))))
46+
Inlined(None, Nil, Match(Literal(StringConstant("c")), List(CaseDef(Bind("n", TypedTree(Wildcard(), TypeIdent("String"))), None, Block(Nil, Literal(UnitConstant()))))))
4747
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
4848

4949
Inlined(None, Nil, Match(Literal(StringConstant("e")), List(CaseDef(Wildcard(), None, Block(Nil, Literal(UnitConstant()))))))
5050
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
5151

52-
Inlined(None, Nil, Match(Literal(StringConstant("f")), List(CaseDef(Typed(Wildcard(), TypeIdent("String")), None, Block(Nil, Literal(UnitConstant()))))))
52+
Inlined(None, Nil, Match(Literal(StringConstant("f")), List(CaseDef(TypedTree(Wildcard(), TypeIdent("String")), None, Block(Nil, Literal(UnitConstant()))))))
5353
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
5454

55-
Inlined(None, Nil, Match(Typed(Literal(StringConstant("g")), TypeIdent("Any")), List(CaseDef(Alternatives(List(Typed(Wildcard(), TypeIdent("String")), Typed(Wildcard(), TypeIdent("Int")))), None, Block(Nil, Literal(UnitConstant()))))))
55+
Inlined(None, Nil, Match(Typed(Literal(StringConstant("g")), TypeIdent("Any")), List(CaseDef(Alternatives(List(TypedTree(Wildcard(), TypeIdent("String")), TypedTree(Wildcard(), TypeIdent("Int")))), None, Block(Nil, Literal(UnitConstant()))))))
5656
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
5757

5858
Inlined(None, Nil, Match(Literal(StringConstant("h")), List(CaseDef(Wildcard(), Some(Literal(BooleanConstant(false))), Block(Nil, Literal(UnitConstant()))))))

0 commit comments

Comments
 (0)