diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index c581dac5ec52..602c74ab699a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -27,8 +27,8 @@ object Inferencing { * but only if the overall result of `isFullyDefined` is `true`. * Variables that are successfully minimized do not count as uninstantiated. */ - def isFullyDefined(tp: Type, force: ForceDegree.Value)(using Context): Boolean = - withFreshTyperState(new IsFullyDefinedAccumulator(force).process(tp), x => x) + def isFullyDefined(tp: Type, force: ForceDegree.Value, ifProto: Boolean = false)(using Context): Boolean = + withFreshTyperState(new IsFullyDefinedAccumulator(force, ifProto = ifProto).process(tp), x => x) /** Try to fully define `tp`. Return whether constraint has changed. * Any changed constraint is kept. @@ -161,7 +161,7 @@ object Inferencing { * Instance types can be improved by replacing covariant occurrences of Nothing * with fresh type variables, if `force` allows this in its `canImprove` implementation. */ - private class IsFullyDefinedAccumulator(force: ForceDegree.Value, minimizeSelected: Boolean = false) + private class IsFullyDefinedAccumulator(force: ForceDegree.Value, minimizeSelected: Boolean = false, ifProto: Boolean = false) (using Context) extends TypeAccumulator[Boolean] { /** Replace toplevel-covariant occurrences (i.e. covariant without double flips) @@ -233,8 +233,10 @@ object Inferencing { val tpd = tp.dealias if tpd ne tp then apply(x, tpd) else tp match - case _: WildcardType | _: ProtoType => + case _: WildcardType => false + case tp: ProtoType => + ifProto && foldOver(x, tp) case tvar: TypeVar if !tvar.isInstantiated => force.appliesTo(tvar) && ctx.typerState.constraint.contains(tvar) diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 0b6688c6f5fe..d6b23e886529 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -396,7 +396,7 @@ object ProtoTypes { args: List[untpd.Tree] = this.args, resultType: Type = this.resultType, typer: Typer = this.typer, - constrainResultDeep: Boolean = this.constrainResultDeep): FunProto = + constrainResultDeep: Boolean = this.constrainResultDeep)(using Context): FunProto = if (args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 10a061ab8fc4..c1fbe84c713d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -54,6 +54,7 @@ import transform.CheckUnused.OriginalName import scala.annotation.{unchecked as _, *} import dotty.tools.dotc.util.chaining.* import dotty.tools.dotc.ast.untpd.Mod +import dotty.tools.dotc.reporting.Reporter.NoReporter object Typer { @@ -4357,6 +4358,27 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer else formals1 implicitArgs(formals2, argIndex + 1, pt) + + def doesntContainsWildcards = { + val newCtx = ctx.fresh.setNewScope.setReporter(new reporting.ThrowingReporter(NoReporter)) + val pt1 = pt.deepenProtoTrans(using newCtx) + try { + isFullyDefined(pt1, ForceDegree.none, ifProto = true) + } catch { + case _: UnhandledError => false + } + } + val pt1 = pt.deepenProtoTrans + if (pt1 `ne` pt) + && (pt1 ne sharpenedPt) + && formal.typeSymbol != defn.ClassTagClass + && !isFullyDefined(formal, ForceDegree.none) + && !formal.existsPart(ty => { + val dty = ty.dealias + (dty ne ty) && ty.isInstanceOf[TypeVar] && dty.isInstanceOf[TypeVar] + }, StopAt.Static, forceLazy = false) + && doesntContainsWildcards then + constrainResult(tree.symbol, wtp, wildApprox(pt1)) val arg = inferImplicitArg(formal, tree.span.endPos) def canProfitFromMoreConstraints = @@ -4367,7 +4389,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer arg.tpe match case failed: SearchFailureType if canProfitFromMoreConstraints => - val pt1 = pt.deepenProtoTrans if (pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, pt1) then return implicitArgs(formals, argIndex, pt1) case _ =>