Skip to content

Commit 41b9969

Browse files
nicolasstuckiKordyjan
authored andcommitted
Move treeMatch into QuoteMatcher
[Cherry-picked 7d3f3e4]
1 parent 721e7c8 commit 41b9969

File tree

2 files changed

+61
-58
lines changed

2 files changed

+61
-58
lines changed

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

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ package runtime.impl
33

44
import dotty.tools.dotc.ast.tpd
55
import dotty.tools.dotc.core.Contexts.*
6+
import dotty.tools.dotc.core.Decorators.*
67
import dotty.tools.dotc.core.Flags.*
78
import dotty.tools.dotc.core.Names.*
9+
import dotty.tools.dotc.core.Mode.GadtConstraintInference
810
import dotty.tools.dotc.core.Types.*
911
import dotty.tools.dotc.core.StdNames.nme
1012
import dotty.tools.dotc.core.Symbols.*
@@ -122,10 +124,62 @@ 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 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+
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)
176+
}
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+
}
182+
}
129183

130184
/** Check that all trees match with `mtch` and concatenate the results with &&& */
131185
private def matchLists[T](l1: List[T], l2: List[T])(mtch: (T, T) => MatchingExprs): optional[MatchingExprs] = (l1, l2) match {

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

Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
4545
reflect.Printer.TreeCode.show(reflect.asTerm(self))
4646

4747
def matches(that: scala.quoted.Expr[Any]): Boolean =
48-
treeMatch(reflect.asTerm(self), reflect.asTerm(that)).nonEmpty
48+
QuoteMatcher.treeMatch(reflect.asTerm(self), reflect.asTerm(that)).nonEmpty
4949

5050
def valueOrAbort(using fromExpr: FromExpr[T]): T =
5151
def reportError =
@@ -3155,65 +3155,14 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
31553155
def unapply[TypeBindings, Tup <: Tuple](scrutinee: scala.quoted.Expr[Any])(using pattern: scala.quoted.Expr[Any]): Option[Tup] =
31563156
val scrutineeTree = reflect.asTerm(scrutinee)
31573157
val patternTree = reflect.asTerm(pattern)
3158-
treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
3158+
QuoteMatcher.treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
31593159
end ExprMatch
31603160

31613161
object TypeMatch extends TypeMatchModule:
31623162
def unapply[TypeBindings, Tup <: Tuple](scrutinee: scala.quoted.Type[?])(using pattern: scala.quoted.Type[?]): Option[Tup] =
31633163
val scrutineeTree = reflect.TypeTree.of(using scrutinee)
31643164
val patternTree = reflect.TypeTree.of(using pattern)
3165-
treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
3165+
QuoteMatcher.treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
31663166
end TypeMatch
31673167

3168-
private def treeMatch(scrutinee: reflect.Tree, pattern: reflect.Tree): Option[Tuple] = {
3169-
import reflect._
3170-
def isTypeHoleDef(tree: Tree): Boolean =
3171-
tree match
3172-
case tree: TypeDef =>
3173-
tree.symbol.hasAnnotation(dotc.core.Symbols.defn.QuotedRuntimePatterns_patternTypeAnnot)
3174-
case _ => false
3175-
3176-
def extractTypeHoles(pat: Term): (Term, List[Symbol]) =
3177-
pat match
3178-
case tpd.Inlined(_, Nil, pat2) => extractTypeHoles(pat2)
3179-
case tpd.Block(stats @ ((typeHole: TypeDef) :: _), expr) if isTypeHoleDef(typeHole) =>
3180-
val holes = stats.takeWhile(isTypeHoleDef).map(_.symbol)
3181-
val otherStats = stats.dropWhile(isTypeHoleDef)
3182-
(tpd.cpy.Block(pat)(otherStats, expr), holes)
3183-
case _ =>
3184-
(pat, Nil)
3185-
3186-
val (pat1, typeHoles) = extractTypeHoles(pattern)
3187-
3188-
val ctx1 =
3189-
if typeHoles.isEmpty then ctx
3190-
else
3191-
val ctx1 = ctx.fresh.setFreshGADTBounds.addMode(dotc.core.Mode.GadtConstraintInference)
3192-
ctx1.gadtState.addToConstraint(typeHoles)
3193-
ctx1
3194-
3195-
// After matching and doing all subtype checks, we have to approximate all the type bindings
3196-
// that we have found, seal them in a quoted.Type and add them to the result
3197-
def typeHoleApproximation(sym: Symbol) =
3198-
val fromAboveAnnot = sym.hasAnnotation(dotc.core.Symbols.defn.QuotedRuntimePatterns_fromAboveAnnot)
3199-
val fullBounds = ctx1.gadt.fullBounds(sym)
3200-
if fromAboveAnnot then fullBounds.hi else fullBounds.lo
3201-
3202-
QuoteMatcher.treeMatch(scrutinee, pat1)(using ctx1).map { matchings =>
3203-
import QuoteMatcher.MatchResult.*
3204-
lazy val spliceScope = SpliceScope.getCurrent
3205-
val typeHoleApproximations = typeHoles.map(typeHoleApproximation)
3206-
val typeHoleMapping = Map(typeHoles.zip(typeHoleApproximations)*)
3207-
val typeHoleMap = new Types.TypeMap {
3208-
def apply(tp: Types.Type): Types.Type = tp match
3209-
case Types.TypeRef(Types.NoPrefix, _) => typeHoleMapping.getOrElse(tp.typeSymbol, tp)
3210-
case _ => mapOver(tp)
3211-
}
3212-
val matchedExprs = matchings.map(_.toExpr(typeHoleMap, spliceScope))
3213-
val matchedTypes = typeHoleApproximations.map(reflect.TypeReprMethods.asType)
3214-
val results = matchedTypes ++ matchedExprs
3215-
Tuple.fromIArray(IArray.unsafeFromArray(results.toArray))
3216-
}
3217-
}
3218-
32193168
end QuotesImpl

0 commit comments

Comments
 (0)