Skip to content

Commit ca42229

Browse files
committed
Fix #8997: Support multiple contextual parameter blocks on unapply
1 parent b5eded6 commit ca42229

File tree

3 files changed

+29
-11
lines changed

3 files changed

+29
-11
lines changed

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,9 +378,16 @@ object PatternMatcher {
378378
// This plan will never execute because it'll be guarded by a `NonNullTest`.
379379
ResultPlan(tpd.Throw(tpd.nullLiteral))
380380
else {
381+
def applyImplicits(acc: Tree, implicits: List[Tree], mt: Type): Tree = mt match {
382+
case mt: MethodType =>
383+
assert(mt.isImplicitMethod || mt.isContextualMethod)
384+
val (args, rest) = implicits.splitAt(mt.paramNames.size)
385+
applyImplicits(acc.appliedToArgs(args), rest, mt.resultType)
386+
case _ => acc
387+
}
381388
val mt @ MethodType(_) = extractor.tpe.widen
382-
var unapp = extractor.appliedTo(ref(scrutinee).ensureConforms(mt.paramInfos.head))
383-
if (implicits.nonEmpty) unapp = unapp.appliedToArgs(implicits)
389+
val unapp0 = extractor.appliedTo(ref(scrutinee).ensureConforms(mt.paramInfos.head))
390+
val unapp = applyImplicits(unapp0, implicits, mt.resultType)
384391
unapplyPlan(unapp, args)
385392
}
386393
if (scrutinee.info.isNotNull || nonNull(scrutinee)) unappPlan

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

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,14 +1226,18 @@ trait Applications extends Compatibility {
12261226
}
12271227
val dummyArg = dummyTreeOfType(ownType)
12281228
val unapplyApp = typedExpr(untpd.TypedSplice(Apply(unapplyFn, dummyArg :: Nil)))
1229-
def unapplyImplicits(unapp: Tree): List[Tree] = unapp match {
1230-
case Apply(Apply(unapply, `dummyArg` :: Nil), args2) => assert(args2.nonEmpty); args2
1231-
case Apply(unapply, `dummyArg` :: Nil) => Nil
1232-
case Inlined(u, _, _) => unapplyImplicits(u)
1233-
case DynamicUnapply(_) =>
1234-
ctx.error("Structural unapply is not supported", unapplyFn.sourcePos)
1235-
Nil
1236-
case _ => Nil.assertingErrorsReported
1229+
def unapplyImplicits(unapp: Tree): List[List[Tree]] = {
1230+
val res = List.newBuilder[List[Tree]]
1231+
def loop(unapp: Tree): Unit = unapp match {
1232+
case Apply(Apply(unapply, `dummyArg` :: Nil), args2) => assert(args2.nonEmpty); res += args2
1233+
case Apply(unapply, `dummyArg` :: Nil) =>
1234+
case Inlined(u, _, _) => loop(u)
1235+
case DynamicUnapply(_) => ctx.error("Structural unapply is not supported", unapplyFn.sourcePos)
1236+
case Apply(fn, args) => assert(args.nonEmpty); loop(fn); res += args
1237+
case _ => ().assertingErrorsReported
1238+
}
1239+
loop(unapp)
1240+
res.result()
12371241
}
12381242

12391243
var argTypes = unapplyArgs(unapplyApp.tpe, unapplyFn, args, tree.sourcePos)
@@ -1250,7 +1254,7 @@ trait Applications extends Compatibility {
12501254
List.fill(argTypes.length - args.length)(WildcardType)
12511255
}
12521256
val unapplyPatterns = bunchedArgs.lazyZip(argTypes) map (typed(_, _))
1253-
val result = assignType(cpy.UnApply(tree)(unapplyFn, unapplyImplicits(unapplyApp), unapplyPatterns), ownType)
1257+
val result = assignType(cpy.UnApply(tree)(unapplyFn, unapplyImplicits(unapplyApp).flatten, unapplyPatterns), ownType)
12541258
unapp.println(s"unapply patterns = $unapplyPatterns")
12551259
if ((ownType eq selType) || ownType.isError) result
12561260
else tryWithClassTag(Typed(result, TypeTree(ownType)), selType)

tests/pos/i8997.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object Foo:
2+
def unapply(n: Int)(using x: DummyImplicit)(using y: Int): Option[Int] = ???
3+
4+
def test =
5+
given Int = 3
6+
1 match
7+
case Foo(_) =>

0 commit comments

Comments
 (0)