Skip to content

Backport "Use more context for implicit search only if no default argument" to 3.7.3 #23713

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: release-3.7.3_backport-23702
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4362,11 +4362,17 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer

val arg = inferImplicitArg(formal, tree.span.endPos)

lazy val defaultArg = findDefaultArgument(argIndex)
.showing(i"default argument: for $formal, $tree, $argIndex = $result", typr)
def argHasDefault = hasDefaultParams && !defaultArg.isEmpty

def canProfitFromMoreConstraints =
arg.tpe.isInstanceOf[AmbiguousImplicits]
// ambiguity could be decided by more constraints
|| !isFullyDefined(formal, ForceDegree.none)
// more context might constrain type variables which could make implicit scope larger
// Ambiguity could be decided by more constraints
|| !isFullyDefined(formal, ForceDegree.none) && !argHasDefault
// More context might constrain type variables which could make implicit scope larger.
// But in this case we should search with additional arguments typed only if there
// is no default argument.

arg.tpe match
case failed: SearchFailureType if canProfitFromMoreConstraints =>
Expand All @@ -4379,15 +4385,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
case failed: AmbiguousImplicits =>
arg :: implicitArgs(formals1, argIndex + 1, pt)
case failed: SearchFailureType =>
lazy val defaultArg = findDefaultArgument(argIndex)
.showing(i"default argument: for $formal, $tree, $argIndex = $result", typr)
if !hasDefaultParams || defaultArg.isEmpty then
// no need to search further, the adapt fails in any case
// the reason why we continue inferring arguments in case of an AmbiguousImplicits
// is that we need to know whether there are further errors.
// If there are none, we have to propagate the ambiguity to the caller.
arg :: formals1.map(dummyArg)
else
if argHasDefault then
// This is tricky. On the one hand, we need the defaultArg to
// correctly type subsequent formal parameters in the same using
// clause in case there are parameter dependencies. On the other hand,
Expand All @@ -4398,6 +4396,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
// `if propFail.exists` where we re-type the whole using clause with named
// arguments for all implicits that were found.
arg :: inferArgsAfter(defaultArg)
else
// no need to search further, the adapt fails in any case
// the reason why we continue inferring arguments in case of an AmbiguousImplicits
// is that we need to know whether there are further errors.
// If there are none, we have to propagate the ambiguity to the caller.
arg :: formals1.map(dummyArg)
case _ =>
arg :: inferArgsAfter(arg)
end implicitArgs
Expand Down