Skip to content

Commit dea3d10

Browse files
authored
Avoid stacked thisCall contexts (#20488)
AddImplicitArgs can recursively add several implicit parameter lists. We need to make sure we don't perform a thisCallContext search in another thisCall context in this case. Fixes #20483 The original code would back out further and further in the context chain for every implicit parameter section on the secondary constructor. Eventually (in this case after 2 times) bad things happen.
2 parents 04ada79 + 2e4a070 commit dea3d10

File tree

4 files changed

+32
-12
lines changed

4 files changed

+32
-12
lines changed

compiler/src/dotty/tools/dotc/core/Contexts.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ object Contexts {
477477

478478
/** Is the flexible types option set? */
479479
def flexibleTypes: Boolean = base.settings.YexplicitNulls.value && !base.settings.YnoFlexibleTypes.value
480-
480+
481481
/** Is the best-effort option set? */
482482
def isBestEffort: Boolean = base.settings.YbestEffort.value
483483

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ trait Implicits:
10771077
trace(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) {
10781078
record("inferImplicit")
10791079
assert(ctx.phase.allowsImplicitSearch,
1080-
if (argument.isEmpty) i"missing implicit parameter of type $pt after typer at phase ${ctx.phase.phaseName}"
1080+
if (argument.isEmpty) i"missing implicit parameter of type $pt after typer at phase ${ctx.phase}"
10811081
else i"type error: ${argument.tpe} does not conform to $pt${err.whyNoMatchStr(argument.tpe, pt)}")
10821082

10831083
val usableForInference = pt.exists && !pt.unusableForInference

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

+17-10
Original file line numberDiff line numberDiff line change
@@ -4056,7 +4056,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
40564056

40574057
def dummyArg(tp: Type) = untpd.Ident(nme.???).withTypeUnchecked(tp)
40584058

4059-
def addImplicitArgs(using Context) = {
4059+
val origCtx = ctx
4060+
4061+
def addImplicitArgs(using Context) =
40604062
def hasDefaultParams = methPart(tree).symbol.hasDefaultParams
40614063
def implicitArgs(formals: List[Type], argIndex: Int, pt: Type): List[Tree] = formals match
40624064
case Nil => Nil
@@ -4179,15 +4181,20 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
41794181
case _ => retyped
41804182
else issueErrors(tree, args)
41814183
}
4182-
else tree match {
4183-
case tree: Block =>
4184-
readaptSimplified(tpd.Block(tree.stats, tpd.Apply(tree.expr, args)))
4185-
case tree: NamedArg =>
4186-
readaptSimplified(tpd.NamedArg(tree.name, tpd.Apply(tree.arg, args)))
4187-
case _ =>
4188-
readaptSimplified(tpd.Apply(tree, args))
4189-
}
4190-
}
4184+
else
4185+
inContext(origCtx):
4186+
// Reset context in case it was set to a supercall context before.
4187+
// otherwise the invariant for taking another this or super call context is not met.
4188+
// Test case is i20483.scala
4189+
tree match
4190+
case tree: Block =>
4191+
readaptSimplified(tpd.Block(tree.stats, tpd.Apply(tree.expr, args)))
4192+
case tree: NamedArg =>
4193+
readaptSimplified(tpd.NamedArg(tree.name, tpd.Apply(tree.arg, args)))
4194+
case _ =>
4195+
readaptSimplified(tpd.Apply(tree, args))
4196+
end addImplicitArgs
4197+
41914198
pt.revealIgnored match {
41924199
case pt: FunProto if pt.applyKind == ApplyKind.Using =>
41934200
// We can end up here if extension methods are called with explicit given arguments.

tests/pos/i20483.scala

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
class Foo
3+
(x: Option[String])
4+
(using Boolean)
5+
(using Int)
6+
(using Double):
7+
8+
def this
9+
(x: String)
10+
(using Boolean)
11+
(using Int)
12+
(using Double) =
13+
this(Some(x))

0 commit comments

Comments
 (0)