Skip to content

Commit 8edf299

Browse files
committed
Infer: Don't minimise to Nothing if there's an upper bound
1 parent c0a7d12 commit 8edf299

File tree

4 files changed

+74
-2
lines changed

4 files changed

+74
-2
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ object Inferencing {
183183
// else hold off instantiating unbounded unconstrained variable
184184
else if direction != 0 then
185185
instantiate(tvar, fromBelow = direction < 0)
186-
else if variance >= 0 && (force.ifBottom == IfBottom.ok || tvar.hasLowerBound) then
186+
else if variance >= 0 && (force.ifBottom == IfBottom.ok && !tvar.hasUpperBound || tvar.hasLowerBound) then
187187
instantiate(tvar, fromBelow = true)
188188
else if variance >= 0 && force.ifBottom == IfBottom.fail then
189189
return false
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package dotty.tools
2+
package dotc
3+
package typer
4+
5+
// Modelling the decision in IsFullyDefined
6+
object InstantiateModel:
7+
enum LB { case NN; case LL; case L1 }; import LB.*
8+
enum UB { case AA; case UU; case U1 }; import UB.*
9+
enum Var { case V; case NotV }; import Var.*
10+
enum MSe { case M; case NotM }; import MSe.*
11+
enum Bot { case Fail; case Ok; case Flip }; import Bot.*
12+
enum Act { case Min; case Max; case ToMax; case Skip; case False }; import Act.*
13+
14+
// NN/AA = Nothing/Any
15+
// LL/UU = the original bounds, on the type parameter
16+
// L1/U1 = the constrained bounds, on the type variable
17+
// V = variance >= 0 ("non-contravariant")
18+
// MSe = minimisedSelected
19+
// Bot = IfBottom
20+
// ToMax = delayed maximisation, via addition to toMaximize
21+
// Skip = minimisedSelected "hold off instantiating"
22+
// False = return false
23+
24+
// there are 9 combinations:
25+
// # | LB | UB | d | // d = direction
26+
// --+----+----+---+
27+
// 1 | L1 | AA | - | L1 <: T
28+
// 2 | L1 | UU | - | L1 <: T <: UU
29+
// 3 | LL | U1 | + | LL <: T <: U1
30+
// 4 | NN | U1 | + | T <: U1
31+
// 5 | L1 | U1 | 0 | L1 <: T <: U1
32+
// 6 | LL | UU | 0 | LL <: T <: UU
33+
// 7 | LL | AA | 0 | LL <: T
34+
// 8 | NN | UU | 0 | T <: UU
35+
// 9 | NN | AA | 0 | T
36+
37+
def decide(lb: LB, ub: UB, v: Var, bot: Bot, m: MSe): Act = (lb, ub) match
38+
case (L1, AA) => Min
39+
case (L1, UU) => Min
40+
case (LL, U1) => Max
41+
case (NN, U1) => Max
42+
43+
case (L1, U1) => if m==M || v==V then Min else ToMax
44+
case (LL, UU) => if m==M || v==V then Min else ToMax
45+
case (LL, AA) => if m==M || v==V then Min else ToMax
46+
47+
case (NN, UU) => bot match
48+
case _ if m==M => Max
49+
//case Ok if v => Min // removed
50+
case Fail if v==V => False
51+
case _ => ToMax
52+
53+
case (NN, AA) => bot match
54+
case _ if m==M => Skip
55+
case Ok if v==V => Min
56+
case Fail if v==V => False
57+
case _ => ToMax

tests/neg/i15525.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def element22(
3737
transmittable20.Type / transmittable21.Type
3838
} = ???
3939

40-
def test22 =
40+
def test22 = // error
4141
Resolution(
4242
element22(
4343
Resolution(element0), Resolution(element0), // error // error

tests/pos/i14218.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class Pet
2+
class Cat extends Pet
3+
4+
class Z1[ S2 <: Pet](val fn: S2 => Unit) // the case: given an upper bound
5+
class Z2[ S1 ](val fn: S1 => Unit) // the counter-example: works without an upper bound
6+
class Z3[-S3 <: Pet](val fn: S3 => Unit)
7+
8+
abstract class Test:
9+
def test =
10+
val r1 = new Z1((_: Pet) => ()); eat[Z1[Pet]](r1) // the case: using the parameter bound in situ infers Z[Nothing]
11+
val r2 = new Z2((_: Pet) => ()); eat[Z2[Pet]](r2) // counter-example: infers as desired without an upper bound
12+
val r3 = new Z3((_: Pet) => ()); eat[Z3[Pet]](r3) // workaround: declare it contravariant
13+
val r4 = new Z1((_: Cat) => ()); eat[Z1[Cat]](r4) // counter-example: infers as desired with a subtype
14+
15+
def eat[T](x: T): Unit

0 commit comments

Comments
 (0)