Skip to content

Reference to type parameter name is ambiguous with inner trait and self-type to outer trait #9844

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Sciss opened this issue Sep 21, 2020 · 10 comments

Comments

@Sciss
Copy link
Contributor

Sciss commented Sep 21, 2020

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.

@Sciss
Copy link
Contributor Author

Sciss commented Sep 21, 2020

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

@Sciss
Copy link
Contributor Author

Sciss commented Sep 21, 2020

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)
  }
}

@Sciss
Copy link
Contributor Author

Sciss commented Sep 21, 2020

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)

@griggt
Copy link
Contributor

griggt commented Sep 21, 2020

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.

@Sciss
Copy link
Contributor Author

Sciss commented Sep 21, 2020

@griggt thanks for minimising even further

@griggt
Copy link
Contributor

griggt commented Sep 21, 2020

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.

@som-snytt
Copy link
Contributor

This is the new check #8617 in overdrive.

Scala 2 doesn't benefit from the check yet.

@griggt
Copy link
Contributor

griggt commented Sep 21, 2020

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?

@odersky
Copy link
Contributor

odersky commented Sep 22, 2020

I think all examples should compile.

@odersky
Copy link
Contributor

odersky commented Sep 22, 2020

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

smarter added a commit that referenced this issue Sep 22, 2020
Fix #9844: Exclude private members of wrong classes from findMember
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants