-
Notifications
You must be signed in to change notification settings - Fork 21
the protected[this] variance escape hatch is unsound #7093
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
Comments
Imported From: https://issues.scala-lang.org/browse/SI-7093?orig=1 |
@retronym said (edited on Feb 6, 2013 10:22:20 PM UTC): scala> class C extends A[B] with A[C]
<console>:10: error: trait A is inherited twice
class C extends A[B] with A[C]
^ if (parents exists (p => p != parent && p.tpe.typeSymbol == psym && !psym.isError))
pending += ParentInheritedTwiceError(parent, psym)
The checks up the transitive parents come later on, in RefChecks: scala> class C extends B with A[String]
<console>:9: error: illegal inheritance;
class C inherits different type instances of trait A:
A[String] and A[B]
class C extends B with A[String]
^ |
@Blaisorblade said: class C extends B with A[C] That's the same feature that interacts with type refinement for covariant GADTs. |
@odersky said (edited on Sep 25, 2014 2:12:06 PM UTC): trait A {
type X
protected[this] def f(x: X): X = x
}
trait B extends A {
type X <: B
def kaboom = f(new B {})
} This code does not typecheck - kaboom is ill typed. Interestingly, The dotc compiler does not use the straightforward encoding, but instead would type B as follows: trait B extends A {
type X =+ B
def kaboom = f(new B {})
} The "=+" is not available in user code, and has no foundation in DOT. It means in effect something like "covariant alias binding". With this change, the code compiles, and exhibits the same unsoundness hole. Now, as far as I know variant aliases is the most significant deviation of dotc from DOT. It is telling that this deviation leads directly to an unsoundness hole. Why did I add variant aliases? Because, without them, the collections library could not be ingested. So, this points to three possible ways forward, which should be investigated further.
trait B extends A {
type T = B
def kaboom = f(new B {})
} This would then invalidate the definition of C. I believe this is what Paolo was proposing to also fix the GADT problem. |
@Blaisorblade said: |
@odersky said (edited on Sep 25, 2014 4:33:50 PM UTC): trait B extends A[B] --> trait B { type X = B }
trait B extends A[+B] --> trait B { type X <: B } maybe? |
@odersky said: trait B extends A[_ <: B] |
@odersky said: trait B extends A[_ <: B] is legal Scala and expands to exactly what we need in dotty. So, no need for new syntax. |
@Blaisorblade said: scala> trait B extends A[_ <: B]
<console>:20: error: illegal cyclic reference involving trait B
trait B extends A[_ <: B]
^
<console>:20: error: class type required but A[_ <: B] found
trait B extends A[_ <: B]
^ Gotta think more on other points. |
@Blaisorblade said:
What's the problem with collections? The text above mentions |
@retronym said: |
@Blaisorblade said (edited on Sep 25, 2014 11:25:06 PM UTC): Still, I'm under the impression that defining C should probably be allowed by default, so this wouldn't work: trait B extends A[B] --> trait B { type X = B }
trait B extends A[_ <: B] --> trait B { type X <: B } //or trait B { type X = _ <: B }, which seems the same even though it's nicer and we'd need something like this: trait B extends A[=B] --> trait B { type X = B }
trait B extends A[B] --> trait B { type X <: B } (Not enthusiast about the = syntax, but I am sure that picking some syntax is easier than getting soundness). |
@Blaisorblade said: Let's analyze again this code. See the comments. trait B extends A[B] {
def kaboom = f(new B {})
//Scalac seems to "believe" that X = B, in particular that B <: X, but B <:s X is false if we allow defining C. However, B <: X is only used for calling protected[this] methods: we can't refer to X explicitly. However, protected[this] isn't the root of the problem.
//Do variant aliases force Scala to believe that B <: X, and still allow defining C? If so, they seem unsound themselves.
} Does this understanding make sense? |
@odersky said (edited on Sep 26, 2014 9:57:08 AM UTC): Problem with collections: Indeed, collections use the F-bounded pattern systematically and pervasively. E.g. class List[T] extends .... LinearSeqOptimized[T, List[T]] But these recursive occurrences are covariant. So a translation to class List[T] extends .... LinearSeqOptimized[T, _ <: List[T]] looks feasible (although I have not tried it). |
@odersky said: Indeed covariant aliases have the same problems as parameters when combined with protected[this]. It would be nice if we could get rid of them. And the "split encoding" idea of treating some superclass bindings as aliases and others as approximations looks the most promising so far to me. |
@Blaisorblade said:
Sure, I just mean that from this POV the crash is the symptom, not the root cause. trait A {
type X
def f(x: X): X = x //We can totally accept this, even if it would violate variance checking!
}
trait B extends A {
type X <: B
def callF = f(exp) //Here, exp must have type Nothing!
} So, variance violations only translate to "useless" code, not to soundness violations. (And in fact, it's not even useless, since you can set a lower bound later). |
@odersky said: But having a clean translation from declaration site to use site opens up new possibilities. We could make variance violations warnings instead of errors. Or, still use @uncheckedVariance to suppress variance errors, but now we get the assurance that nothing goes wrong. @uncheckedVariance would not present a soundness risk anymore. |
A similar issue with a trait A[+_X] {
protected[this] type X = _X
def f: X
}
trait B extends A[B] {
def f: X = new B {}
}
class C extends B with A[C] {
// should be required because the inherited f is of type B, not C
//override def f: X = new C
}
val c1 = new C
val c2: C = c1.f Both Scala and Dotty will happily compile this and throw a ClassCastException at runtime. |
The text was updated successfully, but these errors were encountered: