Skip to content

Commit 06dc5c3

Browse files
authored
Merge pull request #527 from scala/backport-lts-3.3-23532
Backport "Refine implicit search fallbacks for better ClassTag handling" to 3.3 LTS
2 parents 068c6c7 + a1813d1 commit 06dc5c3

File tree

5 files changed

+45
-17
lines changed

5 files changed

+45
-17
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,9 @@ object Inferencing {
377377
}
378378

379379
/** The instantiation decision for given poly param computed from the constraint. */
380-
enum Decision { case Min; case Max; case ToMax; case Skip; case Fail }
380+
enum Decision:
381+
case Min, Max, ToMax, Skip, Fail
382+
381383
private def instDecision(tvar: TypeVar, v: Int, minimizeSelected: Boolean, ifBottom: IfBottom)(using Context): Decision =
382384
import Decision.*
383385
val direction = instDirection(tvar.origin)

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,21 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
2727
private type SpecialHandlers = List[(ClassSymbol, SpecialHandler)]
2828

2929
val synthesizedClassTag: SpecialHandler = (formal, span) =>
30-
def instArg(tp: Type): Type = tp.stripTypeVar 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.
30+
def instArg(tp: Type): Type = tp.dealias match
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)
38+
case tvar: TypeVar if ctx.typerState.constraint.contains(tvar) =>
39+
instArg(
40+
if tvar.hasLowerBound then tvar.instantiate(fromBelow = true)
41+
else if tvar.hasUpperBound then tvar.instantiate(fromBelow = false)
42+
else NoType)
3843
case _ =>
39-
if isFullyDefined(tp, ForceDegree.all) then tp
40-
else NoType // this happens in tests/neg/i15372.scala
44+
tp
4145

4246
val tag = formal.argInfos match
4347
case arg :: Nil =>

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)