Skip to content

Opaque types incompatible with inline as representation leaks from opaque type's enclosing scope #6662

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
j-mie6 opened this issue Jun 11, 2019 · 1 comment

Comments

@j-mie6
Copy link

j-mie6 commented Jun 11, 2019

The following code worked fine as of 0.15.0-RC1:

opaque type Opt[A >: Null] = A

inline def (x: Opt[A]) nonEmpty[A >: Null]: Boolean = x.get != null
inline def (x: Opt[A]) isEmpty[A >: Null]: Boolean = x.get == null
inline def (x: Opt[A]) isDefined[A >: Null]: Boolean = x.nonEmpty
inline def (x: Opt[A]) get[A >: Null]: A = Opt.unOpt(x)

object Opt
{
    inline def unOpt[A >: Null](x: Opt[A]): A = x
    inline def apply[A >: Null](x: A): Opt[A] = x
    inline def some[A >: Null](x: A): Opt[A] = x
    inline def none[A >: Null]: Opt[A] = null
    inline def fromOption[A >: Null](x: Option[A]) = x.orNull
}

As of 0.16.0-RC3 however, things have changed with opaque types as I understand it. I managed to get everything working again by wrapping in an Object. This code compiles fine:

object opt
{
    opaque type Opt[A >: Null] = A
    object Opt
    {
        inline def unOpt[A >: Null](x: Opt[A]): A = x
        inline def apply[A >: Null](x: A): Opt[A] = x
        /*inline*/ def some[A >: Null](x: A): Opt[A] = x
        /*inline*/ def none[A >: Null]: Opt[A] = null
        inline def fromOption[A >: Null](x: Option[A]) = x.orNull
    }
}

import opt.Opt
inline def (x: Opt[A]) nonEmpty[A >: Null]: Boolean = x.get != null
inline def (x: Opt[A]) isEmpty[A >: Null]: Boolean = x.get == null
inline def (x: Opt[A]) isDefined[A >: Null]: Boolean = x.nonEmpty
inline def (x: Opt[A]) get[A >: Null]: A = Opt.unOpt(x)

However, suppose we uncomment the inline of some or none, then when using either of them we get this compiler error:

-- [E007] Type Mismatch Error: /*snip*/DominatorTree.scala:163:47 
[error] 163 |                    ancestor(cs.get.idx) = some(s)
[error]     |                                           ^^^^^^^
[error]     |Found:    datastructures.opt.Opt[DominatorTree.this.DomNode]
[error]     |Required: datastructures.opt.Opt[DominatorTree.this.DomNode]

This error is pretty obscure, but I imagine it is something to do with the new rules surrounding how opaque types are treated inside and outside of the defining scope (and inline probably makes that leak!).

Additionally, moving any of the extension methods into the opt object makes them give "Member not found errors" when used outside of the opt object's scope if inline is not removed. Placing them inside a delegate for {} and adding inline makes a "An extension method was tried, but could not be fully constructed:" be given in addition. I'm fairly sure this is the same leakage problem, where they are not agreeing with the representation found outside the opt object (and so are method not found) because they see the erased type.

@j-mie6 j-mie6 changed the title Inline and opaque types (and extension methods?) Opaque types incompatible with inline as representation leaks from opaque types enclosing scope Jun 11, 2019
@j-mie6 j-mie6 changed the title Opaque types incompatible with inline as representation leaks from opaque types enclosing scope Opaque types incompatible with inline as representation leaks from opaque type's enclosing scope Jun 11, 2019
@nicolasstucki
Copy link
Contributor

Now there is an implementation restriction that disallows inline methods that have (known) opaque types in their signature.

OlivierBlanvillain added a commit that referenced this issue Jan 9, 2020
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

3 participants