From c1f2338efd05578a77c25080d658fa55825ce7dd Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 20 Apr 2025 16:46:00 +0300 Subject: [PATCH 01/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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 => From 480cb8d944f7901bd674935071b0b5f810091c5b Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 25 May 2025 00:44:36 +0300 Subject: [PATCH 15/27] subtype check instead constrainResult --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 29d85b9029e8..36ab922eea25 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4265,32 +4265,25 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer ) 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) + return wtp.resultType <:< stripedApproxRes false } val pt1 = pt.deepenProtoTrans - val isConstrained = tryConstrainType(pt1) + tryConstrainType(pt1) val arg = inferImplicitArg(formal, tree.span.endPos) arg.tpe match case failed: AmbiguousImplicits => - if !isConstrained && (pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, 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 => From 24b2dc76d62c45611d0bd2c95500d940570608d2 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 25 May 2025 14:03:27 +0300 Subject: [PATCH 16/27] remove resultAlreadyConstrained check --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 36ab922eea25..ebf650648bdf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4265,12 +4265,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer ) case _ => mapOver(t) - val resultAlreadyConstrained = pt1.isInstanceOf[MethodOrPoly] if !formal.isGround && (formal.simplified `ne` formal) && (pt1 `ne` pt) - && (pt1 ne sharpenedPt) - && !resultAlreadyConstrained then + && (pt1 ne sharpenedPt) then val approxRes = wildApprox(pt1.resultType) val stripedApproxRes = tm(approxRes) if !stripedApproxRes.containsWildcardTypes then From d94a22f7eee964705d9822309861e5f5c7fc6d14 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 19 Jul 2025 15:03:30 +0300 Subject: [PATCH 17/27] change isGround --- .../src/dotty/tools/dotc/core/Types.scala | 6 +++- .../src/dotty/tools/dotc/typer/Typer.scala | 29 ++----------------- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8cbf309206bb..f448b2fdb68f 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -6967,11 +6967,15 @@ object Types extends TypeUtils { end NamedPartsAccumulator class isGroundAccumulator(using Context) extends TypeAccumulator[Boolean] { + var tparams = util.HashSet[TypeLambda](initialCapacity = 8) def apply(x: Boolean, tp: Type): Boolean = x && { tp match { - case _: TypeParamRef => false + case tp: TypeParamRef => tparams.contains(tp.binder) case tp: TypeVar => apply(x, tp.underlying) case tp: AppliedType => tp.isGround(this) + case tp: HKTypeLambda => + tparams.add(tp) + apply(x, tp.resType) case _ => foldOver(x, tp) } } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index b70c8bb61485..9ea7d1713d12 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4357,34 +4357,9 @@ 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) - if !formal.isGround - && (formal.simplified `ne` formal) - && (pt1 `ne` pt) - && (pt1 ne sharpenedPt) then - val approxRes = wildApprox(pt1.resultType) - val stripedApproxRes = tm(approxRes) - if !stripedApproxRes.containsWildcardTypes then - return wtp.resultType <:< stripedApproxRes - false - } - val pt1 = pt.deepenProtoTrans - tryConstrainType(pt1) + if (pt1 `ne` pt) && (pt1 ne sharpenedPt) && pt1.isGround then + constrainResult(tree.symbol, wtp, pt1) val arg = inferImplicitArg(formal, tree.span.endPos) def canProfitFromMoreConstraints = From e8c4c106c47dd284471f9c2a14b6cb36c5645c2e Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 19 Jul 2025 23:51:40 +0300 Subject: [PATCH 18/27] use wildApprox instead isGround --- compiler/src/dotty/tools/dotc/core/Types.scala | 6 +----- compiler/src/dotty/tools/dotc/typer/Typer.scala | 7 ++++++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index f448b2fdb68f..8cbf309206bb 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -6967,15 +6967,11 @@ object Types extends TypeUtils { end NamedPartsAccumulator class isGroundAccumulator(using Context) extends TypeAccumulator[Boolean] { - var tparams = util.HashSet[TypeLambda](initialCapacity = 8) def apply(x: Boolean, tp: Type): Boolean = x && { tp match { - case tp: TypeParamRef => tparams.contains(tp.binder) + case _: TypeParamRef => false case tp: TypeVar => apply(x, tp.underlying) case tp: AppliedType => tp.isGround(this) - case tp: HKTypeLambda => - tparams.add(tp) - apply(x, tp.resType) case _ => foldOver(x, tp) } } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 9ea7d1713d12..f73de39efee4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4358,7 +4358,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer implicitArgs(formals2, argIndex + 1, pt) val pt1 = pt.deepenProtoTrans - if (pt1 `ne` pt) && (pt1 ne sharpenedPt) && pt1.isGround then + val approxPt = withMode(Mode.TypevarsMissContext): + wildApprox(pt1) + if (pt1 `ne` pt) + && (pt1 ne sharpenedPt) + && (AvoidWildcardsMap()(approxPt) `eq` approxPt) + && !isFullyDefined(formal, ForceDegree.none) then constrainResult(tree.symbol, wtp, pt1) val arg = inferImplicitArg(formal, tree.span.endPos) From e5b2e7646235a402b972de4d31c8dea0412fb005 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 20 Jul 2025 13:08:12 +0300 Subject: [PATCH 19/27] not constrain if formal contains constrained type vars --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f73de39efee4..ffecf8113ca3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4360,10 +4360,22 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val pt1 = pt.deepenProtoTrans val approxPt = withMode(Mode.TypevarsMissContext): wildApprox(pt1) + var formalConstrained = false + val tm = new TypeMap: + def apply(t: Type): Type = t match + case tvar: TypeVar => + formalConstrained |= ctx.typerState.constraint.contains(tvar) + val inst = tvar.instanceOpt + if (inst.exists && !formalConstrained) mapOver(inst) else tvar + case _ => + if formalConstrained then t + else mapOver(t) + tm(formal) if (pt1 `ne` pt) && (pt1 ne sharpenedPt) && (AvoidWildcardsMap()(approxPt) `eq` approxPt) - && !isFullyDefined(formal, ForceDegree.none) then + && !isFullyDefined(formal, ForceDegree.none) + && !formalConstrained then constrainResult(tree.symbol, wtp, pt1) val arg = inferImplicitArg(formal, tree.span.endPos) From e41045e739a7c2364bd138dca4e6017c0218e011 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 20 Jul 2025 14:47:30 +0300 Subject: [PATCH 20/27] not constrain if formal contains instantiated type vars --- 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 ffecf8113ca3..f3b200b0cabc 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4364,7 +4364,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val tm = new TypeMap: def apply(t: Type): Type = t match case tvar: TypeVar => - formalConstrained |= ctx.typerState.constraint.contains(tvar) + formalConstrained |= ctx.typerState.constraint.contains(tvar) || tvar.instanceOpt.exists val inst = tvar.instanceOpt if (inst.exists && !formalConstrained) mapOver(inst) else tvar case _ => From 3a4aabd92969f2841ef9a83110677c18160e7184 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 20 Jul 2025 17:33:15 +0300 Subject: [PATCH 21/27] not constrain if formal contains instantiated type vars --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f3b200b0cabc..ae6f6915f203 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4364,9 +4364,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val tm = new TypeMap: def apply(t: Type): Type = t match case tvar: TypeVar => - formalConstrained |= ctx.typerState.constraint.contains(tvar) || tvar.instanceOpt.exists - val inst = tvar.instanceOpt - if (inst.exists && !formalConstrained) mapOver(inst) else tvar + formalConstrained |= ctx.typerState.constraint.contains(tvar) || tvar.instanceOpt.isInstanceOf[TypeVar] + tvar case _ => if formalConstrained then t else mapOver(t) From fe2a943357151cd96b6f6d10d1e50110454a0fae Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 27 Jul 2025 00:24:33 +0300 Subject: [PATCH 22/27] type fully defined then typevar instantiated to other typevar --- .../dotty/tools/dotc/typer/Inferencing.scala | 6 +++-- .../dotty/tools/dotc/typer/ProtoTypes.scala | 2 +- .../src/dotty/tools/dotc/typer/Typer.scala | 27 +++++++++---------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index c581dac5ec52..93aa7e50958c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -231,8 +231,10 @@ object Inferencing { def apply(x: Boolean, tp: Type): Boolean = trace(i"isFullyDefined($tp, $force)", typr) { try { val tpd = tp.dealias - if tpd ne tp then apply(x, tpd) - else tp match + if tpd ne tp then { + (tpd.isInstanceOf[TypeVar] && tp.isInstanceOf[TypeVar]) + || apply(x, tpd) + } else tp match case _: WildcardType | _: ProtoType => false case tvar: TypeVar if !tvar.isInstantiated => 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 ae6f6915f203..024bc056d7ea 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,24 +4358,22 @@ 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 { + !pt1.containsWildcardTypes(using newCtx) + } catch { + case _: UnhandledError => false + } + } val pt1 = pt.deepenProtoTrans - val approxPt = withMode(Mode.TypevarsMissContext): - wildApprox(pt1) - var formalConstrained = false - val tm = new TypeMap: - def apply(t: Type): Type = t match - case tvar: TypeVar => - formalConstrained |= ctx.typerState.constraint.contains(tvar) || tvar.instanceOpt.isInstanceOf[TypeVar] - tvar - case _ => - if formalConstrained then t - else mapOver(t) - tm(formal) if (pt1 `ne` pt) && (pt1 ne sharpenedPt) - && (AvoidWildcardsMap()(approxPt) `eq` approxPt) + && formal.typeSymbol != defn.ClassTagClass && !isFullyDefined(formal, ForceDegree.none) - && !formalConstrained then + && doesntContainsWildcards then constrainResult(tree.symbol, wtp, pt1) val arg = inferImplicitArg(formal, tree.span.endPos) From 33d98ad98225235bcfdcfb42fa0cd3a61948f1f7 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 27 Jul 2025 02:10:56 +0300 Subject: [PATCH 23/27] revert --- compiler/src/dotty/tools/dotc/typer/Inferencing.scala | 6 ++---- compiler/src/dotty/tools/dotc/typer/Typer.scala | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index 93aa7e50958c..c581dac5ec52 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -231,10 +231,8 @@ object Inferencing { def apply(x: Boolean, tp: Type): Boolean = trace(i"isFullyDefined($tp, $force)", typr) { try { val tpd = tp.dealias - if tpd ne tp then { - (tpd.isInstanceOf[TypeVar] && tp.isInstanceOf[TypeVar]) - || apply(x, tpd) - } else tp match + if tpd ne tp then apply(x, tpd) + else tp match case _: WildcardType | _: ProtoType => false case tvar: TypeVar if !tvar.isInstantiated => diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 024bc056d7ea..7181976fd389 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4373,6 +4373,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer && (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, pt1) val arg = inferImplicitArg(formal, tree.span.endPos) From 899c5e64b21c78a2568ac2d41904882998436f56 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 27 Jul 2025 13:00:38 +0300 Subject: [PATCH 24/27] wildApprox before constrain result --- 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 7181976fd389..575ea89b5705 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4378,7 +4378,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer (dty ne ty) && ty.isInstanceOf[TypeVar] && dty.isInstanceOf[TypeVar] }, StopAt.Static, forceLazy = false) && doesntContainsWildcards then - constrainResult(tree.symbol, wtp, pt1) + constrainResult(tree.symbol, wtp, wildApprox(pt1)) val arg = inferImplicitArg(formal, tree.span.endPos) def canProfitFromMoreConstraints = From 53563a7c5001df857e3dc2a0bead7ab39ca57d18 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 27 Jul 2025 18:11:43 +0300 Subject: [PATCH 25/27] use isFullyDefined --- compiler/src/dotty/tools/dotc/typer/Inferencing.scala | 10 ++++++---- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) 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/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 575ea89b5705..c1fbe84c713d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4363,7 +4363,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val newCtx = ctx.fresh.setNewScope.setReporter(new reporting.ThrowingReporter(NoReporter)) val pt1 = pt.deepenProtoTrans(using newCtx) try { - !pt1.containsWildcardTypes(using newCtx) + isFullyDefined(pt1, ForceDegree.none, ifProto = true) } catch { case _: UnhandledError => false } From 01c86206d8e80a26953bc3b7cce78861c8b90444 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 27 Jul 2025 19:36:36 +0300 Subject: [PATCH 26/27] use new ctx in isFullyDefined --- 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 c1fbe84c713d..32015a509865 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4363,7 +4363,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val newCtx = ctx.fresh.setNewScope.setReporter(new reporting.ThrowingReporter(NoReporter)) val pt1 = pt.deepenProtoTrans(using newCtx) try { - isFullyDefined(pt1, ForceDegree.none, ifProto = true) + isFullyDefined(pt1, ForceDegree.none, ifProto = true)(using newCtx) } catch { case _: UnhandledError => false } From 15ea692a0f0308624bc666d1064a7c39a649d4dc Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 27 Jul 2025 23:02:39 +0300 Subject: [PATCH 27/27] disable implicits --- 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 32015a509865..c65fc9c052db 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4378,7 +4378,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer (dty ne ty) && ty.isInstanceOf[TypeVar] && dty.isInstanceOf[TypeVar] }, StopAt.Static, forceLazy = false) && doesntContainsWildcards then - constrainResult(tree.symbol, wtp, wildApprox(pt1)) + withoutMode(Mode.ImplicitsEnabled)(constrainResult(tree.symbol, wtp, wildApprox(pt1))) val arg = inferImplicitArg(formal, tree.span.endPos) def canProfitFromMoreConstraints =