Skip to content

Commit a1813d1

Browse files
oderskytgodzik
authored andcommitted
Constrain by deepening results in more implicit searches
We used to look at deep expected type when the result of an implicit was ambiguous. This could add more constraints which could resolve the ambiguity. We now do the same also if the search type has uninstantiated type variables. In that case, consulting more context might further constrain type variables, which might in turn enlarge the implicit scope so that a solution can be found. Fixes scala#23526 [Cherry-picked 45f7ef6]
1 parent 445baff commit a1813d1

File tree

4 files changed

+35
-13
lines changed

4 files changed

+35
-13
lines changed

compiler/src/dotty/tools/dotc/typer/Synthesizer.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
2828

2929
val synthesizedClassTag: SpecialHandler = (formal, span) =>
3030
def instArg(tp: Type): Type = tp.dealias match
31-
// Special case to avoid instantiating `Int & S` to `Int & Nothing` in
32-
// i16328.scala. The intersection comes from an earlier instantiation
33-
// to an upper bound.
34-
// The dual situation with unions is harder to trigger because lower
35-
// bounds are usually widened during instantiation.
3631
case tp: AndOrType if tp.tp1 =:= tp.tp2 =>
32+
// Special case to avoid instantiating `Int & S` to `Int & Nothing` in
33+
// i16328.scala. The intersection comes from an earlier instantiation
34+
// to an upper bound.
35+
// The dual situation with unions is harder to trigger because lower
36+
// bounds are usually widened during instantiation.
3737
instArg(tp.tp1)
3838
case tvar: TypeVar if ctx.typerState.constraint.contains(tvar) =>
3939
instArg(

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3850,12 +3850,23 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
38503850
implicitArgs(formals2, argIndex + 1, pt)
38513851

38523852
val arg = inferImplicitArg(formal, tree.span.endPos)
3853+
3854+
def canProfitFromMoreConstraints =
3855+
arg.tpe.isInstanceOf[AmbiguousImplicits]
3856+
// ambiguity could be decided by more constraints
3857+
|| !isFullyDefined(formal, ForceDegree.none)
3858+
// more context might constrain type variables which could make implicit scope larger
3859+
38533860
arg.tpe match
3854-
case failed: AmbiguousImplicits =>
3861+
case failed: SearchFailureType if canProfitFromMoreConstraints =>
38553862
val pt1 = pt.deepenProtoTrans
38563863
if (pt1 `ne` pt) && (pt1 ne sharpenedPt) && constrainResult(tree.symbol, wtp, pt1)
3857-
then implicitArgs(formals, argIndex, pt1)
3858-
else arg :: implicitArgs(formals1, argIndex + 1, pt1)
3864+
then return implicitArgs(formals, argIndex, pt1)
3865+
case _ =>
3866+
3867+
arg.tpe match
3868+
case failed: AmbiguousImplicits =>
3869+
arg :: implicitArgs(formals1, argIndex + 1, pt)
38593870
case failed: SearchFailureType =>
38603871
lazy val defaultArg =
38613872
def appPart(t: Tree): Tree = t match

tests/neg/i9568.check

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,10 @@
44
| No given instance of type => Monad[F] was found for parameter ev of method blaMonad in object Test.
55
| I found:
66
|
7-
| Test.blaMonad[F², S](Test.blaMonad[F³, S²])
7+
| Test.blaMonad[F², S]
88
|
9-
| But method blaMonad in object Test does not match type => Monad[F²]
9+
| But method blaMonad in object Test does not match type => Monad[F]
1010
|
1111
| where: F is a type variable with constraint <: [_] =>> Any
1212
| F² is a type variable with constraint <: [_] =>> Any
13-
| F³ is a type variable with constraint <: [_] =>> Any
14-
| S is a type variable
15-
| S² is a type variable
1613
| .

tests/pos/i23526.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
trait B[-A, +To] {
2+
def addOne(e: A): this.type = this
3+
def res(): To
4+
}
5+
6+
class Col[A]
7+
8+
object Factory {
9+
def newB[A](using reflect.ClassTag[A]) = new B[A, Col[A]] { def res(): Col[A] = new Col[A] }
10+
}
11+
12+
def test =
13+
val a = Factory.newB.addOne(1).res()
14+
val b = collection.immutable.ArraySeq.newBuilder.addOne(1).result()

0 commit comments

Comments
 (0)