@@ -3,8 +3,10 @@ package runtime.impl
3
3
4
4
import dotty .tools .dotc .ast .tpd
5
5
import dotty .tools .dotc .core .Contexts .*
6
+ import dotty .tools .dotc .core .Decorators .*
6
7
import dotty .tools .dotc .core .Flags .*
7
8
import dotty .tools .dotc .core .Names .*
9
+ import dotty .tools .dotc .core .Mode .GadtConstraintInference
8
10
import dotty .tools .dotc .core .Types .*
9
11
import dotty .tools .dotc .core .StdNames .nme
10
12
import dotty .tools .dotc .core .Symbols .*
@@ -122,10 +124,61 @@ object QuoteMatcher {
122
124
123
125
private def withEnv [T ](env : Env )(body : Env ?=> T ): T = body(using env)
124
126
125
- def treeMatch (scrutineeTree : Tree , patternTree : Tree )(using Context ): Option [MatchingExprs ] =
126
- given Env = Map .empty
127
- optional :
128
- scrutineeTree =?= patternTree
127
+ /** Evaluate the result of pattern matching against a quote pattern.
128
+ * Implementation of the runtime of `QuoteMatching.{ExprMatch, TypeMatch}.unapply`.
129
+ */
130
+ def treeMatch (scrutinee : Tree , pattern : Tree )(using Context ): Option [Tuple ] = {
131
+ val (pat1, typeHoles, ctx1) = instrumentTypeHoles(pattern)
132
+ inContext(ctx1) {
133
+ optional {
134
+ given Env = Map .empty
135
+ scrutinee =?= pat1
136
+ }.map { matchings =>
137
+ import QuoteMatcher .MatchResult .*
138
+ lazy val spliceScope = SpliceScope .getCurrent
139
+ // After matching and doing all subtype checks, we have to approximate all the type bindings
140
+ // that we have found, seal them in a quoted.Type and add them to the result
141
+ val typeHoleApproximations = typeHoles.map(typeHoleApproximation)
142
+ val matchedTypes = typeHoleApproximations.map(tpe => new TypeImpl (TypeTree (tpe), spliceScope))
143
+ val matchedExprs =
144
+ val typeHoleMap : Type => Type =
145
+ if typeHoles.isEmpty then identity
146
+ else new TypeMap {
147
+ private val typeHoleMapping = Map (typeHoles.zip(typeHoleApproximations)* )
148
+ def apply (tp : Type ): Type = tp match
149
+ case TypeRef (NoPrefix , _) => typeHoleMapping.getOrElse(tp.typeSymbol, tp)
150
+ case _ => mapOver(tp)
151
+ }
152
+ if matchings.isEmpty then Nil
153
+ else matchings.map(_.toExpr(typeHoleMap, spliceScope))
154
+ val results = matchedTypes ++ matchedExprs
155
+ Tuple .fromIArray(IArray .unsafeFromArray(results.toArray))
156
+ }
157
+ }
158
+ }
159
+
160
+ def instrumentTypeHoles (pat : Tree )(using Context ): (Tree , List [Symbol ], Context ) =
161
+ def isTypeHoleDef (tree : Tree ): Boolean = tree match
162
+ case tree : TypeDef => tree.symbol.hasAnnotation(defn.QuotedRuntimePatterns_patternTypeAnnot )
163
+ case _ => false
164
+ pat match
165
+ case tpd.Inlined (_, Nil , pat2) => instrumentTypeHoles(pat2)
166
+ case tpd.Block (stats @ ((typeHole : TypeDef ) :: _), expr) if isTypeHoleDef(typeHole) =>
167
+ val (holeDefs, otherStats) = stats.span(isTypeHoleDef)
168
+ val holeSyms = holeDefs.map(_.symbol)
169
+ val ctx1 = ctx.fresh.setFreshGADTBounds.addMode(GadtConstraintInference )
170
+ ctx1.gadtState.addToConstraint(holeSyms)
171
+ (tpd.cpy.Block (pat)(otherStats, expr), holeSyms, ctx1)
172
+ case _ =>
173
+ (pat, Nil , ctx)
174
+
175
+ /** Type approximation of a quote pattern type variable.
176
+ * Should only be approximated after matching the tree.
177
+ */
178
+ def typeHoleApproximation (sym : Symbol )(using Context ): Type =
179
+ val fromAboveAnnot = sym.hasAnnotation(defn.QuotedRuntimePatterns_fromAboveAnnot )
180
+ val fullBounds = ctx.gadt.fullBounds(sym)
181
+ if fromAboveAnnot then fullBounds.nn.hi else fullBounds.nn.lo
129
182
130
183
/** Check that all trees match with `mtch` and concatenate the results with &&& */
131
184
private def matchLists [T ](l1 : List [T ], l2 : List [T ])(mtch : (T , T ) => MatchingExprs ): optional[MatchingExprs ] = (l1, l2) match {
@@ -457,7 +510,7 @@ object QuoteMatcher {
457
510
*
458
511
* This expression is assumed to be a valid expression in the given splice scope.
459
512
*/
460
- def toExpr (mapTypeHoles : TypeMap , spliceScope : Scope )(using Context ): Expr [Any ] = this match
513
+ def toExpr (mapTypeHoles : Type => Type , spliceScope : Scope )(using Context ): Expr [Any ] = this match
461
514
case MatchResult .ClosedTree (tree) =>
462
515
new ExprImpl (tree, spliceScope)
463
516
case MatchResult .OpenTree (tree, patternTpe, args, env) =>
0 commit comments