Dotty: Reference to type parameter name is ambiguous with inner trait and self-type to outer trait

Created on 21 Sep 2020  路  10Comments  路  Source: lampepfl/dotty

Minimized code

object DetSkipOctree {
  sealed trait Leaf  [PL]
  sealed trait Branch[PL]
} 
trait DetSkipOctree[PL]

class Impl[PL] extends DetSkipOctree[PL] {
  final type Leaf = DetSkipOctree.Leaf[PL]

  protected trait LeftBranchImpl {
    this: DetSkipOctree.Branch[PL] =>

    def demoteLeaf(point: PL, leaf: Leaf): Unit = ???
  }
}

Output

Reference to PL is ambiguous,
it is both defined in class Impl
and inherited subsequently in trait LeftBranchImpl

Expectation

It's clear that PL unambiguously refers to the same thing. This compiles in 2.13.

bug

Most helpful comment

trait Foo[A]

trait Baz[A]  {
  trait Bar {
    this: Foo[A] =>
    def bar(a: A): Unit
  }
}
[info] Compiling 1 Scala source to /src/dotty-issues/i9844/target/scala-0.27/classes ...
[error] -- [E049] Reference Error: /src/dotty-issues/i9844/src/main/scala/Main.scala:6:15 
[error] 6 |    def bar(a: A): Unit
[error]   |               ^
[error]   |               Reference to A is ambiguous,
[error]   |               it is both defined in trait Baz
[error]   |               and inherited subsequently in trait Bar

But compiles successfully with Scala 2.13.3.

All 10 comments

and I can't seem to find a work-around for this to cross-compile 2.13, Dotty

Here is a work-around (I still think this is a bug)

object DetSkipOctree {
  sealed trait Leaf  [PL]
  sealed trait Branch[PL] {
    def newLeaf(qIdx: Int): Leaf[PL]
  }
} 
trait DetSkipOctree[PL]

class Impl[_PL] extends DetSkipOctree[_PL] {
  final type Leaf = DetSkipOctree.Leaf[_PL]

  protected trait LeftBranchImpl {
    this: DetSkipOctree.Branch[_PL] =>

    def demoteLeaf(point: _PL, leaf: Leaf): Unit = ???

    final def insert(point: _PL): Leaf = newLeaf(1234)
  }
}

The work-around does not really work, as eventually there is a problem between _PL and PL, like

bad parameter reference (param)86#_T at pruneErasedDefs
the parameter is type _T in class Impl but the prefix (param)86
does not define any corresponding arguments. while compiling  ...

(here it's _T versus T but it is the same thing)

trait Foo[A]

trait Baz[A]  {
  trait Bar {
    this: Foo[A] =>
    def bar(a: A): Unit
  }
}
[info] Compiling 1 Scala source to /src/dotty-issues/i9844/target/scala-0.27/classes ...
[error] -- [E049] Reference Error: /src/dotty-issues/i9844/src/main/scala/Main.scala:6:15 
[error] 6 |    def bar(a: A): Unit
[error]   |               ^
[error]   |               Reference to A is ambiguous,
[error]   |               it is both defined in trait Baz
[error]   |               and inherited subsequently in trait Bar

But compiles successfully with Scala 2.13.3.

@griggt thanks for minimising even further

Potential workaround:

trait Foo[A]

trait Baz[A]  {
  type Q = A                      // added type alias
  trait Bar {
    this: Foo[A] =>
    def bar(a: Q): Unit
  }
}

and for the original code:

object DetSkipOctree {
  sealed trait Leaf  [PL]
  sealed trait Branch[PL]
}
trait DetSkipOctree[PL]

class Impl[PL] extends DetSkipOctree[PL] {
  final type Leaf = DetSkipOctree.Leaf[PL]

  type PLL = PL                       // added type alias

  protected trait LeftBranchImpl {
    this: DetSkipOctree.Branch[PL] =>

    def demoteLeaf(point: PLL, leaf: Leaf): Unit = ???
  }
}

Seems to work for both dotty and scalac, for these examples.

This is the new check https://github.com/lampepfl/dotty/issues/8617 in overdrive.

Scala 2 doesn't benefit from the check yet.

It actually fails with a different error if compiled with a Dotty without #8622 (the fix for #8617) merged.

I tried it with both dotty 0.23.0 and 0.28.0-bin-SNAPSHOT-git-333ab8e that I patched to remove the change introduced by 8622. The result is the same in both cases:

trait Foo[A]

trait Baz[A]  {
  trait Bar {
    this: Foo[A] =>
    def bar(a: A): Unit
  }
}
[info] Compiling 1 Scala source to /src/dotty-issues/i9844/target/scala-0.23/classes ...
[error] -- Error: /src/dotty-issues/i9844/src/main/scala/Main.scala:6:15 ---------------
[error] 6 |    def bar(a: A): Unit
[error]   |               ^
[error]   |type A in trait Foo cannot be accessed as a member of (Bar.this : Foo[A] & Baz.this.Bar) from trait Bar.

As it differs from Scala 2, what is the expected (documented?) behavior?

I think all examples should compile.

Thanks for the minimizations! That was vey helpful in finding the problem, which turned out to be quite fundamental.

Was this page helpful?
0 / 5 - 0 ratings