Skip to content

Commit a57e749

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

File tree

3 files changed

+49
-47
lines changed

3 files changed

+49
-47
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: 20 additions & 35 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,12 +103,13 @@ 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._
109+
/** Sequence of matched expressions.
110+
* These expressions are part of the scrutinee and will be bound to the quote pattern term splices.
111+
*/
112+
type MatchingExps = Seq[Expr[Any]]
112113

113114
/** A map relating equivalent symbols from the scrutinee and the pattern
114115
* For example in
@@ -121,19 +122,20 @@ object QuoteMatcher {
121122

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

124-
def treeMatch(scrutineeTree: Tree, patternTree: Tree)(using Context): Option[Tuple] =
125+
def treeMatch(scrutineeTree: Tree, patternTree: Tree)(using Context): Option[MatchingExps] =
125126
given Env = Map.empty
126-
scrutineeTree =?= patternTree
127+
optional:
128+
scrutineeTree =?= patternTree
127129

128130
/** 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 {
131+
private def matchLists[T](l1: List[T], l2: List[T])(mtch: (T, T) => MatchingExps): optional[MatchingExps] = (l1, l2) match {
130132
case (x :: xs, y :: ys) => mtch(x, y) &&& matchLists(xs, ys)(mtch)
131133
case (Nil, Nil) => matched
132134
case _ => notMatched
133135
}
134136

135137
extension (scrutinees: List[Tree])
136-
private def =?= (patterns: List[Tree])(using Env, Context): Matching =
138+
private def =?= (patterns: List[Tree])(using Env, Context): optional[MatchingExps] =
137139
matchLists(scrutinees, patterns)(_ =?= _)
138140

139141
extension (scrutinee0: Tree)
@@ -144,9 +146,9 @@ object QuoteMatcher {
144146
* @param scrutinee The tree being matched
145147
* @param pattern The pattern tree that the scrutinee should match. Contains `patternHole` holes.
146148
* @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.
149+
* @return `None` if it did not match or `Some(tup: MatchingExps)` if it matched where `tup` contains the contents of the holes.
148150
*/
149-
private def =?= (pattern0: Tree)(using Env, Context): Matching =
151+
private def =?= (pattern0: Tree)(using Env, Context): optional[MatchingExps] =
150152

151153
/* Match block flattening */ // TODO move to cases
152154
/** Normalize the tree */
@@ -431,7 +433,6 @@ object QuoteMatcher {
431433
case _ => scrutinee
432434
val pattern = patternTree.symbol
433435

434-
435436
devirtualizedScrutinee == pattern
436437
|| summon[Env].get(devirtualizedScrutinee).contains(pattern)
437438
|| devirtualizedScrutinee.allOverriddenSymbols.contains(pattern)
@@ -452,32 +453,16 @@ object QuoteMatcher {
452453
accumulator.apply(Set.empty, term)
453454
}
454455

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
456+
private inline def notMatched: optional[MatchingExps] =
457+
optional.break()
461458

462-
val matched: Matching = Some(Tuple())
459+
private inline def matched: MatchingExps =
460+
Seq.empty
463461

464-
def matched(tree: Tree)(using Context): Matching =
465-
Some(Tuple1(new ExprImpl(tree, SpliceScope.getCurrent)))
462+
private inline def matched(tree: Tree)(using Context): MatchingExps =
463+
Seq(new ExprImpl(tree, SpliceScope.getCurrent))
466464

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-
}
465+
extension (self: MatchingExps)
466+
private inline def &&& (that: MatchingExps): MatchingExps = self ++ that
482467

483468
}

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)