Skip to content

Commit 6bd8050

Browse files
committed
Avoid inserting multiple .apply's.
This can lead to stackoverflow, as i1639.scala shows. Fixes #1639.
1 parent 7ae3e08 commit 6bd8050

File tree

3 files changed

+35
-11
lines changed

3 files changed

+35
-11
lines changed

src/dotty/tools/dotc/typer/ReTyper.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ class ReTyper extends Typer {
7373

7474
override def index(trees: List[untpd.Tree])(implicit ctx: Context) = ctx
7575

76-
override def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree =
77-
fallBack(tree, ctx.typerState)
76+
override def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: => Tree)(implicit ctx: Context): Tree =
77+
fallBack
7878

7979
override def completeAnnotations(mdef: untpd.MemberDef, sym: Symbol)(implicit ctx: Context): Unit = ()
8080

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

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,18 +1565,34 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
15651565
* `fallBack`.
15661566
*
15671567
* 1st strategy: Try to insert `.apply` so that the result conforms to prototype `pt`.
1568+
* This strategy is not tried if the prototype represents already
1569+
* another `.apply` or `.apply()` selection.
15681570
* 2nd strategy: If tree is a select `qual.name`, try to insert an implicit conversion
15691571
* around the qualifier part `qual` so that the result conforms to the expected type
15701572
* with wildcard result type.
15711573
*/
1572-
def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree =
1573-
tryEither { implicit ctx =>
1574+
def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: => Tree)(implicit ctx: Context): Tree = {
1575+
1576+
/** Is `pt` a prototype of an `apply` selection, or a parameterless function yielding one? */
1577+
def isApplyProto(pt: Type): Boolean = pt match {
1578+
case pt: SelectionProto => pt.name == nme.apply
1579+
case pt: FunProto => pt.args.isEmpty && isApplyProto(pt.resultType)
1580+
case pt: IgnoredProto => isApplyProto(pt.ignored)
1581+
case _ => false
1582+
}
1583+
1584+
def tryApply(implicit ctx: Context) = {
15741585
val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
15751586
if (sel.tpe.isError) sel else adapt(sel, pt)
1576-
} { (failedTree, failedState) =>
1577-
tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack(failedTree, failedState))
15781587
}
15791588

1589+
def tryImplicit =
1590+
tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack)
1591+
1592+
if (isApplyProto(pt)) tryImplicit
1593+
else tryEither(tryApply(_))((_, _) => tryImplicit)
1594+
}
1595+
15801596
/** If this tree is a select node `qual.name`, try to insert an implicit conversion
15811597
* `c` around `qual` so that `c(qual).name` conforms to `pt`.
15821598
*/
@@ -1668,7 +1684,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
16681684
def hasEmptyParams(denot: SingleDenotation) = denot.info.paramTypess == ListOfNil
16691685
pt match {
16701686
case pt: FunProto =>
1671-
tryInsertApplyOrImplicit(tree, pt)((_, _) => noMatches)
1687+
tryInsertApplyOrImplicit(tree, pt)(noMatches)
16721688
case _ =>
16731689
if (altDenots exists (_.info.paramTypess == ListOfNil))
16741690
typed(untpd.Apply(untpd.TypedSplice(tree), Nil), pt)
@@ -1707,7 +1723,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
17071723
case Apply(_, _) => " more"
17081724
case _ => ""
17091725
}
1710-
(_, _) => errorTree(tree, em"$methodStr does not take$more parameters")
1726+
errorTree(tree, em"$methodStr does not take$more parameters")
17111727
}
17121728
}
17131729

@@ -1924,9 +1940,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
19241940
case pt: FunProto =>
19251941
adaptToArgs(wtp, pt)
19261942
case pt: PolyProto =>
1927-
tryInsertApplyOrImplicit(tree, pt) {
1928-
(_, _) => tree // error will be reported in typedTypeApply
1929-
}
1943+
tryInsertApplyOrImplicit(tree, pt)(tree) // error will be reported in typedTypeApply
19301944
case _ =>
19311945
if (ctx.mode is Mode.Type) adaptType(tree.tpe)
19321946
else adaptNoArgs(wtp)

tests/neg/i1639.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class Bar {
2+
implicit def f(implicit x: String): String = x
3+
4+
implicitly[String](f) // error: divergent (turn -explaintypes on to see it)
5+
}
6+
7+
class Foo(implicit val bar: String) {
8+
def this() = this("baz") // error: none of the alternatives match arguments
9+
}
10+

0 commit comments

Comments
 (0)