Skip to content

Commit 7c8dee5

Browse files
authored
Merge pull request #5601 from milessabin/topic/t5427
Propagate dependencies through implicit parameters
2 parents 2b95357 + ccba10c commit 7c8dee5

File tree

3 files changed

+82
-3
lines changed

3 files changed

+82
-3
lines changed

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,7 +2348,7 @@ class Typer extends Namer
23482348
def dummyArg(tp: Type) = untpd.Ident(nme.???).withTypeUnchecked(tp)
23492349

23502350
def addImplicitArgs(implicit ctx: Context) = {
2351-
def implicitArgs(formals: List[Type]): List[Tree] = formals match {
2351+
def implicitArgs(formals: List[Type], argIndex: Int): List[Tree] = formals match {
23522352
case Nil => Nil
23532353
case formal :: formals1 =>
23542354
val arg = inferImplicitArg(formal, tree.pos.endPos)
@@ -2361,10 +2361,17 @@ class Typer extends Namer
23612361
// If there are none, we have to propagate the ambiguity to the caller.
23622362
arg :: formals1.map(dummyArg)
23632363
case _ =>
2364-
arg :: implicitArgs(formals1)
2364+
// If the implicit parameter list is dependent we must propagate inferred
2365+
// types through the remainder of the parameter list similarly to how it's
2366+
// done for non-implicit parameter lists in Applications#matchArgs#addTyped.
2367+
val formals2 =
2368+
if (wtp.isParamDependent && arg.tpe.exists)
2369+
formals1.mapconserve(f1 => safeSubstParam(f1, wtp.paramRefs(argIndex), arg.tpe))
2370+
else formals1
2371+
arg :: implicitArgs(formals2, argIndex + 1)
23652372
}
23662373
}
2367-
val args = implicitArgs(wtp.paramInfos)
2374+
val args = implicitArgs(wtp.paramInfos, 0)
23682375

23692376
def propagatedFailure(args: List[Tree]): Type = args match {
23702377
case arg :: args1 =>

tests/neg/i5427.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
trait Foo[In] { type Out }
2+
3+
object Test {
4+
def fooInt: Foo[Int] { type Out = String } = ???
5+
implicit def str: String = ???
6+
7+
def test1[A](f1: Foo[A])(implicit f2: f1.Out) = ???
8+
def test2[A](implicit f1: Foo[A], f2: f1.Out) = ???
9+
10+
test1(fooInt) // OK
11+
test2 // error
12+
}
13+
14+
object Test2 {
15+
implicit def fooInt: Foo[Int] { type Out = String } = ???
16+
implicit def fooString: Foo[String] { type Out = Boolean } = ???
17+
implicit def fooBoolean: Foo[Boolean] { type Out = Double } = ???
18+
19+
def test3[A](f1: Foo[A], f2: Foo[f1.Out])(implicit f3: Foo[f2.Out]): f3.Out = ???
20+
def test4[A](implicit f1: Foo[A], f2: Foo[f1.Out], f3: Foo[f2.Out]): f3.Out = ???
21+
22+
val t3 = test3(fooInt, fooString)
23+
t3: Double
24+
val t4 = test4 // error
25+
t4: Double
26+
}

tests/pos/i5427.scala

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
trait Foo[In] { type Out }
2+
3+
object Test {
4+
implicit def fooInt: Foo[Int] { type Out = String } = ???
5+
implicit def str: String = ???
6+
7+
def test1[A](f1: Foo[A])(implicit f2: f1.Out) = ???
8+
def test2[A](implicit f1: Foo[A], f2: f1.Out) = ???
9+
10+
test1(fooInt) // OK
11+
test2 // OK
12+
}
13+
14+
object Test2 {
15+
implicit def fooInt: Foo[Int] { type Out = String } = ???
16+
implicit def fooString: Foo[String] { type Out = Boolean } = ???
17+
implicit def fooBoolean: Foo[Boolean] { type Out = Double } = ???
18+
19+
def test3[A](f1: Foo[A], f2: Foo[f1.Out])(implicit f3: Foo[f2.Out]): f3.Out = ???
20+
def test4[A](implicit f1: Foo[A], f2: Foo[f1.Out], f3: Foo[f2.Out]): f3.Out = ???
21+
22+
val t3 = test3(fooInt, fooString)
23+
t3: Double
24+
val t4 = test4[Int]
25+
t4: Double
26+
}
27+
28+
object Test3 {
29+
def fooInt: Foo[Int] { type Out = String } = ???
30+
implicit def str: String = ???
31+
32+
def test5[A](implicit f1: Foo[A] = fooInt, f2: f1.Out) = f2
33+
34+
val t5 = test5
35+
t5: String
36+
}
37+
38+
object Test4 {
39+
implicit def fooInt: Foo[Int] { type Out = String } = ???
40+
def str: String = ???
41+
42+
def test6[A](implicit f1: Foo[A], f2: f1.Out = str) = f2
43+
44+
val t6 = test6
45+
t6: String
46+
}

0 commit comments

Comments
 (0)