diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 6b7b840e7606..29d85b9029e8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4250,13 +4250,49 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer else formals1 implicitArgs(formals2, argIndex + 1, pt) + // try to constrain type before implicit search. See #18763 + def tryConstrainType(pt1: Type): Boolean = { + // subst dummyArg into FunProto so that we don't have to search for nested implicit + val tm = new TypeMap: + def apply(t: Type): Type = t match + case fp@FunProto(args, resType) => + fp.derivedFunProto( + args.map(arg => + if (arg.isInstanceOf[untpd.TypedSplice]) arg + else dummyArg(arg.typeOpt).withSpan(arg.span) + ), + mapOver(resType) + ) + case _ => + mapOver(t) + val ownedVars = ctx.typerState.ownedVars + def qualifying = (ownedVars -- locked).toList + val resultAlreadyConstrained = pt1.isInstanceOf[MethodOrPoly] + if !formal.isGround + && (formal.simplified `ne` formal) + && (pt1 `ne` pt) + && (pt1 ne sharpenedPt) + && (ownedVars ne locked) + && !ownedVars.isEmpty + && qualifying.nonEmpty + && !resultAlreadyConstrained then + val approxRes = wildApprox(pt1.resultType) + val stripedApproxRes = tm(approxRes) + if !stripedApproxRes.containsWildcardTypes then + if ctx.typerState.isCommittable then + return NoViewsAllowed.constrainResult(tree.symbol, wtp.resultType, stripedApproxRes) + else return constrainResult(tree.symbol, wtp.resultType, stripedApproxRes) + false + } + + val pt1 = pt.deepenProtoTrans + val isConstrained = tryConstrainType(pt1) val arg = inferImplicitArg(formal, tree.span.endPos) arg.tpe match case failed: AmbiguousImplicits => - val pt1 = pt.deepenProtoTrans - if (pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, pt1) - then implicitArgs(formals, argIndex, pt1) - else arg :: implicitArgs(formals1, argIndex + 1, pt1) + if !isConstrained && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, pt1) + then implicitArgs(formals, argIndex, pt) + else arg :: implicitArgs(formals1, argIndex + 1, pt) case failed: SearchFailureType => lazy val defaultArg = findDefaultArgument(argIndex) .showing(i"default argument: for $formal, $tree, $argIndex = $result", typr)