Skip to content

Commit

Permalink
Avoid stacked thisCall contexts
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 scala#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 3 times) bad things happen.
  • Loading branch information
odersky authored and WojciechMazur committed Jun 19, 2024
1 parent edbb7c4 commit 00ef3f3
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 @@ -1067,7 +1067,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 @@ -4058,7 +4058,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 @@ -4181,15 +4183,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 00ef3f3

Please sign in to comment.