Skip to content

Commit 7d3f3e4

Browse files
committed
Move treeMatch into QuoteMatcher
1 parent fe08449 commit 7d3f3e4

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
@@ -46,7 +46,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
4646
reflect.Printer.TreeCode.show(reflect.asTerm(self))
4747

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

5151
def valueOrAbort(using fromExpr: FromExpr[T]): T =
5252
def reportError =
@@ -3110,65 +3110,14 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
31103110
def unapply[TypeBindings, Tup <: Tuple](scrutinee: scala.quoted.Expr[Any])(using pattern: scala.quoted.Expr[Any]): Option[Tup] =
31113111
val scrutineeTree = reflect.asTerm(scrutinee)
31123112
val patternTree = reflect.asTerm(pattern)
3113-
treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
3113+
QuoteMatcher.treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
31143114
end ExprMatch
31153115

31163116
object TypeMatch extends TypeMatchModule:
31173117
def unapply[TypeBindings, Tup <: Tuple](scrutinee: scala.quoted.Type[?])(using pattern: scala.quoted.Type[?]): Option[Tup] =
31183118
val scrutineeTree = reflect.TypeTree.of(using scrutinee)
31193119
val patternTree = reflect.TypeTree.of(using pattern)
3120-
treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
3120+
QuoteMatcher.treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
31213121
end TypeMatch
31223122

3123-
private def treeMatch(scrutinee: reflect.Tree, pattern: reflect.Tree): Option[Tuple] = {
3124-
import reflect._
3125-
def isTypeHoleDef(tree: Tree): Boolean =
3126-
tree match
3127-
case tree: TypeDef =>
3128-
tree.symbol.hasAnnotation(dotc.core.Symbols.defn.QuotedRuntimePatterns_patternTypeAnnot)
3129-
case _ => false
3130-
3131-
def extractTypeHoles(pat: Term): (Term, List[Symbol]) =
3132-
pat match
3133-
case tpd.Inlined(_, Nil, pat2) => extractTypeHoles(pat2)
3134-
case tpd.Block(stats @ ((typeHole: TypeDef) :: _), expr) if isTypeHoleDef(typeHole) =>
3135-
val holes = stats.takeWhile(isTypeHoleDef).map(_.symbol)
3136-
val otherStats = stats.dropWhile(isTypeHoleDef)
3137-
(tpd.cpy.Block(pat)(otherStats, expr), holes)
3138-
case _ =>
3139-
(pat, Nil)
3140-
3141-
val (pat1, typeHoles) = extractTypeHoles(pattern)
3142-
3143-
val ctx1 =
3144-
if typeHoles.isEmpty then ctx
3145-
else
3146-
val ctx1 = ctx.fresh.setFreshGADTBounds.addMode(dotc.core.Mode.GadtConstraintInference)
3147-
ctx1.gadtState.addToConstraint(typeHoles)
3148-
ctx1
3149-
3150-
// After matching and doing all subtype checks, we have to approximate all the type bindings
3151-
// that we have found, seal them in a quoted.Type and add them to the result
3152-
def typeHoleApproximation(sym: Symbol) =
3153-
val fromAboveAnnot = sym.hasAnnotation(dotc.core.Symbols.defn.QuotedRuntimePatterns_fromAboveAnnot)
3154-
val fullBounds = ctx1.gadt.fullBounds(sym)
3155-
if fromAboveAnnot then fullBounds.hi else fullBounds.lo
3156-
3157-
QuoteMatcher.treeMatch(scrutinee, pat1)(using ctx1).map { matchings =>
3158-
import QuoteMatcher.MatchResult.*
3159-
lazy val spliceScope = SpliceScope.getCurrent
3160-
val typeHoleApproximations = typeHoles.map(typeHoleApproximation)
3161-
val typeHoleMapping = Map(typeHoles.zip(typeHoleApproximations)*)
3162-
val typeHoleMap = new Types.TypeMap {
3163-
def apply(tp: Types.Type): Types.Type = tp match
3164-
case Types.TypeRef(Types.NoPrefix, _) => typeHoleMapping.getOrElse(tp.typeSymbol, tp)
3165-
case _ => mapOver(tp)
3166-
}
3167-
val matchedExprs = matchings.map(_.toExpr(typeHoleMap, spliceScope))
3168-
val matchedTypes = typeHoleApproximations.map(reflect.TypeReprMethods.asType)
3169-
val results = matchedTypes ++ matchedExprs
3170-
Tuple.fromIArray(IArray.unsafeFromArray(results.toArray))
3171-
}
3172-
}
3173-
31743123
end QuotesImpl

0 commit comments

Comments
 (0)