Skip to content

Unchecked overridden opaque type #14659

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
prolativ opened this issue Mar 10, 2022 · 1 comment · Fixed by #14665
Closed

Unchecked overridden opaque type #14659

prolativ opened this issue Mar 10, 2022 · 1 comment · Fixed by #14665

Comments

@prolativ
Copy link
Contributor

Compiler version

3.0.0...3.1.2-RC2

Minimized code

trait Foo {
  opaque type Out = Int
  def out1: Out
  def out2: Out = out1
}

object Bar extends Foo {
  override opaque type Out = String
  override def out1 = "abc"
}

@main def run() =
  val x = Bar.out2

Output

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
        at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:99)
        at Bar$.out1(Opaque.scala:9)
        at Foo.out2(Opaque.scala:4)
        at Foo.out2$(Opaque.scala:1)
        at Bar$.out2(Opaque.scala:7)
        at Opaque$package$.run(Opaque.scala:13)
        at run.main(Opaque.scala:12)

Expectation

This should not compile. Instead a compilation error should be reported just like this happens for non-opaque types, e.g.

trait Foo {
  type Out = Int
  def out1: Out
  def out2: Out = out1
}

object Bar extends Foo {
  override type Out = String
  override def out1 = "abc"
}
[error] error overriding type Out in trait Foo, which equals Int;
[error]   type Out, which equals String has incompatible type
[error]   override type Out = String
[error]                 ^

Alternatively maybe we should consider making opaque types unoverridable? It seems quite strange to me that currently it's possible to override a concrete opaque type although you cannot define an abstract one. Additionally it looks like redefining an opaque type in a subtype works as a hack to leak the opaque type's internals, e.g. the code below compiles successfully unless you comment out the marked line:

trait Foo {
  opaque type Out = Int
  def out1: Out
  def out2: Out = out1
}

object Bar extends Foo {
  override opaque type Out = Int // compilation breaks if this line gets commented out
  override def out1 = 1
}
@Swoorup
Copy link

Swoorup commented Mar 11, 2022

If overriding is disallowed I am wondering if there is any alternative mechanism to reuse the transparent alias mechanism. I have asked a question here: https://contributors.scala-lang.org/t/good-way-to-reuse-opaque-types-transparentness/5642

@Kordyjan Kordyjan added this to the 3.1.3 milestone Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants