Skip to content

Commit 9498dee

Browse files
committed
Use existing helper functions to deconstruct closures and function calls
1 parent a1732a7 commit 9498dee

File tree

3 files changed

+47
-21
lines changed

3 files changed

+47
-21
lines changed

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import util.HashSet
99
import typer.ConstFold
1010
import reporting.trace
1111

12+
import scala.annotation.tailrec
13+
1214
trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
1315
import TreeInfo._
1416

@@ -512,17 +514,22 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
512514
}
513515

514516
/** Decompose a call fn[targs](vargs_1)...(vargs_n)
515-
* into its constituents (where targs, vargss may be empty)
517+
* into its constituents (fn, targs, vargss).
518+
*
519+
* Note: targ and vargss may be empty
516520
*/
517-
def decomposeCall(tree: Tree): (Tree, List[Tree], List[List[Tree]]) = tree match {
518-
case Apply(fn, args) =>
519-
val (meth, targs, argss) = decomposeCall(fn)
520-
(meth, targs, argss :+ args)
521-
case TypeApply(fn, targs) =>
522-
val (meth, targss, args) = decomposeCall(fn)
523-
(meth, targs ++ targss, args)
524-
case _ =>
525-
(tree, Nil, Nil)
521+
def decomposeCall(tree: Tree): (Tree, List[Tree], List[List[Tree]]) = {
522+
@tailrec
523+
def loop(tree: Tree, targss: List[Tree], argss: List[List[Tree]]): (Tree, List[Tree], List[List[Tree]]) =
524+
tree match {
525+
case Apply(fn, args) =>
526+
loop(fn, targss, args :: argss)
527+
case TypeApply(fn, targs) =>
528+
loop(fn, targs ::: targss, argss)
529+
case _ =>
530+
(tree, targss, argss)
531+
}
532+
loop(tree, Nil, Nil)
526533
}
527534

528535
/** An extractor for closures, either contained in a block or standalone.

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -707,14 +707,14 @@ trait Implicits { self: Typer =>
707707
}
708708
def resolveTypes(targs: List[Tree])(implicit ctx: Context) =
709709
targs.map(a => fullyDefinedType(a.tpe, "type argument", a.pos))
710-
val args = alt.tree match {
711-
case TypeApply(_, targs) =>
712-
resolveTypes(targs)(ctx.fresh.setTyperState(alt.tstate))
713-
case Block(List(DefDef(_, _, _, _, Apply(TypeApply(_, targs), _))), _) =>
714-
resolveTypes(targs.asInstanceOf[List[Tree]])(ctx.fresh.setTyperState(alt.tstate))
715-
case _ =>
716-
Nil
717-
}
710+
711+
// We can extract type arguments from an eta-expanded function:
712+
// @implicitAmbiguous("msg A=${A}")
713+
// implicit def f[A](x: Int): String = ...
714+
// implicitly[Int => String] // found: x => f[Any](x)
715+
val call = closureBody(alt.tree) // the tree itself if not a closure
716+
val (_, targs, _) = decomposeCall(call)
717+
val args = resolveTypes(targs)(ctx.fresh.setTyperState(alt.tstate))
718718
err.userDefinedErrorString(raw, params, args)
719719
}
720720

compiler/test/dotty/tools/dotc/reporting/UserDefinedErrorMessages.scala

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ class UserDefinedErrorMessages extends ErrorMessagesTest {
2222
|
2323
| implicitly[Int =!= Int]
2424
|}
25-
2625
""".stripMargin
2726
}.expect { (itcx, messages) =>
2827
import diagnostic.NoExplanation
@@ -48,7 +47,6 @@ class UserDefinedErrorMessages extends ErrorMessagesTest {
4847
|
4948
| implicitly[Int =!= Int]
5049
|}
51-
5250
""".stripMargin
5351
}.expect { (itcx, messages) =>
5452
import diagnostic.NoExplanation
@@ -75,7 +73,6 @@ class UserDefinedErrorMessages extends ErrorMessagesTest {
7573
|
7674
| implicitly[Int =!= Int]
7775
|}
78-
7976
""".stripMargin
8077
}.expect { (itcx, messages) =>
8178
import diagnostic.NoExplanation
@@ -98,7 +95,29 @@ class UserDefinedErrorMessages extends ErrorMessagesTest {
9895
| implicitly[Int => String]
9996
| }
10097
|}
98+
""".stripMargin
99+
}.expect { (itcx, messages) =>
100+
import diagnostic.NoExplanation
101+
implicit val ctx: Context = itcx
102+
103+
assertMessageCount(1, messages)
104+
val (m: NoExplanation) :: Nil = messages
101105

106+
assertEquals(m.msg, "msg A=Any")
107+
}
108+
109+
@Test def userDefinedImplicitAmbiguous5 =
110+
checkMessagesAfter("frontend") {
111+
"""
112+
|class C {
113+
| @annotation.implicitAmbiguous("msg A=${A}")
114+
| implicit def f[A](implicit x: String): Int = 1
115+
| implicit def g: Int = 2
116+
| def test: Unit = {
117+
| implicit val s: String = "Hello"
118+
| implicitly[Int]
119+
| }
120+
|}
102121
""".stripMargin
103122
}.expect { (itcx, messages) =>
104123
import diagnostic.NoExplanation

0 commit comments

Comments
 (0)