From c1f2338efd05578a77c25080d658fa55825ce7dd Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 20 Apr 2025 16:46:00 +0300 Subject: [PATCH 01/14] Run type inference before implicit search --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 6b7b840e7606..902ce082eb00 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4250,13 +4250,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer else formals1 implicitArgs(formals2, argIndex + 1, pt) + val pt1 = pt.deepenProtoTrans + if ((pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, pt1)) { + return implicitArgs(formals, argIndex, 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) + arg :: implicitArgs(formals1, argIndex + 1, pt1) case failed: SearchFailureType => lazy val defaultArg = findDefaultArgument(argIndex) .showing(i"default argument: for $formal, $tree, $argIndex = $result", typr) From ad5ab27e7b67068ace583292b929bdfff356f780 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 21 Apr 2025 00:05:53 +0300 Subject: [PATCH 02/14] new typer state when infer types before search implicit --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 902ce082eb00..451dd5923a69 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4250,11 +4250,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer else formals1 implicitArgs(formals2, argIndex + 1, pt) - val pt1 = pt.deepenProtoTrans - if ((pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, pt1)) { - return implicitArgs(formals, argIndex, pt1) + val newctx = ctx.fresh.setNewTyperState() + val pt1 = pt.deepenProtoTrans(using newctx) + val arg = if ((pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, pt1)(using newctx)) { + inferImplicitArg(formal, tree.span.endPos)(using newctx) + } else { + inferImplicitArg(formal, tree.span.endPos) } - val arg = inferImplicitArg(formal, tree.span.endPos) arg.tpe match case failed: AmbiguousImplicits => arg :: implicitArgs(formals1, argIndex + 1, pt1) From 9be384bd8232bd00069f89bfa69c90a89aabea9f Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 22 Apr 2025 23:32:25 +0300 Subject: [PATCH 03/14] not infer if type not simplified before implicit search --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 451dd5923a69..109089109b24 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4250,10 +4250,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer else formals1 implicitArgs(formals2, argIndex + 1, pt) - val newctx = ctx.fresh.setNewTyperState() + val newctx = ctx.fresh.setExploreTyperState() val pt1 = pt.deepenProtoTrans(using newctx) - val arg = if ((pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, pt1)(using newctx)) { - inferImplicitArg(formal, tree.span.endPos)(using newctx) + val arg = if ((formal.simplified `ne` formal) && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, pt1)(using newctx)) { + inferImplicitArg(formal.simplified(using newctx), tree.span.endPos) } else { inferImplicitArg(formal, tree.span.endPos) } From 4fe718b23c711c57700b80c9b498c9821291c6b3 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 24 Apr 2025 22:47:37 +0300 Subject: [PATCH 04/14] return constrainResult after AmbiguousImplicits --- .../src/dotty/tools/dotc/typer/Typer.scala | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 109089109b24..eca9ceb597a0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4250,16 +4250,25 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer else formals1 implicitArgs(formals2, argIndex + 1, pt) - val newctx = ctx.fresh.setExploreTyperState() - val pt1 = pt.deepenProtoTrans(using newctx) - val arg = if ((formal.simplified `ne` formal) && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, pt1)(using newctx)) { - inferImplicitArg(formal.simplified(using newctx), tree.span.endPos) - } else { - inferImplicitArg(formal, tree.span.endPos) + val ownedVars = ctx.typerState.ownedVars + val pt1 = pt.deepenProtoTrans + if ((formal.simplified `ne` formal) && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && (ownedVars ne locked) && !ownedVars.isEmpty) { + val qualifying = (ownedVars -- locked).toList + if (qualifying.nonEmpty) { + val resultAlreadyConstrained = pt1.isInstanceOf[MethodOrPoly] + if (!resultAlreadyConstrained) { + if ctx.typerState.isCommittable then + NoViewsAllowed.constrainResult(tree.symbol, wtp, pt1) + else constrainResult(tree.symbol, wtp, pt1) + } + } } + val arg = inferImplicitArg(formal, tree.span.endPos) arg.tpe match case failed: AmbiguousImplicits => - arg :: implicitArgs(formals1, argIndex + 1, pt1) + if (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) From 9f3c727fbd2c3b614939d586d4ee91e0a3920753 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 26 Apr 2025 00:03:17 +0300 Subject: [PATCH 05/14] run constrainResult before implicit search when search type not ground --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index eca9ceb597a0..d95f57f3965e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4252,7 +4252,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val ownedVars = ctx.typerState.ownedVars val pt1 = pt.deepenProtoTrans - if ((formal.simplified `ne` formal) && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && (ownedVars ne locked) && !ownedVars.isEmpty) { + if ((!formal.isGround) && (formal.simplified `ne` formal) && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && (ownedVars ne locked) && !ownedVars.isEmpty) { val qualifying = (ownedVars -- locked).toList if (qualifying.nonEmpty) { val resultAlreadyConstrained = pt1.isInstanceOf[MethodOrPoly] From 5ec51bcaebe044b6b4e2b4e985b3b2d7d098a2c5 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 27 Apr 2025 17:02:35 +0300 Subject: [PATCH 06/14] Approximate result type before constrain --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index d95f57f3965e..f11341b303d0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4255,11 +4255,18 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer if ((!formal.isGround) && (formal.simplified `ne` formal) && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && (ownedVars ne locked) && !ownedVars.isEmpty) { val qualifying = (ownedVars -- locked).toList if (qualifying.nonEmpty) { + val approxRes = wildApprox(pt1.resultType) + val tm = new TypeMap: + def apply(t: Type) = t match + case fp@FunProto(args, resType) => + fp.derivedFunProto(args.map(a => dummyArg(a.typeOpt).withSpan(a.span)), mapOver(resType)) + case _ => + mapOver(t) val resultAlreadyConstrained = pt1.isInstanceOf[MethodOrPoly] if (!resultAlreadyConstrained) { if ctx.typerState.isCommittable then - NoViewsAllowed.constrainResult(tree.symbol, wtp, pt1) - else constrainResult(tree.symbol, wtp, pt1) + NoViewsAllowed.constrainResult(tree.symbol, wtp.resultType, tm(approxRes)) + else constrainResult(tree.symbol, wtp.resultType, tm(approxRes)) } } } From 116fdfcca2e229b17cee8c918e5ec28d43ae4a66 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 27 Apr 2025 22:51:19 +0300 Subject: [PATCH 07/14] not subst dummyArg if tree is TypedSlice --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f11341b303d0..616f06e594fc 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4259,7 +4259,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val tm = new TypeMap: def apply(t: Type) = t match case fp@FunProto(args, resType) => - fp.derivedFunProto(args.map(a => dummyArg(a.typeOpt).withSpan(a.span)), mapOver(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 resultAlreadyConstrained = pt1.isInstanceOf[MethodOrPoly] From 1a8afbcaf20d0528ffc39da348ce971779d17591 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 28 Apr 2025 21:00:54 +0300 Subject: [PATCH 08/14] not constrainResult if type contains Wildcard Types --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 616f06e594fc..323f3e6070c8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4268,11 +4268,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer ) case _ => mapOver(t) + val stripedApproxRes = tm(approxRes) val resultAlreadyConstrained = pt1.isInstanceOf[MethodOrPoly] - if (!resultAlreadyConstrained) { + if (!resultAlreadyConstrained && !stripedApproxRes.containsWildcardTypes) { if ctx.typerState.isCommittable then - NoViewsAllowed.constrainResult(tree.symbol, wtp.resultType, tm(approxRes)) - else constrainResult(tree.symbol, wtp.resultType, tm(approxRes)) + NoViewsAllowed.constrainResult(tree.symbol, wtp.resultType, stripedApproxRes) + else constrainResult(tree.symbol, wtp.resultType, stripedApproxRes) } } } From 77a83c6b5f2df7767c1b9a3a004140a4c3897090 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 29 Apr 2025 12:07:35 +0300 Subject: [PATCH 09/14] move constrain to function --- .../src/dotty/tools/dotc/typer/Typer.scala | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 323f3e6070c8..a82069c4bf8a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4250,18 +4250,17 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer else formals1 implicitArgs(formals2, argIndex + 1, pt) - val ownedVars = ctx.typerState.ownedVars - val pt1 = pt.deepenProtoTrans - if ((!formal.isGround) && (formal.simplified `ne` formal) && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && (ownedVars ne locked) && !ownedVars.isEmpty) { + def tryConstrainType(pt1: Type): Boolean = { + val ownedVars = ctx.typerState.ownedVars val qualifying = (ownedVars -- locked).toList - if (qualifying.nonEmpty) { + if ((pt1 `ne` pt) && (pt1 ne sharpenedPt) && (ownedVars ne locked) && !ownedVars.isEmpty && qualifying.nonEmpty) { val approxRes = wildApprox(pt1.resultType) val tm = new TypeMap: def apply(t: Type) = t match case fp@FunProto(args, resType) => fp.derivedFunProto( args.map(arg => - if(arg.isInstanceOf[untpd.TypedSplice]) arg + if (arg.isInstanceOf[untpd.TypedSplice]) arg else dummyArg(arg.typeOpt).withSpan(arg.span) ), mapOver(resType) @@ -4269,14 +4268,20 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer case _ => mapOver(t) val stripedApproxRes = tm(approxRes) - val resultAlreadyConstrained = pt1.isInstanceOf[MethodOrPoly] - if (!resultAlreadyConstrained && !stripedApproxRes.containsWildcardTypes) { + if (!stripedApproxRes.containsWildcardTypes) { if ctx.typerState.isCommittable then NoViewsAllowed.constrainResult(tree.symbol, wtp.resultType, stripedApproxRes) else constrainResult(tree.symbol, wtp.resultType, stripedApproxRes) + } else { + false } + } else { + false } } + + val pt1 = pt.deepenProtoTrans + tryConstrainType(pt1) val arg = inferImplicitArg(formal, tree.span.endPos) arg.tpe match case failed: AmbiguousImplicits => From 58993a0a48541f3c98643a61b13c32a2449157d3 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 29 Apr 2025 12:41:36 +0300 Subject: [PATCH 10/14] return isGround check --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index a82069c4bf8a..0cca340fd051 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4253,7 +4253,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer def tryConstrainType(pt1: Type): Boolean = { val ownedVars = ctx.typerState.ownedVars val qualifying = (ownedVars -- locked).toList - if ((pt1 `ne` pt) && (pt1 ne sharpenedPt) && (ownedVars ne locked) && !ownedVars.isEmpty && qualifying.nonEmpty) { + if (!formal.isGround && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && (ownedVars ne locked) && !ownedVars.isEmpty && qualifying.nonEmpty) { val approxRes = wildApprox(pt1.resultType) val tm = new TypeMap: def apply(t: Type) = t match From 76d891398131c559b6aa0c6975d4169e1130392a Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 29 Apr 2025 14:52:31 +0300 Subject: [PATCH 11/14] return resultAlreadyConstrained check --- .../src/dotty/tools/dotc/typer/Typer.scala | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 0cca340fd051..5a27e0841100 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4250,34 +4250,38 @@ 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 - val qualifying = (ownedVars -- locked).toList - if (!formal.isGround && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && (ownedVars ne locked) && !ownedVars.isEmpty && qualifying.nonEmpty) { + def qualifying = (ownedVars -- locked).toList + val resultAlreadyConstrained = pt1.isInstanceOf[MethodOrPoly] + if !formal.isGround + && (pt1 `ne` pt) + && (pt1 ne sharpenedPt) + && (ownedVars ne locked) + && !ownedVars.isEmpty + && qualifying.nonEmpty + && !resultAlreadyConstrained then val approxRes = wildApprox(pt1.resultType) - val tm = new TypeMap: - def apply(t: 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 stripedApproxRes = tm(approxRes) - if (!stripedApproxRes.containsWildcardTypes) { + if !stripedApproxRes.containsWildcardTypes then if ctx.typerState.isCommittable then - NoViewsAllowed.constrainResult(tree.symbol, wtp.resultType, stripedApproxRes) - else constrainResult(tree.symbol, wtp.resultType, stripedApproxRes) - } else { - false - } - } else { - false - } + return NoViewsAllowed.constrainResult(tree.symbol, wtp.resultType, stripedApproxRes) + else return constrainResult(tree.symbol, wtp.resultType, stripedApproxRes) + false } val pt1 = pt.deepenProtoTrans From d03d8bd507b524f7797af52a3f0b164df64e5efd Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 29 Apr 2025 16:35:05 +0300 Subject: [PATCH 12/14] return simplified check --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 5a27e0841100..e12ea41658f9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4269,6 +4269,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer 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) From 23cc07faad9334214ceaf01bab33b05d6be7a158 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 29 Apr 2025 16:42:19 +0300 Subject: [PATCH 13/14] fix --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index e12ea41658f9..8c16b63de9fd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4269,7 +4269,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer def qualifying = (ownedVars -- locked).toList val resultAlreadyConstrained = pt1.isInstanceOf[MethodOrPoly] if !formal.isGround - && formal.simplified `ne` formal + && (formal.simplified `ne` formal) && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && (ownedVars ne locked) From b91ad9b9238148f35da2b678a504fb26afeb0fad Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 29 Apr 2025 18:57:57 +0300 Subject: [PATCH 14/14] no need in constrain type, if it already constrained --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 8c16b63de9fd..29d85b9029e8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4286,11 +4286,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer } val pt1 = pt.deepenProtoTrans - tryConstrainType(pt1) + val isConstrained = tryConstrainType(pt1) val arg = inferImplicitArg(formal, tree.span.endPos) arg.tpe match case failed: AmbiguousImplicits => - if (pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, 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 =>