Skip to content

Commit

Permalink
Avoid stacked thisCall contexts (#20488)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
odersky authored Jun 10, 2024
2 parents 04ada79 + 2e4a070 commit dea3d10
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 12 deletions.
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ object Contexts {

/** Is the flexible types option set? */
def flexibleTypes: Boolean = base.settings.YexplicitNulls.value && !base.settings.YnoFlexibleTypes.value

/** Is the best-effort option set? */
def isBestEffort: Boolean = base.settings.YbestEffort.value

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ trait Implicits:
trace(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) {
record("inferImplicit")
assert(ctx.phase.allowsImplicitSearch,
if (argument.isEmpty) i"missing implicit parameter of type $pt after typer at phase ${ctx.phase.phaseName}"
if (argument.isEmpty) i"missing implicit parameter of type $pt after typer at phase ${ctx.phase}"
else i"type error: ${argument.tpe} does not conform to $pt${err.whyNoMatchStr(argument.tpe, pt)}")

val usableForInference = pt.exists && !pt.unusableForInference
Expand Down
27 changes: 17 additions & 10 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4056,7 +4056,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer

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

def addImplicitArgs(using Context) = {
val origCtx = ctx

def addImplicitArgs(using Context) =
def hasDefaultParams = methPart(tree).symbol.hasDefaultParams
def implicitArgs(formals: List[Type], argIndex: Int, pt: Type): List[Tree] = formals match
case Nil => Nil
Expand Down Expand Up @@ -4179,15 +4181,20 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
case _ => retyped
else issueErrors(tree, args)
}
else tree match {
case tree: Block =>
readaptSimplified(tpd.Block(tree.stats, tpd.Apply(tree.expr, args)))
case tree: NamedArg =>
readaptSimplified(tpd.NamedArg(tree.name, tpd.Apply(tree.arg, args)))
case _ =>
readaptSimplified(tpd.Apply(tree, args))
}
}
else
inContext(origCtx):
// Reset context in case it was set to a supercall context before.
// otherwise the invariant for taking another this or super call context is not met.
// Test case is i20483.scala
tree match
case tree: Block =>
readaptSimplified(tpd.Block(tree.stats, tpd.Apply(tree.expr, args)))
case tree: NamedArg =>
readaptSimplified(tpd.NamedArg(tree.name, tpd.Apply(tree.arg, args)))
case _ =>
readaptSimplified(tpd.Apply(tree, args))
end addImplicitArgs

pt.revealIgnored match {
case pt: FunProto if pt.applyKind == ApplyKind.Using =>
// We can end up here if extension methods are called with explicit given arguments.
Expand Down
13 changes: 13 additions & 0 deletions tests/pos/i20483.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

class Foo
(x: Option[String])
(using Boolean)
(using Int)
(using Double):

def this
(x: String)
(using Boolean)
(using Int)
(using Double) =
this(Some(x))

0 comments on commit dea3d10

Please sign in to comment.