Expected compiler behavior? (2)

Is it expected that the compiler doesn’t accept the code below?

trait Root:
  type T

trait A[T]

trait B(val root: Root) extends A[root.T]

class AWrapper[T](val a: A[T])

final class BWrapper(val b: B) extends AWrapper[b.root.T](b) 

The compiler error:

Found:    (BWrapper.this.b : Playground.B)
Required: Playground.A[BWrapper.this.b.root.T]

But it seems to me that b is of type Playground.A[BWrapper.this.b.root.T]

Might be inteded? Think what is happening here is that the compiler forgets about where root came from, and sees it just as a value of the class. Changing the code a bit makes things a bit clearer.

trait Root:
  type T

trait A[T]
class B(val root: Root) extends A[root.T]:
  def asA: A[root.T] = this

def makeB(root: Root): A[root.T] = B(root).asA

Here we instead get the error message

Found:    Playground.A[?1.root.T]
Required: Playground.A[root².T]

where:    ?1    is an unknown value of type Playground.B
          root  is a value in class B
          root² is a parameter in method makeB

If we add a type parameter to B for the compiler to “remember” and track the type, like this, it compiles fine.

trait Root:
  type T

trait A[T]
class B[T0](val root: Root {type T = T0}) extends A[root.T]:
  def asA: A[root.T] = this

def makeB(root: Root): A[root.T] = B(root).asA
1 Like

Yeah, the type of B(root) is just B, there’s an open issue for inferring a more precise type: Infer refinement types for val members of traits and abstract classes · Issue #3964 · lampepfl/dotty · GitHub

1 Like

Interesting. Thank you!

Unfortunately, your approach is not practical for my code, so I’ll resort to asInstanceOf casts for now.

Ironically, I find myself doing casts regularly in Scala. I think it’s due to the type checker logic being incomplete in several areas.