@@ -124,63 +124,76 @@ object QuoteMatcher {
124
124
125
125
private def withEnv [T ](env : Env )(body : Env ?=> T ): T = body(using env)
126
126
127
- /** Evaluate the the result of pattern matching against a quote pattern.
128
- * Implementation of the runtime of `QuoteMatching.{ ExprMatch,TypeMatch} .unapply`.
127
+ /** Evaluate the result of pattern matching against a quote pattern.
128
+ * Implementation of the runtime of `QuoteMatching.ExprMatch.unapply`.
129
129
*/
130
- def treeMatch (scrutinee : Tree , pattern : Tree )(using Context ): Option [Tuple ] = {
131
- def isTypeHoleDef (tree : Tree ): Boolean =
132
- tree match
133
- case tree : TypeDef =>
134
- tree.symbol.hasAnnotation(defn.QuotedRuntimePatterns_patternTypeAnnot )
135
- case _ => false
136
-
137
- def extractTypeHoles (pat : Tree ): (Tree , List [Symbol ]) =
138
- pat match
139
- case tpd.Inlined (_, Nil , pat2) => extractTypeHoles(pat2)
140
- case tpd.Block (stats @ ((typeHole : TypeDef ) :: _), expr) if isTypeHoleDef(typeHole) =>
141
- val holes = stats.takeWhile(isTypeHoleDef).map(_.symbol)
142
- val otherStats = stats.dropWhile(isTypeHoleDef)
143
- (tpd.cpy.Block (pat)(otherStats, expr), holes)
144
- case _ =>
145
- (pat, Nil )
146
-
147
- val (pat1, typeHoles) = extractTypeHoles(pattern)
130
+ def exprMatch (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 typeHoleMapping = Map (typeHoles.zip(typeHoleApproximations)* )
143
+ val typeHoleMap = new TypeMap {
144
+ def apply (tp : Type ): Type = tp match
145
+ case TypeRef (NoPrefix , _) => typeHoleMapping.getOrElse(tp.typeSymbol, tp)
146
+ case _ => mapOver(tp)
147
+ }
148
+ val matchedExprs = matchings.map(_.toExpr(typeHoleMap, spliceScope))
149
+ val matchedTypes = typeHoleApproximations.map(tpe => new TypeImpl (TypeTree (tpe), spliceScope))
150
+ val results = matchedTypes ++ matchedExprs
151
+ Tuple .fromIArray(IArray .unsafeFromArray(results.toArray))
152
+ }
153
+ }
154
+ }
148
155
149
- val ctx1 =
150
- if typeHoles.isEmpty then ctx
151
- else
152
- val ctx1 = ctx.fresh.setFreshGADTBounds.addMode(GadtConstraintInference )
153
- ctx1.gadtState.addToConstraint(typeHoles)
154
- ctx1
155
-
156
- // After matching and doing all subtype checks, we have to approximate all the type bindings
157
- // that we have found, seal them in a quoted.Type and add them to the result
158
- def typeHoleApproximation (sym : Symbol ) =
159
- val fromAboveAnnot = sym.hasAnnotation(defn.QuotedRuntimePatterns_fromAboveAnnot )
160
- val fullBounds = ctx1.gadt.fullBounds(sym)
161
- if fromAboveAnnot then fullBounds.nn.hi else fullBounds.nn.lo
162
-
163
- optional {
164
- given Context = ctx1
165
- given Env = Map .empty
166
- scrutinee =?= pat1
167
- }.map { matchings =>
168
- import QuoteMatcher .MatchResult .*
169
- lazy val spliceScope = SpliceScope .getCurrent
170
- val typeHoleApproximations = typeHoles.map(typeHoleApproximation)
171
- val typeHoleMapping = Map (typeHoles.zip(typeHoleApproximations)* )
172
- val typeHoleMap = new TypeMap {
173
- def apply (tp : Type ): Type = tp match
174
- case TypeRef (NoPrefix , _) => typeHoleMapping.getOrElse(tp.typeSymbol, tp)
175
- case _ => mapOver(tp)
156
+ /** Evaluate the the result of pattern matching against a quote pattern.
157
+ * Implementation of the runtime of `QuoteMatching.TypeMatch.unapply`.
158
+ */
159
+ def typeMatch (scrutinee : Tree , pattern : Tree )(using Context ): Option [Tuple ] = {
160
+ val (pat1, typeHoles, ctx1) = instrumentTypeHoles(pattern)
161
+ inContext(ctx1) {
162
+ optional {
163
+ given Env = Map .empty
164
+ scrutinee =?= pat1
165
+ }.map { matchings =>
166
+ assert(matchings.isEmpty)
167
+ lazy val spliceScope = SpliceScope .getCurrent
168
+ val matchedTypes = typeHoles.map(tpe => new TypeImpl (TypeTree (typeHoleApproximation(tpe)), spliceScope))
169
+ Tuple .fromIArray(IArray .unsafeFromArray(matchedTypes.toArray))
176
170
}
177
- val matchedExprs = matchings.map(_.toExpr(typeHoleMap, spliceScope))
178
- val matchedTypes = typeHoleApproximations.map(tpe => new TypeImpl (TypeTree (tpe), spliceScope))
179
- val results = matchedTypes ++ matchedExprs
180
- Tuple .fromIArray(IArray .unsafeFromArray(results.toArray))
181
171
}
182
172
}
183
173
174
+ def instrumentTypeHoles (pat : Tree )(using Context ): (Tree , List [Symbol ], Context ) =
175
+ def isTypeHoleDef (tree : Tree ): Boolean = tree match
176
+ case tree : TypeDef => tree.symbol.hasAnnotation(defn.QuotedRuntimePatterns_patternTypeAnnot )
177
+ case _ => false
178
+ pat match
179
+ case tpd.Inlined (_, Nil , pat2) => instrumentTypeHoles(pat2)
180
+ case tpd.Block (stats @ ((typeHole : TypeDef ) :: _), expr) if isTypeHoleDef(typeHole) =>
181
+ val (holeDefs, otherStats) = stats.span(isTypeHoleDef)
182
+ val holeSyms = holeDefs.map(_.symbol)
183
+ val ctx1 = ctx.fresh.setFreshGADTBounds.addMode(GadtConstraintInference )
184
+ ctx1.gadtState.addToConstraint(holeSyms)
185
+ (tpd.cpy.Block (pat)(otherStats, expr), holeSyms, ctx1)
186
+ case _ =>
187
+ (pat, Nil , ctx)
188
+
189
+ /** Type approximation of a quote pattern type variable.
190
+ * Should only be approximated after matching the tree.
191
+ */
192
+ def typeHoleApproximation (sym : Symbol )(using Context ): Type =
193
+ val fromAboveAnnot = sym.hasAnnotation(defn.QuotedRuntimePatterns_fromAboveAnnot )
194
+ val fullBounds = ctx.gadt.fullBounds(sym)
195
+ if fromAboveAnnot then fullBounds.nn.hi else fullBounds.nn.lo
196
+
184
197
/** Check that all trees match with `mtch` and concatenate the results with &&& */
185
198
private def matchLists [T ](l1 : List [T ], l2 : List [T ])(mtch : (T , T ) => MatchingExprs ): optional[MatchingExprs ] = (l1, l2) match {
186
199
case (x :: xs, y :: ys) => mtch(x, y) &&& matchLists(xs, ys)(mtch)
0 commit comments