Skip to content

Commit e67c5f0

Browse files
committed
Introduce Typed abstraction that supports patterns
1 parent fffa86d commit e67c5f0

File tree

16 files changed

+120
-46
lines changed

16 files changed

+120
-46
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

+34-13
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,10 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
650650

651651
object TypedTypeTest extends TypeTest[Tree, Typed]:
652652
def unapply(x: Tree): Option[Typed & x.type] = x match
653-
case x: (tpd.Typed & x.type) => Some(x)
653+
case x: (tpd.Typed & x.type) =>
654+
x.expr match
655+
case TermTypeTest(_) => Some(x)
656+
case _ => None
654657
case _ => None
655658
end TypedTypeTest
656659

@@ -666,7 +669,6 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
666669
given TypedMethods: TypedMethods with
667670
extension (self: Typed)
668671
def expr: Term = self.expr
669-
def tpt: TypeTree = self.tpt
670672
end extension
671673
end TypedMethods
672674

@@ -1416,6 +1418,30 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
14161418
def unapply(pattern: Wildcard): true = true
14171419
end Wildcard
14181420

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

14211447
object BindTypeTest extends TypeTest[Tree, Bind]:
@@ -1440,13 +1466,12 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
14401466
end extension
14411467
end BindMethods
14421468

1443-
type Unapply = tpd.UnApply | tpd.Typed // tpd.Typed containing a tpd.UnApply as expression
1469+
type Unapply = tpd.UnApply
14441470

14451471
object UnapplyTypeTest extends TypeTest[Tree, Unapply]:
14461472
def unapply(x: Tree): Option[Unapply & x.type] =
1447-
x match // keep in sync with UnapplyMethodsImpl.selfUnApply
1473+
x match
14481474
case x: (tpd.UnApply & x.type) => Some(x)
1449-
case x: (tpd.Typed & x.type) if x.expr.isInstanceOf[tpd.UnApply] => Some(x)
14501475
case _ => None
14511476
end UnapplyTypeTest
14521477

@@ -1459,14 +1484,10 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
14591484

14601485
given UnapplyMethods: UnapplyMethods with
14611486
extension (self: Unapply)
1462-
def fun: Term = selfUnApply(self).fun
1463-
def implicits: List[Term] = selfUnApply(self).implicits
1464-
def patterns: List[Tree] = effectivePatterns(selfUnApply(self).patterns)
1465-
end extension
1466-
private def selfUnApply(self: Unapply): tpd.UnApply =
1467-
self match // keep in sync with UnapplyTypeTest
1468-
case self: tpd.UnApply => self
1469-
case self: tpd.Typed => self.expr.asInstanceOf[tpd.UnApply]
1487+
def fun: Term = self.fun
1488+
def implicits: List[Term] = self.implicits
1489+
def patterns: List[Tree] = effectivePatterns(self.patterns)
1490+
end extension
14701491
private def effectivePatterns(patterns: List[Tree]): List[Tree] =
14711492
patterns match
14721493
case patterns0 :+ dotc.ast.Trees.SeqLiteral(elems, _) => patterns0 ::: elems

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

+9
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)

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

+60-18
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,18 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
135135
* | +- Inlined
136136
* | +- SelectOuter
137137
* | +- While
138+
* | +·
139+
* | \
140+
* | +- Typed
141+
* | /
142+
* +- TypedTree +-----------------·
143+
* +- Wildcard
144+
* +- Bind
145+
* +- Unapply
146+
* +- Alternatives
138147
* |
148+
* +- CaseDef
149+
* +- TypeCaseDef
139150
* |
140151
* +- TypeTree ----+- Inferred
141152
* | +- TypeIdent
@@ -153,14 +164,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
153164
* |
154165
* +- TypeBoundsTree
155166
* +- WildcardTypeTree
156-
* |
157-
* +- CaseDef
158-
* |
159-
* +- TypeCaseDef
160-
* +- Wildcard
161-
* +- Bind
162-
* +- Unapply
163-
* +- Alternatives
164167
*
165168
* +- ParamClause -+- TypeParamClause
166169
* +- TermParamClause
@@ -1092,22 +1095,26 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
10921095
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `Typed` */
10931096
given TypedTypeTest: TypeTest[Tree, Typed]
10941097

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

10981105
/** Module object of `type Typed` */
10991106
val Typed: TypedModule
11001107

11011108
/** Methods of the module object `val Typed` */
11021109
trait TypedModule { this: Typed.type =>
11031110

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

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

1109-
/** Matches `<expr: Tree>: <tpt: TypeTree>` */
1110-
def unapply(x: Typed): (Tree, TypeTree)
1116+
/** Matches `<expr: Term>: <tpt: TypeTree>` */
1117+
def unapply(x: Typed): (Term, TypeTree)
11111118
}
11121119

11131120
/** Makes extension methods on `Typed` available without any imports */
@@ -1116,8 +1123,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
11161123
/** Extension methods of `Typed` */
11171124
trait TypedMethods:
11181125
extension (self: Typed)
1119-
def expr: Tree
1120-
def tpt: TypeTree
1126+
def expr: Term
11211127
end extension
11221128
end TypedMethods
11231129

@@ -2036,6 +2042,38 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
20362042
def unapply(pattern: Wildcard): true
20372043
}
20382044

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

@@ -4263,6 +4301,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
42634301
case Bind(_, body) => foldTree(x, body)(owner)
42644302
case Unapply(fun, implicits, patterns) => foldTrees(foldTrees(foldTree(x, fun)(owner), implicits)(owner), patterns)(owner)
42654303
case Alternatives(patterns) => foldTrees(x, patterns)(owner)
4304+
case TypedTree(tree1, tpt) => foldTree(foldTree(x, tree1)(owner), tpt)(owner)
4305+
42664306
}
42674307
}
42684308
end TreeAccumulator
@@ -4327,6 +4367,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
43274367
Unapply.copy(pattern)(transformTerm(pattern.fun)(owner), transformSubTrees(pattern.implicits)(owner), transformTrees(pattern.patterns)(owner))
43284368
case pattern: Alternatives =>
43294369
Alternatives.copy(pattern)(transformTrees(pattern.patterns)(owner))
4370+
case TypedTree(expr, tpt) =>
4371+
TypedTree.copy(tree)(transformTree(expr)(owner), transformTypeTree(tpt)(owner))
43304372
}
43314373
}
43324374

@@ -4377,7 +4419,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
43774419
case New(tpt) =>
43784420
New.copy(tree)(transformTypeTree(tpt)(owner))
43794421
case Typed(expr, tpt) =>
4380-
Typed.copy(tree)(transformTree(expr)(owner), transformTypeTree(tpt)(owner))
4422+
Typed.copy(tree)(transformTerm(expr)(owner), transformTypeTree(tpt)(owner))
43814423
case tree: NamedArg =>
43824424
NamedArg.copy(tree)(tree.name, transformTerm(tree.value)(owner))
43834425
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)