Skip to content

Commit 1bedf7a

Browse files
Merge pull request #12418 from dotty-staging/improve-QuoteMatcher-performance
Improve quote matcher performance
2 parents 9d1fb4f + cc34a88 commit 1bedf7a

File tree

1 file changed

+182
-136
lines changed

1 file changed

+182
-136
lines changed

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

Lines changed: 182 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -181,26 +181,30 @@ object QuoteMatcher {
181181
case _ => None
182182
end TypeTreeTypeTest
183183

184-
(scrutinee, pattern) match
184+
val res = pattern match
185185

186186
/* Term hole */
187187
// Match a scala.internal.Quoted.patternHole typed as a repeated argument and return the scrutinee tree
188-
case (scrutinee @ Typed(s, tpt1), Typed(TypeApply(patternHole, tpt :: Nil), tpt2))
188+
case Typed(TypeApply(patternHole, tpt :: Nil), tpt2)
189189
if patternHole.symbol.eq(defn.QuotedRuntimePatterns_patternHole) &&
190-
s.tpe <:< tpt.tpe &&
191-
tpt2.tpe.derivesFrom(defn.RepeatedParamClass) =>
192-
matched(scrutinee)
190+
tpt2.tpe.derivesFrom(defn.RepeatedParamClass) =>
191+
scrutinee match
192+
case Typed(s, tpt1) if s.tpe <:< tpt.tpe => matched(scrutinee)
193+
case _ => notMatched
193194

194195
/* Term hole */
195196
// Match a scala.internal.Quoted.patternHole and return the scrutinee tree
196-
case (ClosedPatternTerm(scrutinee), TypeApply(patternHole, tpt :: Nil))
197+
case TypeApply(patternHole, tpt :: Nil)
197198
if patternHole.symbol.eq(defn.QuotedRuntimePatterns_patternHole) &&
198199
scrutinee.tpe <:< tpt.tpe =>
199-
matched(scrutinee)
200+
scrutinee match
201+
case ClosedPatternTerm(scrutinee) => matched(scrutinee)
202+
case _ => notMatched
203+
200204

201205
/* Higher order term hole */
202206
// Matches an open term and wraps it into a lambda that provides the free variables
203-
case (scrutinee, pattern @ Apply(TypeApply(Ident(_), List(TypeTree())), SeqLiteral(args, _) :: Nil))
207+
case Apply(TypeApply(Ident(_), List(TypeTree())), SeqLiteral(args, _) :: Nil)
204208
if pattern.symbol.eq(defn.QuotedRuntimePatterns_higherOrderHole) =>
205209
val names: List[TermName] = args.map {
206210
case Block(List(DefDef(nme.ANON_FUN, _, _, Apply(Ident(name), _))), _) => name.asTermName
@@ -221,138 +225,180 @@ object QuoteMatcher {
221225
}
222226
matched(Closure(meth, bodyFn))
223227

224-
//
225-
// Match two equivalent trees
226-
//
227-
228-
/* Match literal */
229-
case (Literal(constant1), Literal(constant2)) if constant1 == constant2 =>
230-
matched
231-
232-
/* Match type ascription (a) */
233-
case (Typed(expr1, _), pattern) =>
234-
expr1 =?= pattern
235-
236228
/* Match type ascription (b) */
237-
case (scrutinee, Typed(expr2, _)) =>
229+
case Typed(expr2, _) =>
238230
scrutinee =?= expr2
239231

240-
/* Match selection */
241-
case (ref: RefTree, Select(qual2, _)) if symbolMatch(scrutinee, pattern) =>
242-
ref match
243-
case Select(qual1, _) => qual1 =?= qual2
244-
case ref: Ident =>
245-
ref.tpe match
246-
case TermRef(qual: TermRef, _) => tpd.ref(qual) =?= qual2
247-
case _ => matched
248-
249-
/* Match reference */
250-
case (_: RefTree, _: Ident) if symbolMatch(scrutinee, pattern) =>
251-
matched
252-
253-
/* Match application */
254-
case (Apply(fn1, args1), Apply(fn2, args2)) =>
255-
fn1 =?= fn2 &&& args1 =?= args2
256-
257-
/* Match type application */
258-
case (TypeApply(fn1, args1), TypeApply(fn2, args2)) =>
259-
fn1 =?= fn2 &&& args1 =?= args2
260-
261-
/* Match block */
262-
case (Block(stat1 :: stats1, expr1), Block(stat2 :: stats2, expr2)) =>
263-
val newEnv = (stat1, stat2) match {
264-
case (stat1: MemberDef, stat2: MemberDef) =>
265-
summon[Env] + (stat1.symbol -> stat2.symbol)
266-
case _ =>
267-
summon[Env]
268-
}
269-
withEnv(newEnv) {
270-
stat1 =?= stat2 &&& Block(stats1, expr1) =?= Block(stats2, expr2)
271-
}
272-
273-
/* Match if */
274-
case (If(cond1, thenp1, elsep1), If(cond2, thenp2, elsep2)) =>
275-
cond1 =?= cond2 &&& thenp1 =?= thenp2 &&& elsep1 =?= elsep2
276-
277-
/* Match while */
278-
case (WhileDo(cond1, body1), WhileDo(cond2, body2)) =>
279-
cond1 =?= cond2 &&& body1 =?= body2
280-
281-
/* Match assign */
282-
case (Assign(lhs1, rhs1), Assign(lhs2, rhs2)) =>
283-
lhs1 =?= lhs2 &&& rhs1 =?= rhs2
284-
285-
/* Match new */
286-
case (New(tpt1), New(tpt2)) if tpt1.tpe.typeSymbol == tpt2.tpe.typeSymbol =>
287-
matched
288-
289-
/* Match this */
290-
case (This(_), This(_)) if scrutinee.symbol == pattern.symbol =>
291-
matched
292-
293-
/* Match super */
294-
case (Super(qual1, mix1), Super(qual2, mix2)) if mix1 == mix2 =>
295-
qual1 =?= qual2
296-
297-
/* Match varargs */
298-
case (SeqLiteral(elems1, _), SeqLiteral(elems2, _)) if elems1.size == elems2.size =>
299-
elems1 =?= elems2
300-
301-
/* Match type */
302-
// TODO remove this?
303-
case (TypeTreeTypeTest(scrutinee), TypeTreeTypeTest(pattern)) if scrutinee.tpe <:< pattern.tpe =>
304-
matched
305-
306-
/* Match val */
307-
case (scrutinee @ ValDef(_, tpt1, _), pattern @ ValDef(_, tpt2, _)) if checkValFlags() =>
308-
def rhsEnv = summon[Env] + (scrutinee.symbol -> pattern.symbol)
309-
tpt1 =?= tpt2 &&& withEnv(rhsEnv)(scrutinee.rhs =?= pattern.rhs)
310-
311-
/* Match def */
312-
case (scrutinee @ DefDef(_, paramss1, tpt1, _), pattern @ DefDef(_, paramss2, tpt2, _)) =>
313-
def rhsEnv: Env =
314-
val paramSyms: List[(Symbol, Symbol)] =
315-
for
316-
(clause1, clause2) <- paramss1.zip(paramss2)
317-
(param1, param2) <- clause1.zip(clause2)
318-
yield
319-
param1.symbol -> param2.symbol
320-
val oldEnv: Env = summon[Env]
321-
val newEnv: List[(Symbol, Symbol)] = (scrutinee.symbol -> pattern.symbol) :: paramSyms
322-
oldEnv ++ newEnv
323-
324-
matchLists(paramss1, paramss2)(_ =?= _)
325-
&&& tpt1 =?= tpt2
326-
&&& withEnv(rhsEnv)(scrutinee.rhs =?= pattern.rhs)
327-
328-
case (Closure(_, _, tpt1), Closure(_, _, tpt2)) =>
329-
// TODO match tpt1 with tpt2?
330-
matched
331-
332-
case (NamedArg(name1, arg1), NamedArg(name2, arg2)) if name1 == name2 =>
333-
arg1 =?= arg2
334-
335-
case (EmptyTree, EmptyTree) =>
336-
matched
337-
338-
// No Match
339232
case _ =>
340-
if (debug)
341-
val quotes = QuotesImpl()
342-
println(
343-
s""">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
344-
|Scrutinee
345-
| ${scrutinee.show}
346-
|did not match pattern
347-
| ${pattern.show}
348-
|
349-
|with environment: ${summon[Env]}
350-
|
351-
|Scrutinee: ${quotes.reflect.Printer.TreeStructure.show(scrutinee.asInstanceOf)}
352-
|Pattern: ${quotes.reflect.Printer.TreeStructure.show(pattern.asInstanceOf)}
353-
|
354-
|""".stripMargin)
355-
notMatched
233+
scrutinee match
234+
/* Match type ascription (a) */
235+
case Typed(expr1, _) =>
236+
expr1 =?= pattern
237+
238+
/* Match literal */
239+
case Literal(constant1) =>
240+
pattern match
241+
case Literal(constant2) if constant1 == constant2 => matched
242+
case _ => notMatched
243+
244+
case ref: RefTree =>
245+
pattern match
246+
/* Match selection */
247+
case Select(qual2, _) if symbolMatch(scrutinee, pattern) =>
248+
ref match
249+
case Select(qual1, _) => qual1 =?= qual2
250+
case ref: Ident =>
251+
ref.tpe match
252+
case TermRef(qual: TermRef, _) => tpd.ref(qual) =?= qual2
253+
case _ => matched
254+
/* Match reference */
255+
case _: Ident if symbolMatch(scrutinee, pattern) => matched
256+
/* Match type */
257+
case TypeTreeTypeTest(pattern) if scrutinee.tpe <:< pattern.tpe => matched
258+
case _ => notMatched
259+
260+
/* Match application */
261+
case Apply(fn1, args1) =>
262+
pattern match
263+
case Apply(fn2, args2) =>
264+
fn1 =?= fn2 &&& args1 =?= args2
265+
case _ => notMatched
266+
267+
/* Match type application */
268+
case TypeApply(fn1, args1) =>
269+
pattern match
270+
case TypeApply(fn2, args2) =>
271+
fn1 =?= fn2 &&& args1 =?= args2
272+
case _ => notMatched
273+
274+
/* Match block */
275+
case Block(stat1 :: stats1, expr1) =>
276+
pattern match
277+
case Block(stat2 :: stats2, expr2) =>
278+
val newEnv = (stat1, stat2) match {
279+
case (stat1: MemberDef, stat2: MemberDef) =>
280+
summon[Env] + (stat1.symbol -> stat2.symbol)
281+
case _ =>
282+
summon[Env]
283+
}
284+
withEnv(newEnv) {
285+
stat1 =?= stat2 &&& Block(stats1, expr1) =?= Block(stats2, expr2)
286+
}
287+
case _ => notMatched
288+
289+
/* Match if */
290+
case If(cond1, thenp1, elsep1) =>
291+
pattern match
292+
case If(cond2, thenp2, elsep2) =>
293+
cond1 =?= cond2 &&& thenp1 =?= thenp2 &&& elsep1 =?= elsep2
294+
case _ => notMatched
295+
296+
/* Match while */
297+
case WhileDo(cond1, body1) =>
298+
pattern match
299+
case WhileDo(cond2, body2) => cond1 =?= cond2 &&& body1 =?= body2
300+
case _ => notMatched
301+
302+
/* Match assign */
303+
case Assign(lhs1, rhs1) =>
304+
pattern match
305+
case Assign(lhs2, rhs2) => lhs1 =?= lhs2 &&& rhs1 =?= rhs2
306+
case _ => notMatched
307+
308+
/* Match new */
309+
case New(tpt1) =>
310+
pattern match
311+
case New(tpt2) if tpt1.tpe.typeSymbol == tpt2.tpe.typeSymbol => matched
312+
case _ => notMatched
313+
314+
/* Match this */
315+
case This(_) =>
316+
pattern match
317+
case This(_) if scrutinee.symbol == pattern.symbol => matched
318+
case _ => notMatched
319+
320+
/* Match super */
321+
case Super(qual1, mix1) =>
322+
pattern match
323+
case Super(qual2, mix2) if mix1 == mix2 => qual1 =?= qual2
324+
case _ => notMatched
325+
326+
/* Match varargs */
327+
case SeqLiteral(elems1, _) =>
328+
pattern match
329+
case SeqLiteral(elems2, _) if elems1.size == elems2.size => elems1 =?= elems2
330+
case _ => notMatched
331+
332+
/* Match type */
333+
// TODO remove this?
334+
case TypeTreeTypeTest(scrutinee) =>
335+
pattern match
336+
case TypeTreeTypeTest(pattern) if scrutinee.tpe <:< pattern.tpe => matched
337+
case _ => notMatched
338+
339+
/* Match val */
340+
case scrutinee @ ValDef(_, tpt1, _) =>
341+
pattern match
342+
case pattern @ ValDef(_, tpt2, _) if checkValFlags() =>
343+
def rhsEnv = summon[Env] + (scrutinee.symbol -> pattern.symbol)
344+
tpt1 =?= tpt2 &&& withEnv(rhsEnv)(scrutinee.rhs =?= pattern.rhs)
345+
case _ => notMatched
346+
347+
/* Match def */
348+
case scrutinee @ DefDef(_, paramss1, tpt1, _) =>
349+
pattern match
350+
case pattern @ DefDef(_, paramss2, tpt2, _) =>
351+
def rhsEnv: Env =
352+
val paramSyms: List[(Symbol, Symbol)] =
353+
for
354+
(clause1, clause2) <- paramss1.zip(paramss2)
355+
(param1, param2) <- clause1.zip(clause2)
356+
yield
357+
param1.symbol -> param2.symbol
358+
val oldEnv: Env = summon[Env]
359+
val newEnv: List[(Symbol, Symbol)] = (scrutinee.symbol -> pattern.symbol) :: paramSyms
360+
oldEnv ++ newEnv
361+
matchLists(paramss1, paramss2)(_ =?= _)
362+
&&& tpt1 =?= tpt2
363+
&&& withEnv(rhsEnv)(scrutinee.rhs =?= pattern.rhs)
364+
case _ => notMatched
365+
366+
case Closure(_, _, tpt1) =>
367+
pattern match
368+
case Closure(_, _, tpt2) => matched // TODO match tpt1 with tpt2?
369+
case _ => notMatched
370+
371+
case NamedArg(name1, arg1) =>
372+
pattern match
373+
case NamedArg(name2, arg2) if name1 == name2 => arg1 =?= arg2
374+
case _ => notMatched
375+
376+
case EmptyTree =>
377+
if pattern.isEmpty then matched
378+
else notMatched
379+
380+
// No Match
381+
case _ =>
382+
notMatched
383+
384+
if (debug && res == notMatched)
385+
val quotes = QuotesImpl()
386+
println(
387+
s""">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
388+
|Scrutinee
389+
| ${scrutinee.show}
390+
|did not match pattern
391+
| ${pattern.show}
392+
|
393+
|with environment: ${summon[Env]}
394+
|
395+
|Scrutinee: ${quotes.reflect.Printer.TreeStructure.show(scrutinee.asInstanceOf)}
396+
|Pattern: ${quotes.reflect.Printer.TreeStructure.show(pattern.asInstanceOf)}
397+
|
398+
|""".stripMargin)
399+
400+
res
401+
end =?=
356402

357403
end extension
358404

0 commit comments

Comments
 (0)