Skip to content

Commit ab5059f

Browse files
Merge pull request #9904 from dotty-staging/refactor-quote-pattern-entry-points
Refactor quote matching internal logic
2 parents 015bbbb + 671201b commit ab5059f

File tree

15 files changed

+205
-244
lines changed

15 files changed

+205
-244
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ object desugar {
922922
def quotedPatternTypeDef(tree: TypeDef)(using Context): TypeDef = {
923923
assert(ctx.mode.is(Mode.QuotedPattern))
924924
if (tree.name.startsWith("$") && !tree.isBackquoted) {
925-
val patternBindHoleAnnot = New(ref(defn.InternalQuotedMatcher_patternTypeAnnot.typeRef)).withSpan(tree.span)
925+
val patternBindHoleAnnot = New(ref(defn.InternalQuotedPatterns_patternTypeAnnot.typeRef)).withSpan(tree.span)
926926
val mods = tree.mods.withAddedAnnotation(patternBindHoleAnnot)
927927
tree.withMods(mods)
928928
}

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -808,12 +808,12 @@ class Definitions {
808808
@tu lazy val InternalQuoted_exprNestedSplice : Symbol = InternalQuotedModule.requiredMethod("exprNestedSplice")
809809
@tu lazy val InternalQuoted_QuoteTypeTagAnnot: ClassSymbol = InternalQuotedModule.requiredClass("quoteTypeTag")
810810

811-
@tu lazy val InternalQuotedMatcher: Symbol = requiredModule("scala.internal.quoted.Matcher")
812-
@tu lazy val InternalQuotedMatcher_patternHole: Symbol = InternalQuotedMatcher.requiredMethod("patternHole")
813-
@tu lazy val InternalQuotedMatcher_patternHigherOrderHole: Symbol = InternalQuotedMatcher.requiredMethod("patternHigherOrderHole")
814-
@tu lazy val InternalQuotedMatcher_higherOrderHole: Symbol = InternalQuotedMatcher.requiredMethod("higherOrderHole")
815-
@tu lazy val InternalQuotedMatcher_patternTypeAnnot: ClassSymbol = InternalQuotedMatcher.requiredClass("patternType")
816-
@tu lazy val InternalQuotedMatcher_fromAboveAnnot: ClassSymbol = InternalQuotedMatcher.requiredClass("fromAbove")
811+
@tu lazy val InternalQuotedPatterns: Symbol = requiredModule("scala.internal.quoted.Patterns")
812+
@tu lazy val InternalQuotedPatterns_patternHole: Symbol = InternalQuotedPatterns.requiredMethod("patternHole")
813+
@tu lazy val InternalQuotedPatterns_patternHigherOrderHole: Symbol = InternalQuotedPatterns.requiredMethod("patternHigherOrderHole")
814+
@tu lazy val InternalQuotedPatterns_higherOrderHole: Symbol = InternalQuotedPatterns.requiredMethod("higherOrderHole")
815+
@tu lazy val InternalQuotedPatterns_patternTypeAnnot: ClassSymbol = InternalQuotedPatterns.requiredClass("patternType")
816+
@tu lazy val InternalQuotedPatterns_fromAboveAnnot: ClassSymbol = InternalQuotedPatterns.requiredClass("fromAbove")
817817

818818
@tu lazy val InternalQuotedExprModule: Symbol = requiredModule("scala.internal.quoted.Expr")
819819
@tu lazy val InternalQuotedExpr_unapply: Symbol = InternalQuotedExprModule.requiredMethod(nme.unapply)

library/src-bootstrapped/scala/internal/quoted/Matcher.scala renamed to compiler/src/dotty/tools/dotc/quoted/Matcher.scala

Lines changed: 11 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package scala.internal.quoted
1+
package dotty.tools.dotc.quoted
22

33
import scala.annotation.internal.sharable
44
import scala.annotation.{Annotation, compileTimeOnly}
@@ -98,33 +98,8 @@ import scala.internal.tasty.CompilerInterface.quoteContextWithCompilerInterface
9898
*/
9999
object Matcher {
100100

101-
/** A splice in a quoted pattern is desugared by the compiler into a call to this method */
102-
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternHole`")
103-
def patternHole[T]: T = ???
104-
105-
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternHigherOrderHole`")
106-
/** A higher order splice in a quoted pattern is desugared by the compiler into a call to this method */
107-
def patternHigherOrderHole[U](pat: Any, args: Any*): U = ???
108-
109-
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.higherOrderHole`")
110-
/** A higher order splice in a quoted pattern is desugared by the compiler into a call to this method */
111-
def higherOrderHole[U](args: Any*): U = ???
112-
113-
// TODO remove
114-
/** A splice of a name in a quoted pattern is desugared by wrapping getting this annotation */
115-
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternBindHole`")
116-
class patternBindHole extends Annotation
117-
118-
/** A splice of a name in a quoted pattern is that marks the definition of a type splice */
119-
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternType`")
120-
class patternType extends Annotation
121-
122-
/** A type pattern that must be aproximated from above */
123-
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.fromAbove`")
124-
class fromAbove extends Annotation
125-
126101
class QuoteMatcher[QCtx <: QuoteContext & Singleton](val qctx0: QCtx) {
127-
val qctx = quoteContextWithCompilerInterface(qctx0)
102+
val qctx = qctx0.asInstanceOf[qctx0.type { val tasty: qctx0.tasty.type & scala.internal.tasty.CompilerInterface }]
128103

129104
// TODO improve performance
130105

@@ -145,54 +120,13 @@ object Matcher {
145120

146121
inline private def withEnv[T](env: Env)(inline body: Env ?=> T): T = body(using env)
147122

148-
class SymBinding(val sym: Symbol, val fromAbove: Boolean)
149-
150-
def termMatch(scrutineeTerm: Term, patternTerm: Term, hasTypeSplices: Boolean): Option[Tuple] = {
123+
def termMatch(scrutineeTerm: Term, patternTerm: Term): Option[Tuple] =
151124
given Env = Map.empty
152-
val matchings = scrutineeTerm =?= patternTerm
153-
if !hasTypeSplices then matchings
154-
else {
155-
// After matching and doing all subtype checks, we have to approximate all the type bindings
156-
// that we have found and seal them in a quoted.Type
157-
matchings.asOptionOfTuple.map { tup =>
158-
Tuple.fromArray(tup.toArray.map { // TODO improve performance
159-
case x: SymBinding => qctx.tasty.Constraints_approximation(x.sym, !x.fromAbove).seal
160-
case x => x
161-
})
162-
}
163-
}
164-
}
125+
scrutineeTerm =?= patternTerm
165126

166-
// TODO factor out common logic with `termMatch`
167-
def typeTreeMatch(scrutineeTypeTree: TypeTree, patternTypeTree: TypeTree, hasTypeSplices: Boolean): Option[Tuple] = {
127+
def typeTreeMatch(scrutineeTypeTree: TypeTree, patternTypeTree: TypeTree): Option[Tuple] =
168128
given Env = Map.empty
169-
val matchings = scrutineeTypeTree =?= patternTypeTree
170-
if !hasTypeSplices then matchings
171-
else {
172-
// After matching and doing all subtype checks, we have to approximate all the type bindings
173-
// that we have found and seal them in a quoted.Type
174-
matchings.asOptionOfTuple.map { tup =>
175-
Tuple.fromArray(tup.toArray.map { // TODO improve performance
176-
case x: SymBinding => qctx.tasty.Constraints_approximation(x.sym, !x.fromAbove).seal
177-
case x => x
178-
})
179-
}
180-
}
181-
}
182-
183-
private def hasPatternTypeAnnotation(sym: Symbol) = sym.annots.exists(isPatternTypeAnnotation)
184-
185-
private def hasFromAboveAnnotation(sym: Symbol) = sym.annots.exists(isFromAboveAnnotation)
186-
187-
private def isPatternTypeAnnotation(tree: Tree): Boolean = tree match {
188-
case New(tpt) => tpt.symbol == qctx.tasty.Definitions_InternalQuotedMatcher_patternTypeAnnot
189-
case annot => annot.symbol.owner == qctx.tasty.Definitions_InternalQuotedMatcher_patternTypeAnnot
190-
}
191-
192-
private def isFromAboveAnnotation(tree: Tree): Boolean = tree match {
193-
case New(tpt) => tpt.symbol == qctx.tasty.Definitions_InternalQuotedMatcher_fromAboveAnnot
194-
case annot => annot.symbol.owner == qctx.tasty.Definitions_InternalQuotedMatcher_fromAboveAnnot
195-
}
129+
scrutineeTypeTree =?= patternTypeTree
196130

197131
/** Check that all trees match with `mtch` and concatenate the results with &&& */
198132
private def matchLists[T](l1: List[T], l2: List[T])(mtch: (T, T) => Matching): Matching = (l1, l2) match {
@@ -244,23 +178,23 @@ object Matcher {
244178

245179
/* Term hole */
246180
// Match a scala.internal.Quoted.patternHole typed as a repeated argument and return the scrutinee tree
247-
case (scrutinee as Typed(s, tpt1), Typed(TypeApply(patternHole, tpt :: Nil), tpt2))
248-
if patternHole.symbol == qctx.tasty.Definitions_InternalQuotedMatcher_patternHole &&
181+
case (scrutinee @ Typed(s, tpt1), Typed(TypeApply(patternHole, tpt :: Nil), tpt2))
182+
if patternHole.symbol == qctx.tasty.Definitions_InternalQuotedPatterns_patternHole &&
249183
s.tpe <:< tpt.tpe &&
250184
tpt2.tpe.derivesFrom(defn.RepeatedParamClass) =>
251185
matched(scrutinee.seal)
252186

253187
/* Term hole */
254188
// Match a scala.internal.Quoted.patternHole and return the scrutinee tree
255189
case (ClosedPatternTerm(scrutinee), TypeApply(patternHole, tpt :: Nil))
256-
if patternHole.symbol == qctx.tasty.Definitions_InternalQuotedMatcher_patternHole &&
190+
if patternHole.symbol == qctx.tasty.Definitions_InternalQuotedPatterns_patternHole &&
257191
scrutinee.tpe <:< tpt.tpe =>
258192
matched(scrutinee.seal)
259193

260194
/* Higher order term hole */
261195
// Matches an open term and wraps it into a lambda that provides the free variables
262-
case (scrutinee, pattern as Apply(TypeApply(Ident("higherOrderHole"), List(Inferred())), Repeated(args, _) :: Nil))
263-
if pattern.symbol == qctx.tasty.Definitions_InternalQuotedMatcher_higherOrderHole =>
196+
case (scrutinee, pattern @ Apply(TypeApply(Ident("higherOrderHole"), List(Inferred())), Repeated(args, _) :: Nil))
197+
if pattern.symbol == qctx.tasty.Definitions_InternalQuotedPatterns_higherOrderHole =>
264198

265199
def bodyFn(lambdaArgs: List[Tree]): Tree = {
266200
val argsMap = args.map(_.symbol).zip(lambdaArgs.asInstanceOf[List[Term]]).toMap
@@ -317,10 +251,6 @@ object Matcher {
317251
case (TypeApply(fn1, args1), TypeApply(fn2, args2)) =>
318252
fn1 =?= fn2 &&& args1 =?= args2
319253

320-
case (Block(stats1, expr1), Block(binding :: stats2, expr2)) if isTypeBinding(binding) =>
321-
qctx.tasty.Constraints_add(binding.symbol :: Nil)
322-
matched(new SymBinding(binding.symbol, hasFromAboveAnnotation(binding.symbol))) &&& Block(stats1, expr1) =?= Block(stats2, expr2)
323-
324254
/* Match block */
325255
case (Block(stat1 :: stats1, expr1), Block(stat2 :: stats2, expr2)) =>
326256
val newEnv = (stat1, stat2) match {
@@ -333,11 +263,6 @@ object Matcher {
333263
stat1 =?= stat2 &&& Block(stats1, expr1) =?= Block(stats2, expr2)
334264
}
335265

336-
case (scrutinee, Block(typeBindings, expr2)) if typeBindings.forall(isTypeBinding) =>
337-
val bindingSymbols = typeBindings.map(_.symbol)
338-
qctx.tasty.Constraints_add(bindingSymbols)
339-
bindingSymbols.foldRight(scrutinee =?= expr2)((x, acc) => matched(new SymBinding(x, hasFromAboveAnnotation(x))) &&& acc)
340-
341266
/* Match if */
342267
case (If(cond1, thenp1, elsep1), If(cond2, thenp2, elsep2)) =>
343268
cond1 =?= cond2 &&& thenp1 =?= thenp2 &&& elsep1 =?= elsep2
@@ -456,10 +381,6 @@ object Matcher {
456381
}
457382
}
458383

459-
private def isTypeBinding(tree: Tree): Boolean = tree match {
460-
case tree: TypeDef => hasPatternTypeAnnotation(tree.symbol)
461-
case _ => false
462-
}
463384
}
464385

465386
/** Result of matching a part of an expression */

compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2546,20 +2546,62 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext:
25462546
def unpickleType(repr: Unpickler.PickledQuote, args: Unpickler.PickledArgs): TypeTree =
25472547
PickledQuotes.unpickleType(repr, args)
25482548

2549-
def Constraints_context[T]: scala.quoted.QuoteContext =
2550-
val ctx1 = ctx.fresh.setFreshGADTBounds.addMode(dotc.core.Mode.GadtConstraintInference)
2551-
dotty.tools.dotc.quoted.QuoteContextImpl()(using ctx1)
2549+
def termMatch(scrutinee: Term, pattern: Term): Option[Tuple] =
2550+
treeMatch(scrutinee, pattern)
2551+
2552+
def typeTreeMatch(scrutinee: TypeTree, pattern: TypeTree): Option[Tuple] =
2553+
treeMatch(scrutinee, pattern)
2554+
2555+
private def treeMatch(scrutinee: Tree, pattern: Tree): Option[Tuple] = {
2556+
def isTypeHoleDef(tree: Tree): Boolean =
2557+
tree match
2558+
case tree: TypeDef =>
2559+
tree.symbol.hasAnnotation(dotc.core.Symbols.defn.InternalQuotedPatterns_patternTypeAnnot)
2560+
case _ => false
2561+
2562+
def extractTypeHoles(pat: Term): (Term, List[Symbol]) =
2563+
pat match
2564+
case tpd.Inlined(_, Nil, pat2) => extractTypeHoles(pat2)
2565+
case tpd.Block(stats @ ((typeHole: TypeDef) :: _), expr) if isTypeHoleDef(typeHole) =>
2566+
val holes = stats.takeWhile(isTypeHoleDef).map(_.symbol)
2567+
val otherStats = stats.dropWhile(isTypeHoleDef)
2568+
(tpd.cpy.Block(pat)(otherStats, expr), holes)
2569+
case _ =>
2570+
(pat, Nil)
25522571

2553-
def Constraints_add(syms: List[Symbol]): Boolean =
2554-
ctx.gadt.addToConstraint(syms)
2572+
val (pat1, typeHoles) = extractTypeHoles(pattern)
25552573

2556-
def Constraints_approximation(sym: Symbol, fromBelow: Boolean): Type =
2557-
ctx.gadt.approximation(sym, fromBelow)
2574+
val ctx1 =
2575+
if typeHoles.isEmpty then ctx
2576+
else
2577+
val ctx1 = ctx.fresh.setFreshGADTBounds.addMode(dotc.core.Mode.GadtConstraintInference)
2578+
ctx1.gadt.addToConstraint(typeHoles)
2579+
ctx1
2580+
2581+
val qctx1 = dotty.tools.dotc.quoted.QuoteContextImpl()(using ctx1)
2582+
.asInstanceOf[QuoteContext { val tasty: QuoteContextImpl.this.tasty.type }]
2583+
2584+
val matcher = new Matcher.QuoteMatcher[qctx1.type](qctx1)
2585+
2586+
val matchings =
2587+
if pat1.isType then matcher.termMatch(scrutinee, pat1)
2588+
else matcher.termMatch(scrutinee, pat1)
2589+
2590+
// val matchings = matcher.termMatch(scrutinee, pattern)
2591+
if typeHoles.isEmpty then matchings
2592+
else {
2593+
// After matching and doing all subtype checks, we have to approximate all the type bindings
2594+
// that we have found, seal them in a quoted.Type and add them to the result
2595+
def typeHoleApproximation(sym: Symbol) =
2596+
ctx1.gadt.approximation(sym, !sym.hasAnnotation(dotc.core.Symbols.defn.InternalQuotedPatterns_fromAboveAnnot)).seal
2597+
matchings.map { tup =>
2598+
Tuple.fromIArray(typeHoles.map(typeHoleApproximation).toArray.asInstanceOf[IArray[Object]]) ++ tup
2599+
}
2600+
}
2601+
}
25582602

2559-
def Definitions_InternalQuotedMatcher_patternHole: Symbol = dotc.core.Symbols.defn.InternalQuotedMatcher_patternHole
2560-
def Definitions_InternalQuotedMatcher_higherOrderHole: Symbol = dotc.core.Symbols.defn.InternalQuotedMatcher_higherOrderHole
2561-
def Definitions_InternalQuotedMatcher_patternTypeAnnot: Symbol = dotc.core.Symbols.defn.InternalQuotedMatcher_patternTypeAnnot
2562-
def Definitions_InternalQuotedMatcher_fromAboveAnnot: Symbol = dotc.core.Symbols.defn.InternalQuotedMatcher_fromAboveAnnot
2603+
def Definitions_InternalQuotedPatterns_patternHole: Symbol = dotc.core.Symbols.defn.InternalQuotedPatterns_patternHole
2604+
def Definitions_InternalQuotedPatterns_higherOrderHole: Symbol = dotc.core.Symbols.defn.InternalQuotedPatterns_higherOrderHole
25632605

25642606
def betaReduce(tree: Term): Option[Term] =
25652607
tree match

compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ trait QuotesAndSplices {
139139
report.error("Missing arguments for open pattern", tree.srcPos)
140140
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
141141
val typedPat = typedSplice(splice, defn.FunctionOf(argTypes, pt))
142-
ref(defn.InternalQuotedMatcher_patternHigherOrderHole).appliedToType(pt).appliedTo(typedPat, SeqLiteral(typedArgs, TypeTree(defn.AnyType)))
142+
ref(defn.InternalQuotedPatterns_patternHigherOrderHole).appliedToType(pt).appliedTo(typedPat, SeqLiteral(typedArgs, TypeTree(defn.AnyType)))
143143
}
144144

145145
/** Translate ${ t: Type[T] }` into type `t.splice` while tracking the quotation level in the context */
@@ -166,7 +166,7 @@ trait QuotesAndSplices {
166166
case pt: TypeBounds => pt
167167
case _ => TypeBounds.empty
168168
val typeSym = newSymbol(spliceOwner(ctx), name, EmptyFlags, typeSymInfo, NoSymbol, tree.expr.span)
169-
typeSym.addAnnotation(Annotation(New(ref(defn.InternalQuotedMatcher_patternTypeAnnot.typeRef)).withSpan(tree.expr.span)))
169+
typeSym.addAnnotation(Annotation(New(ref(defn.InternalQuotedPatterns_patternTypeAnnot.typeRef)).withSpan(tree.expr.span)))
170170
val pat = typedPattern(tree.expr, defn.QuotedTypeClass.typeRef.appliedTo(typeSym.typeRef))(
171171
using spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
172172
pat.select(tpnme.spliceType)
@@ -236,20 +236,20 @@ trait QuotesAndSplices {
236236
val exprTpt = AppliedTypeTree(TypeTree(defn.QuotedExprClass.typeRef), tpt1 :: Nil)
237237
val newSplice = ref(defn.InternalQuoted_exprSplice).appliedToType(tpt1.tpe).appliedTo(Typed(pat, exprTpt))
238238
transform(newSplice)
239-
case Apply(TypeApply(fn, targs), Apply(sp, pat :: Nil) :: args :: Nil) if fn.symbol == defn.InternalQuotedMatcher_patternHigherOrderHole =>
239+
case Apply(TypeApply(fn, targs), Apply(sp, pat :: Nil) :: args :: Nil) if fn.symbol == defn.InternalQuotedPatterns_patternHigherOrderHole =>
240240
args match // TODO support these patterns. Possibly using scala.quoted.util.Var
241241
case SeqLiteral(args, _) =>
242242
for arg <- args; if arg.symbol.is(Mutable) do
243243
report.error("References to `var`s cannot be used in higher-order pattern", arg.srcPos)
244-
try ref(defn.InternalQuotedMatcher_higherOrderHole.termRef).appliedToTypeTrees(targs).appliedTo(args).withSpan(tree.span)
244+
try ref(defn.InternalQuotedPatterns_higherOrderHole.termRef).appliedToTypeTrees(targs).appliedTo(args).withSpan(tree.span)
245245
finally {
246246
val patType = pat.tpe.widen
247247
val patType1 = patType.translateFromRepeated(toArray = false)
248248
val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
249249
patBuf += pat1
250250
}
251251
case Apply(fn, pat :: Nil) if fn.symbol.isExprSplice =>
252-
try ref(defn.InternalQuotedMatcher_patternHole.termRef).appliedToType(tree.tpe).withSpan(tree.span)
252+
try ref(defn.InternalQuotedPatterns_patternHole.termRef).appliedToType(tree.tpe).withSpan(tree.span)
253253
finally {
254254
val patType = pat.tpe.widen
255255
val patType1 = patType.translateFromRepeated(toArray = false)
@@ -265,7 +265,7 @@ trait QuotesAndSplices {
265265
else
266266
tree
267267
case tdef: TypeDef =>
268-
if tdef.symbol.hasAnnotation(defn.InternalQuotedMatcher_patternTypeAnnot) then
268+
if tdef.symbol.hasAnnotation(defn.InternalQuotedPatterns_patternTypeAnnot) then
269269
transformTypeBindingTypeDef(tdef, typePatBuf)
270270
else if tdef.symbol.isClass then
271271
val kind = if tdef.symbol.is(Module) then "objects" else "classes"
@@ -304,7 +304,7 @@ trait QuotesAndSplices {
304304

305305
private def transformTypeBindingTypeDef(tdef: TypeDef, buff: mutable.Builder[Tree, List[Tree]])(using Context): Tree = {
306306
if (variance == -1)
307-
tdef.symbol.addAnnotation(Annotation(New(ref(defn.InternalQuotedMatcher_fromAboveAnnot.typeRef)).withSpan(tdef.span)))
307+
tdef.symbol.addAnnotation(Annotation(New(ref(defn.InternalQuotedPatterns_fromAboveAnnot.typeRef)).withSpan(tdef.span)))
308308
val bindingType = getBinding(tdef.symbol).symbol.typeRef
309309
val bindingTypeTpe = AppliedType(defn.QuotedTypeClass.typeRef, bindingType :: Nil)
310310
val bindName = tdef.name.toString.stripPrefix("$").toTermName
@@ -450,7 +450,7 @@ trait QuotesAndSplices {
450450
else ref(defn.QuotedTypeModule_apply.termRef).appliedToTypeTree(shape).select(nme.apply).appliedTo(qctx)
451451
UnApply(
452452
fun = ref(unapplySym.termRef).appliedToTypeTrees(typeBindingsTuple :: TypeTree(patType) :: Nil),
453-
implicits = quotedPattern :: Literal(Constant(typeBindings.nonEmpty)) :: qctx :: Nil,
453+
implicits = quotedPattern :: qctx :: Nil,
454454
patterns = splicePat :: Nil,
455455
proto = quoteClass.typeRef.appliedTo(replaceBindings(quoted1.tpe) & quotedPt))
456456
}

0 commit comments

Comments
 (0)