Skip to content

Commit 6f7a05b

Browse files
committed
Refactor matcher code into a class
1 parent 518c426 commit 6f7a05b

File tree

1 file changed

+55
-52
lines changed

1 file changed

+55
-52
lines changed

library/src-bootstrapped/scala/internal/quoted/Matcher.scala

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ object Matcher {
99

1010
private final val debug = false
1111

12-
/** Pattern matches an the scrutineeExpr aquainsnt the patternExpr and returns a tuple
12+
/** Pattern matches an the scrutineeExpr against the patternExpr and returns a tuple
1313
* with the matched holes if successful.
1414
*
1515
* Examples:
@@ -32,49 +32,73 @@ object Matcher {
3232
*/
3333
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeExpr: Expr[_])(implicit patternExpr: Expr[_],
3434
hasTypeSplices: Boolean, qctx: QuoteContext): Option[Tup] = {
35+
import qctx.tasty._
36+
new QuoteMatcher[qctx.type].matches(scrutineeExpr.unseal, patternExpr.unseal, hasTypeSplices).asInstanceOf[Option[Tup]]
37+
}
3538

39+
private class QuoteMatcher[QCtx <: QuoteContext & Singleton] given (val qctx: QCtx) {
3640
// TODO improve performance
41+
3742
import qctx.tasty.{Bind => BindPattern, _}
3843
import Matching._
3944

40-
type Env = Set[(Symbol, Symbol)]
45+
private type Env = Set[(Symbol, Symbol)]
46+
47+
inline private def withEnv[T](env: Env)(body: => given Env => T): T = body given env
4148

4249
class SymBinding(val sym: Symbol)
4350

44-
inline def withEnv[T](env: Env)(body: => given Env => T): T = body given env
51+
def matches(scrutineeTerm: Term, patternTerm: Term, hasTypeSplices: Boolean): Option[Tuple] = {
52+
implicit val env: Env = Set.empty
53+
if (hasTypeSplices) {
54+
implicit val ctx: Context = internal.Context_GADT_setFreshGADTBounds(rootContext)
55+
val matchings = scrutineeTerm.underlyingArgument =#= patternTerm.underlyingArgument
56+
// After matching and doing all subtype check, we have to aproximate all the type bindings
57+
// that we have found and seal them in a quoted.Type
58+
matchings.asOptionOfTuple.map { tup =>
59+
Tuple.fromArray(tup.toArray.map { // TODO improve performace
60+
case x: SymBinding => internal.Context_GADT_approximation(the[Context])(x.sym, true).seal
61+
case x => x
62+
})
63+
}
64+
}
65+
else {
66+
scrutineeTerm.underlyingArgument =#= patternTerm.underlyingArgument
67+
}
68+
}
4569

46-
def hasBindTypeAnnotation(tpt: TypeTree): Boolean = tpt match {
70+
private def hasBindTypeAnnotation(tpt: TypeTree): Boolean = tpt match {
4771
case Annotated(tpt2, annot) => isBindAnnotation(annot) || hasBindTypeAnnotation(tpt2)
4872
case _ => false
4973
}
5074

51-
def hasBindAnnotation(sym: Symbol) = sym.annots.exists(isBindAnnotation)
75+
private def hasBindAnnotation(sym: Symbol) = sym.annots.exists(isBindAnnotation)
5276

53-
def isBindAnnotation(tree: Tree): Boolean = tree match {
77+
private def isBindAnnotation(tree: Tree): Boolean = tree match {
5478
case New(tpt) => tpt.symbol == internal.Definitions_InternalQuoted_patternBindHoleAnnot
5579
case annot => annot.symbol.owner == internal.Definitions_InternalQuoted_patternBindHoleAnnot
5680
}
5781

5882
/** Check that all trees match with `mtch` and concatenate the results with && */
59-
def matchLists[T](l1: List[T], l2: List[T])(mtch: (T, T) => Matching): Matching = (l1, l2) match {
83+
private def matchLists[T](l1: List[T], l2: List[T])(mtch: (T, T) => Matching): Matching = (l1, l2) match {
6084
case (x :: xs, y :: ys) => mtch(x, y) && matchLists(xs, ys)(mtch)
6185
case (Nil, Nil) => matched
6286
case _ => notMatched
6387
}
6488

6589
/** Check that all trees match with =#= and concatenate the results with && */
66-
def (scrutinees: List[Tree]) =##= (patterns: List[Tree]) given Context, Env: Matching =
90+
private def (scrutinees: List[Tree]) =##= (patterns: List[Tree]) given Context, Env: Matching =
6791
matchLists(scrutinees, patterns)(_ =#= _)
6892

6993
/** Check that the trees match and return the contents from the pattern holes.
7094
* Return None if the trees do not match otherwise return Some of a tuple containing all the contents in the holes.
7195
*
72-
* @param scrutinee The tree beeing matched
73-
* @param pattern The pattern tree that the scrutinee should match. Contains `patternHole` holes.
74-
* @param `the[Env]` Set of tuples containing pairs of symbols (s, p) where s defines a symbol in `scrutinee` which corresponds to symbol p in `pattern`.
75-
* @return `None` if it did not match or `Some(tup: Tuple)` if it matched where `tup` contains the contents of the holes.
96+
* @param scrutinee The tree beeing matched
97+
* @param pattern The pattern tree that the scrutinee should match. Contains `patternHole` holes.
98+
* @param `the[Env]` Set of tuples containing pairs of symbols (s, p) where s defines a symbol in `scrutinee` which corresponds to symbol p in `pattern`.
99+
* @return `None` if it did not match or `Some(tup: Tuple)` if it matched where `tup` contains the contents of the holes.
76100
*/
77-
def (scrutinee0: Tree) =#= (pattern0: Tree) given Context, Env: Matching = {
101+
private def (scrutinee0: Tree) =#= (pattern0: Tree) given Context, Env: Matching = {
78102

79103
/** Normalize the tree */
80104
def normalize(tree: Tree): Tree = tree match {
@@ -202,10 +226,10 @@ object Matcher {
202226
paramss1.flatten.zip(paramss2.flatten).map((param1, param2) => param1.symbol -> param2.symbol)
203227

204228
bindMatch &&
205-
typeParams1 =##= typeParams2 &&
206-
matchLists(paramss1, paramss2)(_ =##= _) &&
207-
tpt1 =#= tpt2 &&
208-
withEnv(rhsEnv)(rhs1 =#= rhs2)
229+
typeParams1 =##= typeParams2 &&
230+
matchLists(paramss1, paramss2)(_ =##= _) &&
231+
tpt1 =#= tpt2 &&
232+
withEnv(rhsEnv)(rhs1 =#= rhs2)
209233

210234
case (Closure(_, tpt1), Closure(_, tpt2)) =>
211235
// TODO match tpt1 with tpt2?
@@ -246,36 +270,36 @@ object Matcher {
246270
}
247271
}
248272

249-
def treeOptMatches(scrutinee: Option[Tree], pattern: Option[Tree]) given Context, Env: Matching = {
273+
private def treeOptMatches(scrutinee: Option[Tree], pattern: Option[Tree]) given Context, Env: Matching = {
250274
(scrutinee, pattern) match {
251275
case (Some(x), Some(y)) => x =#= y
252276
case (None, None) => matched
253277
case _ => notMatched
254278
}
255279
}
256280

257-
def caseMatches(scrutinee: CaseDef, pattern: CaseDef) given Context, Env: Matching = {
281+
private def caseMatches(scrutinee: CaseDef, pattern: CaseDef) given Context, Env: Matching = {
258282
val (caseEnv, patternMatch) = scrutinee.pattern =%= pattern.pattern
259283
withEnv(caseEnv) {
260284
patternMatch &&
261-
treeOptMatches(scrutinee.guard, pattern.guard) &&
262-
scrutinee.rhs =#= pattern.rhs
285+
treeOptMatches(scrutinee.guard, pattern.guard) &&
286+
scrutinee.rhs =#= pattern.rhs
263287
}
264288
}
265289

266290
/** Check that the pattern trees match and return the contents from the pattern holes.
267291
* Return a tuple with the new environment containing the bindings defined in this pattern and a matching.
268292
* The matching is None if the pattern trees do not match otherwise return Some of a tuple containing all the contents in the holes.
269293
*
270-
* @param scrutinee The pattern tree beeing matched
271-
* @param pattern The pattern tree that the scrutinee should match. Contains `patternHole` holes.
272-
* @param `the[Env]` Set of tuples containing pairs of symbols (s, p) where s defines a symbol in `scrutinee` which corresponds to symbol p in `pattern`.
273-
* @return The new environment containing the bindings defined in this pattern tuppled with
274-
* `None` if it did not match or `Some(tup: Tuple)` if it matched where `tup` contains the contents of the holes.
294+
* @param scrutinee The pattern tree beeing matched
295+
* @param pattern The pattern tree that the scrutinee should match. Contains `patternHole` holes.
296+
* @param `the[Env]` Set of tuples containing pairs of symbols (s, p) where s defines a symbol in `scrutinee` which corresponds to symbol p in `pattern`.
297+
* @return The new environment containing the bindings defined in this pattern tuppled with
298+
* `None` if it did not match or `Some(tup: Tuple)` if it matched where `tup` contains the contents of the holes.
275299
*/
276-
def (scrutinee: Pattern) =%= (pattern: Pattern) given Context, Env: (Env, Matching) = (scrutinee, pattern) match {
300+
private def (scrutinee: Pattern) =%= (pattern: Pattern) given Context, Env: (Env, Matching) = (scrutinee, pattern) match {
277301
case (Pattern.Value(v1), Pattern.Unapply(TypeApply(Select(patternHole @ Ident("patternHole"), "unapply"), List(tpt)), Nil, Nil))
278-
if patternHole.symbol.owner.fullName == "scala.runtime.quoted.Matcher$" =>
302+
if patternHole.symbol.owner.fullName == "scala.runtime.quoted.Matcher$" =>
279303
(the[Env], matched(v1.seal))
280304

281305
case (Pattern.Value(v1), Pattern.Value(v2)) =>
@@ -319,39 +343,18 @@ object Matcher {
319343
(the[Env], notMatched)
320344
}
321345

322-
def foldPatterns(patterns1: List[Pattern], patterns2: List[Pattern]) given Context, Env: (Env, Matching) = {
346+
private def foldPatterns(patterns1: List[Pattern], patterns2: List[Pattern]) given Context, Env: (Env, Matching) = {
323347
if (patterns1.size != patterns2.size) (the[Env], notMatched)
324348
else patterns1.zip(patterns2).foldLeft((the[Env], matched)) { (acc, x) =>
325349
val (env, res) = (x._1 =%= x._2) given (the[Context], acc._1)
326350
(env, acc._2 && res)
327351
}
328352
}
329353

330-
def isTypeBinding(tree: Tree): Boolean = tree match {
354+
private def isTypeBinding(tree: Tree): Boolean = tree match {
331355
case IsTypeDef(tree) => hasBindAnnotation(tree.symbol)
332356
case _ => false
333357
}
334-
335-
implicit val env: Env = Set.empty
336-
337-
val res = {
338-
if (hasTypeSplices) {
339-
implicit val ctx: Context = qctx.tasty.internal.Context_GADT_setFreshGADTBounds(rootContext)
340-
val matchings = scrutineeExpr.unseal.underlyingArgument =#= patternExpr.unseal.underlyingArgument
341-
// After matching and doing all subtype check, we have to aproximate all the type bindings
342-
// that we have found and seal them in a quoted.Type
343-
matchings.asOptionOfTuple.map { tup =>
344-
Tuple.fromArray(tup.toArray.map { // TODO improve performace
345-
case x: SymBinding => internal.Context_GADT_approximation(the[Context])(x.sym, true).seal
346-
case x => x
347-
})
348-
}
349-
}
350-
else {
351-
scrutineeExpr.unseal.underlyingArgument =#= patternExpr.unseal.underlyingArgument
352-
}
353-
}
354-
res.asInstanceOf[Option[Tup]]
355358
}
356359

357360
/** Result of matching a part of an expression */
@@ -366,7 +369,7 @@ object Matcher {
366369
def (self: Matching) asOptionOfTuple: Option[Tuple] = self
367370

368371
/** Concatenates the contents of two sucessful matchings or return a `notMatched` */
369-
// FIXME inline to avoid alocation of by name closure (see #6395)
372+
// FIXME inline to avoid allocation of by name closure (see #6395)
370373
/*inline*/ def (self: Matching) && (that: => Matching): Matching = self match {
371374
case Some(x) =>
372375
that match {

0 commit comments

Comments
 (0)