Skip to content

Commit d8f5c6c

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

File tree

3 files changed

+35
-11
lines changed

3 files changed

+35
-11
lines changed

compiler/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

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

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,18 +1585,34 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
15851585
* `fallBack`.
15861586
*
15871587
* 1st strategy: Try to insert `.apply` so that the result conforms to prototype `pt`.
1588+
* This strategy is not tried if the prototype represents already
1589+
* another `.apply` or `.apply()` selection.
15881590
* 2nd strategy: If tree is a select `qual.name`, try to insert an implicit conversion
15891591
* around the qualifier part `qual` so that the result conforms to the expected type
15901592
* with wildcard result type.
15911593
*/
1592-
def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree =
1593-
tryEither { implicit ctx =>
1594+
def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: => Tree)(implicit ctx: Context): Tree = {
1595+
1596+
/** Is `pt` a prototype of an `apply` selection, or a parameterless function yielding one? */
1597+
def isApplyProto(pt: Type): Boolean = pt match {
1598+
case pt: SelectionProto => pt.name == nme.apply
1599+
case pt: FunProto => pt.args.isEmpty && isApplyProto(pt.resultType)
1600+
case pt: IgnoredProto => isApplyProto(pt.ignored)
1601+
case _ => false
1602+
}
1603+
1604+
def tryApply(implicit ctx: Context) = {
15941605
val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
15951606
if (sel.tpe.isError) sel else adapt(sel, pt)
1596-
} { (failedTree, failedState) =>
1597-
tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack(failedTree, failedState))
15981607
}
15991608

1609+
def tryImplicit =
1610+
tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack)
1611+
1612+
if (isApplyProto(pt)) tryImplicit
1613+
else tryEither(tryApply(_))((_, _) => tryImplicit)
1614+
}
1615+
16001616
/** If this tree is a select node `qual.name`, try to insert an implicit conversion
16011617
* `c` around `qual` so that `c(qual).name` conforms to `pt`.
16021618
*/
@@ -1688,7 +1704,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
16881704
def hasEmptyParams(denot: SingleDenotation) = denot.info.paramTypess == ListOfNil
16891705
pt match {
16901706
case pt: FunProto =>
1691-
tryInsertApplyOrImplicit(tree, pt)((_, _) => noMatches)
1707+
tryInsertApplyOrImplicit(tree, pt)(noMatches)
16921708
case _ =>
16931709
if (altDenots exists (_.info.paramTypess == ListOfNil))
16941710
typed(untpd.Apply(untpd.TypedSplice(tree), Nil), pt)
@@ -1727,7 +1743,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
17271743
case Apply(_, _) => " more"
17281744
case _ => ""
17291745
}
1730-
(_, _) => errorTree(tree, em"$methodStr does not take$more parameters")
1746+
errorTree(tree, em"$methodStr does not take$more parameters")
17311747
}
17321748
}
17331749

@@ -1946,9 +1962,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
19461962
case pt: FunProto =>
19471963
adaptToArgs(wtp, pt)
19481964
case pt: PolyProto =>
1949-
tryInsertApplyOrImplicit(tree, pt) {
1950-
(_, _) => tree // error will be reported in typedTypeApply
1951-
}
1965+
tryInsertApplyOrImplicit(tree, pt)(tree) // error will be reported in typedTypeApply
19521966
case _ =>
19531967
if (ctx.mode is Mode.Type) adaptType(tree.tpe)
19541968
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)