@@ -3,8 +3,10 @@ package runtime.impl
33
44import dotty .tools .dotc .ast .tpd
55import dotty .tools .dotc .core .Contexts .*
6+ import dotty .tools .dotc .core .Decorators .*
67import dotty .tools .dotc .core .Flags .*
78import dotty .tools .dotc .core .Names .*
9+ import dotty .tools .dotc .core .Mode .GadtConstraintInference
810import dotty .tools .dotc .core .Types .*
911import dotty .tools .dotc .core .StdNames .nme
1012import dotty .tools .dotc .core .Symbols .*
@@ -122,10 +124,61 @@ object QuoteMatcher {
122124
123125 private def withEnv [T ](env : Env )(body : Env ?=> T ): T = body(using env)
124126
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
129182
130183 /** Check that all trees match with `mtch` and concatenate the results with &&& */
131184 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 {
457510 *
458511 * This expression is assumed to be a valid expression in the given splice scope.
459512 */
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
461514 case MatchResult .ClosedTree (tree) =>
462515 new ExprImpl (tree, spliceScope)
463516 case MatchResult .OpenTree (tree, patternTpe, args, env) =>
0 commit comments