Skip to content

Commit 8aacc89

Browse files
committed
Simplify QuoteMatcher using optional
1 parent 847eccc commit 8aacc89

File tree

3 files changed

+45
-48
lines changed

3 files changed

+45
-48
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package dotty.tools.dotc.util
2+
3+
import scala.util.boundary
4+
5+
/** Return type that indicates that the method returns a T or aborts to the enclosing boundary with a `None` */
6+
type optional[T] = boundary.Label[None.type] ?=> T
7+
8+
/** A prompt for `Option`, which establishes a boundary which `_.?` on `Option` can return */
9+
object optional:
10+
inline def apply[T](inline body: optional[T]): Option[T] =
11+
boundary(Some(body))
12+
13+
extension [T](r: Option[T])
14+
inline def ? (using label: boundary.Label[None.type]): T = r match
15+
case Some(x) => x
16+
case None => boundary.break(None)
17+
18+
inline def break()(using label: boundary.Label[None.type]): Nothing =
19+
boundary.break(None)

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

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package scala.quoted
22
package runtime.impl
33

4-
54
import dotty.tools.dotc.ast.tpd
65
import dotty.tools.dotc.core.Contexts.*
76
import dotty.tools.dotc.core.Flags.*
87
import dotty.tools.dotc.core.Names.*
98
import dotty.tools.dotc.core.Types.*
109
import dotty.tools.dotc.core.StdNames.nme
1110
import dotty.tools.dotc.core.Symbols.*
11+
import dotty.tools.dotc.util.optional
1212

1313
/** Matches a quoted tree against a quoted pattern tree.
1414
* A quoted pattern tree may have type and term holes in addition to normal terms.
@@ -103,13 +103,9 @@ import dotty.tools.dotc.core.Symbols.*
103103
object QuoteMatcher {
104104
import tpd.*
105105

106-
// TODO improve performance
107-
108106
// TODO use flag from Context. Maybe -debug or add -debug-macros
109107
private inline val debug = false
110108

111-
import Matching._
112-
113109
/** A map relating equivalent symbols from the scrutinee and the pattern
114110
* For example in
115111
* ```
@@ -121,19 +117,20 @@ object QuoteMatcher {
121117

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

124-
def treeMatch(scrutineeTree: Tree, patternTree: Tree)(using Context): Option[Tuple] =
120+
def treeMatch(scrutineeTree: Tree, patternTree: Tree)(using Context): Option[Seq[Expr[Any]]] =
125121
given Env = Map.empty
126-
scrutineeTree =?= patternTree
122+
optional:
123+
scrutineeTree =?= patternTree
127124

128125
/** Check that all trees match with `mtch` and concatenate the results with &&& */
129-
private def matchLists[T](l1: List[T], l2: List[T])(mtch: (T, T) => Matching): Matching = (l1, l2) match {
126+
private def matchLists[T](l1: List[T], l2: List[T])(mtch: (T, T) => Seq[Expr[Any]]): optional[Seq[Expr[Any]]] = (l1, l2) match {
130127
case (x :: xs, y :: ys) => mtch(x, y) &&& matchLists(xs, ys)(mtch)
131128
case (Nil, Nil) => matched
132129
case _ => notMatched
133130
}
134131

135132
extension (scrutinees: List[Tree])
136-
private def =?= (patterns: List[Tree])(using Env, Context): Matching =
133+
private def =?= (patterns: List[Tree])(using Env, Context): optional[Seq[Expr[Any]]] =
137134
matchLists(scrutinees, patterns)(_ =?= _)
138135

139136
extension (scrutinee0: Tree)
@@ -144,9 +141,9 @@ object QuoteMatcher {
144141
* @param scrutinee The tree being matched
145142
* @param pattern The pattern tree that the scrutinee should match. Contains `patternHole` holes.
146143
* @param `summon[Env]` Set of tuples containing pairs of symbols (s, p) where s defines a symbol in `scrutinee` which corresponds to symbol p in `pattern`.
147-
* @return `None` if it did not match or `Some(tup: Tuple)` if it matched where `tup` contains the contents of the holes.
144+
* @return `None` if it did not match or `Some(tup: Seq[Expr[Any]])` if it matched where `tup` contains the contents of the holes.
148145
*/
149-
private def =?= (pattern0: Tree)(using Env, Context): Matching =
146+
private def =?= (pattern0: Tree)(using Env, Context): optional[Seq[Expr[Any]]] =
150147

151148
/* Match block flattening */ // TODO move to cases
152149
/** Normalize the tree */
@@ -431,7 +428,6 @@ object QuoteMatcher {
431428
case _ => scrutinee
432429
val pattern = patternTree.symbol
433430

434-
435431
devirtualizedScrutinee == pattern
436432
|| summon[Env].get(devirtualizedScrutinee).contains(pattern)
437433
|| devirtualizedScrutinee.allOverriddenSymbols.contains(pattern)
@@ -452,32 +448,16 @@ object QuoteMatcher {
452448
accumulator.apply(Set.empty, term)
453449
}
454450

455-
/** Result of matching a part of an expression */
456-
private type Matching = Option[Tuple]
457-
458-
private object Matching {
459-
460-
def notMatched: Matching = None
451+
private inline def notMatched: optional[Seq[Expr[Any]]] =
452+
optional.break()
461453

462-
val matched: Matching = Some(Tuple())
454+
private inline def matched: Seq[Expr[Any]] =
455+
Seq.empty
463456

464-
def matched(tree: Tree)(using Context): Matching =
465-
Some(Tuple1(new ExprImpl(tree, SpliceScope.getCurrent)))
457+
private inline def matched(tree: Tree)(using Context): Seq[Expr[Any]] =
458+
Seq(new ExprImpl(tree, SpliceScope.getCurrent))
466459

467-
extension (self: Matching)
468-
def asOptionOfTuple: Option[Tuple] = self
469-
470-
/** Concatenates the contents of two successful matchings or return a `notMatched` */
471-
def &&& (that: => Matching): Matching = self match {
472-
case Some(x) =>
473-
that match {
474-
case Some(y) => Some(x ++ y)
475-
case _ => None
476-
}
477-
case _ => None
478-
}
479-
end extension
480-
481-
}
460+
extension (self: Seq[Expr[Any]])
461+
private inline def &&& (that: Seq[Expr[Any]]): Seq[Expr[Any]] = self ++ that
482462

483463
}

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

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3139,18 +3139,16 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
31393139

31403140
val matchings = QuoteMatcher.treeMatch(scrutinee, pat1)(using ctx1)
31413141

3142-
if typeHoles.isEmpty then matchings
3143-
else {
3144-
// After matching and doing all subtype checks, we have to approximate all the type bindings
3145-
// that we have found, seal them in a quoted.Type and add them to the result
3146-
def typeHoleApproximation(sym: Symbol) =
3147-
val fromAboveAnnot = sym.hasAnnotation(dotc.core.Symbols.defn.QuotedRuntimePatterns_fromAboveAnnot)
3148-
val fullBounds = ctx1.gadt.fullBounds(sym)
3149-
val tp = if fromAboveAnnot then fullBounds.hi else fullBounds.lo
3150-
reflect.TypeReprMethods.asType(tp)
3151-
matchings.map { tup =>
3152-
Tuple.fromIArray(typeHoles.map(typeHoleApproximation).toArray.asInstanceOf[IArray[Object]]) ++ tup
3153-
}
3142+
// After matching and doing all subtype checks, we have to approximate all the type bindings
3143+
// that we have found, seal them in a quoted.Type and add them to the result
3144+
def typeHoleApproximation(sym: Symbol) =
3145+
val fromAboveAnnot = sym.hasAnnotation(dotc.core.Symbols.defn.QuotedRuntimePatterns_fromAboveAnnot)
3146+
val fullBounds = ctx1.gadt.fullBounds(sym)
3147+
val tp = if fromAboveAnnot then fullBounds.hi else fullBounds.lo
3148+
reflect.TypeReprMethods.asType(tp)
3149+
matchings.map { tup =>
3150+
val results = typeHoles.map(typeHoleApproximation) ++ tup
3151+
Tuple.fromIArray(results.toArray.asInstanceOf[IArray[Object]])
31543152
}
31553153
}
31563154

0 commit comments

Comments
 (0)