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

problem with type comparison (`<:`) transitiveness when using `this.type` upper-type-boundary (`>:`) and Self-types together with derivation #5879

Open
ibaklan opened this Issue Feb 8, 2019 · 2 comments

Comments

Projects
None yet
2 participants
@ibaklan
Copy link

ibaklan commented Feb 8, 2019

Problem was disclosed when I was making experiments with possible different implementations of HasThisType, trying to achieve that.type <: that.This relationship visibility from outside of HasThisType trait body (not only in form of this.type <: that.This which is more or less obvious to achieve).

Here is different rewrites of the same snippet (all of them exposes similar and same problem)
complete code snippet here, same code with uncommented problems

rewrite#1

    trait HasThisTypeBase {
      type This >: this.type
    }

    trait HasThisType[PThis] extends HasThisTypeBase {
      this: PThis =>
      type This = PThis
    }

rewrite#2
(other problem with | and .type types described in issue#5878)

    trait HasThisTypeBase[PThis] {
      this: PThis =>
      type ThisB >: this.type <: PThis
    }

    trait HasThisType[PThis] extends HasThisTypeBase[PThis] {
      this: PThis =>
      type This >: ThisB | PThis <: PThis
    }

rewrite#3

    trait HasThisTypeBase[PThis] {
      this: PThis =>
      type This >: this.type <: PThis
    }

    trait HasThisType[PThis] extends HasThisTypeBase[PThis] {
      this: PThis =>
      // same result as with `type This = PThis`
      type This >: PThis <: PThis
    }

In all that cases one may expect that if that: HasThisType[...] then that.type <: that.This - not figuratively but literally
So that following assignment expected to be legal

      def testThis[PThis](that: HasThisType[PThis]): Unit = {
        // suppose valid assignment - got '[E007] Type Mismatch Error'
        val thatSelf: that.This = that
      }

While in reality Dotty compiler reports error in all that 3 cases. While transitive assigment "workarounds" still
available for rewrite#2 and rewrite#3.

For rewrite#2 it will look like

      def testThis[PThis](that: HasThisType[PThis]): Unit = {
        // suppose valid assignment - got '[E007] Type Mismatch Error'
//        val thatSelf: that.This = that

        // but transitive assignment through legal cast to auxiliary/intermediate type `ThisB` compiles and works
        val thatSelf2: that.This = that : that.ThisB
      }

For rewrite#3 it will look like

      def testThis[PThis](that: HasThisType[PThis]): Unit = {
        // suppose valid assignment - got '[E007] Type Mismatch Error'
//        val thatSelf: that.This = that

        // but transitive assignment through auxiliary/intermediate assigment and cast to `thatProof.This` compiles and works
        val thatSelf2: that.This = {
          val thatProof: HasThisTypeBase[PThis] = that
          thatProof: thatProof.This
        }
      }

Also this problem looks a specially strange in case#1, when looking on it as on "merged visibility" problem.
If one may think that Self-types provided constraint this.type <: this.This has some protected visibility, and constraint form HasThisTypeBase in form of
type This >: this.type has public visibility, one may expect that after "merging" of them resulting "visibility" of
this.type <: this.This - constraint should be public, while it looks like in fact that protected visibility unexpectedly prevails over public (and resulting "visibility" become more like protected).

@OlivierBlanvillain

This comment has been minimized.

Copy link
Contributor

OlivierBlanvillain commented Feb 8, 2019

This doesn't lead to a compiler crash, and Scalac/Dotty seam to agree on the errors. Self type do not generate the same constraint that type members, but is that really a problem?

@ibaklan

This comment has been minimized.

Copy link
Author

ibaklan commented Feb 8, 2019

Problem is that sub class with self type hides visibility of This >: this.type in case#1 (for HasThisTypeBase it is visible from outside while for HasThisType it is not)

In case#2 Scala/Dotty fails to infer that.type <: that.This while one could "manually prove" that trough chain that.type <: that.ThisB <: that.This which looks like some sort of <: inconsistency (but probably it could be "expected behavior", is it ?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment