Skip to content

Commit ab9bf66

Browse files
Merge pull request #9003 from dotty-staging/fix-#8997
Fix #8997: Support multiple contextual parameter blocks on unapply
2 parents 420822b + ac031b5 commit ab9bf66

File tree

3 files changed

+30
-10
lines changed

3 files changed

+30
-10
lines changed

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,9 +378,18 @@ 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 _ =>
387+
assert(implicits.isEmpty)
388+
acc
389+
}
381390
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)
391+
val unapp0 = extractor.appliedTo(ref(scrutinee).ensureConforms(mt.paramInfos.head))
392+
val unapp = applyImplicits(unapp0, implicits, mt.resultType)
384393
unapplyPlan(unapp, args)
385394
}
386395
if (scrutinee.info.isNotNull || nonNull(scrutinee)) unappPlan

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

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

12411245
var argTypes = unapplyArgs(unapplyApp.tpe, unapplyFn, args, tree.sourcePos)

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)