Skip to content

TypeAssigner#avoid assumes that type variables are always instantiated to their lower bounds #782

Closed
@smarter

Description

@smarter

This is another case where avoid is wrong (see #750, #741, #711, and I can probably come up with more contrived examples too):

class M

class A extends M
class B extends M

class Foo[T](x: T) {
  def foo[S >: T](other: S): Foo[S] = ???
}

object C {
  def xy() = {
    val x: Foo[A] = new Foo(new A)
    x.foo(new B)
  }
}

This compiles but fails with -Ycheck:all because the block inside the method xy() is assigned the type Foo[A | B] but the expression x.foo(new B) is assigned the type Foo[M]:

final module class C$() extends Object() { this: C.type => 
  def xy(): Foo[A | B] = {
    val x: Foo[A] = new Foo[A](new A())
    x.foo[M](new B())
  }
}

The issue is that in TypeAssigner#avoid, when we see the type parameter S >: x.T | B we replace it by A | B (see TypeAssigner.scala#L90-L93), but in TypeVar#interpolate we instantiate S to M because its upper bound is not a union-type (see Types.scala#L2457-L2461).

@odersky : in #750 you said "Maybe we should instantiate those type variables that have escaping refs as bounds", this would also solve this issue. Note that this issue is currently blocking me from experimenting with improving type inference by removing/reducing the use of interpolateUndetVars.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions