Skip to content

Commit c351484

Browse files
nicolasstuckiKordyjan
authored andcommitted
Refactor and optimize treeMatch
Now we do not use use the TypeMap if there is no type to map. We also do not create the type map if there are no expression that may contain types that need mapping. [Cherry-picked aad8475]
1 parent 41b9969 commit c351484

File tree

1 file changed

+51
-52
lines changed

1 file changed

+51
-52
lines changed

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

Lines changed: 51 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -124,63 +124,62 @@ object QuoteMatcher {
124124

125125
private def withEnv[T](env: Env)(body: Env ?=> T): T = body(using env)
126126

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, TypeMatch}.unapply`.
129129
*/
130130
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)
148-
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)
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))
176156
}
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))
181157
}
182158
}
183159

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
182+
184183
/** Check that all trees match with `mtch` and concatenate the results with &&& */
185184
private def matchLists[T](l1: List[T], l2: List[T])(mtch: (T, T) => MatchingExprs): optional[MatchingExprs] = (l1, l2) match {
186185
case (x :: xs, y :: ys) => mtch(x, y) &&& matchLists(xs, ys)(mtch)
@@ -511,7 +510,7 @@ object QuoteMatcher {
511510
*
512511
* This expression is assumed to be a valid expression in the given splice scope.
513512
*/
514-
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
515514
case MatchResult.ClosedTree(tree) =>
516515
new ExprImpl(tree, spliceScope)
517516
case MatchResult.OpenTree(tree, patternTpe, args, env) =>

0 commit comments

Comments
 (0)