Skip to content

Commit 3d49ba6

Browse files
committed
Don't infer unreducible wildcard applications in approximating type maps
Approximating type maps should not compute illegal unreducible wildcard applications. Instead they should propagate the Range outwards Fixes #5592
1 parent 6871cff commit 3d49ba6

File tree

4 files changed

+48
-34
lines changed

4 files changed

+48
-34
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5487,38 +5487,43 @@ object Types {
54875487
case Range(tyconLo, tyconHi) =>
54885488
range(derivedAppliedType(tp, tyconLo, args), derivedAppliedType(tp, tyconHi, args))
54895489
case _ =>
5490-
if (args.exists(isRange))
5491-
if (variance > 0) tp.derivedAppliedType(tycon, args.map(rangeToBounds))
5492-
else {
5493-
val loBuf, hiBuf = new mutable.ListBuffer[Type]
5494-
// Given `C[A1, ..., An]` where sone A's are ranges, try to find
5495-
// non-range arguments L1, ..., Ln and H1, ..., Hn such that
5496-
// C[L1, ..., Ln] <: C[H1, ..., Hn] by taking the right limits of
5497-
// ranges that appear in as co- or contravariant arguments.
5498-
// Fail for non-variant argument ranges.
5499-
// If successful, the L-arguments are in loBut, the H-arguments in hiBuf.
5500-
// @return operation succeeded for all arguments.
5501-
def distributeArgs(args: List[Type], tparams: List[ParamInfo]): Boolean = args match {
5502-
case Range(lo, hi) :: args1 =>
5503-
val v = tparams.head.paramVarianceSign
5504-
if (v == 0) false
5505-
else {
5506-
if (v > 0) { loBuf += lo; hiBuf += hi }
5507-
else { loBuf += hi; hiBuf += lo }
5508-
distributeArgs(args1, tparams.tail)
5509-
}
5510-
case arg :: args1 =>
5511-
loBuf += arg; hiBuf += arg
5490+
if args.exists(isRange) then
5491+
if variance > 0 then
5492+
tp.derivedAppliedType(tycon, args.map(rangeToBounds)) match
5493+
case tp1: AppliedType if tp1.isUnreducibleWild =>
5494+
// don't infer a type that would trigger an error later in
5495+
// Checling.checkAppliedType; fall through to default handling instead
5496+
case tp1 =>
5497+
return tp1
5498+
end if
5499+
val loBuf, hiBuf = new mutable.ListBuffer[Type]
5500+
// Given `C[A1, ..., An]` where some A's are ranges, try to find
5501+
// non-range arguments L1, ..., Ln and H1, ..., Hn such that
5502+
// C[L1, ..., Ln] <: C[H1, ..., Hn] by taking the right limits of
5503+
// ranges that appear in as co- or contravariant arguments.
5504+
// Fail for non-variant argument ranges.
5505+
// If successful, the L-arguments are in loBut, the H-arguments in hiBuf.
5506+
// @return operation succeeded for all arguments.
5507+
def distributeArgs(args: List[Type], tparams: List[ParamInfo]): Boolean = args match {
5508+
case Range(lo, hi) :: args1 =>
5509+
val v = tparams.head.paramVarianceSign
5510+
if (v == 0) false
5511+
else {
5512+
if (v > 0) { loBuf += lo; hiBuf += hi }
5513+
else { loBuf += hi; hiBuf += lo }
55125514
distributeArgs(args1, tparams.tail)
5513-
case nil =>
5514-
true
5515-
}
5516-
if (distributeArgs(args, tp.tyconTypeParams))
5517-
range(tp.derivedAppliedType(tycon, loBuf.toList),
5518-
tp.derivedAppliedType(tycon, hiBuf.toList))
5519-
else range(defn.NothingType, defn.AnyType)
5520-
// TODO: can we give a better bound than `topType`?
5515+
}
5516+
case arg :: args1 =>
5517+
loBuf += arg; hiBuf += arg
5518+
distributeArgs(args1, tparams.tail)
5519+
case nil =>
5520+
true
55215521
}
5522+
if (distributeArgs(args, tp.tyconTypeParams))
5523+
range(tp.derivedAppliedType(tycon, loBuf.toList),
5524+
tp.derivedAppliedType(tycon, hiBuf.toList))
5525+
else range(defn.NothingType, defn.AnyType)
5526+
// TODO: can we give a better bound than `topType`?
55225527
else tp.derivedAppliedType(tycon, args)
55235528
}
55245529

tests/neg/i5302.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
type L[X]
2-
def foo = { class A; null.asInstanceOf[L[A]] } // error
3-
def bar(x: L[_]) = x // error
2+
def foo = { class A; null.asInstanceOf[L[A]] } // was error, now ok, since avoidance does not produce a bad type anymore
3+
def bar(x: L[_]) = x // error

tests/neg/i5592.scala renamed to tests/pos/i5592.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ object Test {
2020
}
2121

2222
val eqSymmetric2: Forall[[x] =>> (y: Obj) => (EQ[x, y.type]) => (EQ[y.type, x])] = {
23-
{ (x: Obj) => { (y: Obj) => { (xEqy: EQ[x.type, y.type]) => xEqy.commute } } } // error
23+
{ (x: Obj) => { (y: Obj) => { (xEqy: EQ[x.type, y.type]) => xEqy.commute } } } // was error
2424
}
2525

2626
val eqSymmetric3: Forall[[x] =>> Forall[[y] =>> EQ[x, y] => EQ[y, x]]] = {
27-
{ (x: Obj) => { (y: Obj) => { (xEqy: EQ[x.type, y.type]) => xEqy.commute } } } // error
27+
{ (x: Obj) => { (y: Obj) => { (xEqy: EQ[x.type, y.type]) => xEqy.commute } } } // was error
2828
}
2929
}

tests/pos/i9999a.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object Test:
2+
3+
type T[X] <: List[List[X]]
4+
5+
var y = // inferred type: Any, since `T[?]` is irreducible wildcard application
6+
val x: Any = null
7+
??? : T[x.type]
8+
9+
y = (??? : Any)

0 commit comments

Comments
 (0)