-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Intersection types are not commutative for overriding and overloading #5139
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
I think I suggested at some point that erasure should choose deterministically, for example by:
|
Using lexicographical order of names would mean that code could break when you rename a trait even if its name is not mentioned anywhere, like trait B
trait A { // Rename A to C
def m(a:B&this.type) = 1
def m(a:B) = 2 // Ok in A, conflict in C
} That seems brittle. You would also give up any programmer control over the erasure for a quite arbitrary rule. Would it be reasonable to just put the current behavior into the specification? You'd have to weaken the claim that |
That is even more brittle, because the compiler can and might change the order of an At least my proposal is specifiable. |
FWIW, the rules for erasure of & are at https://github.com/lampepfl/dotty/blob/master/compiler/src/dotty/tools/dotc/core/TypeErasure.scala#L299 and the rules for | are at https://github.com/lampepfl/dotty/blob/master/compiler/src/dotty/tools/dotc/core/TypeErasure.scala#L244 The lexicographic tie break makes sense to me, but it doesn't match what scalac is doing (we already don't always match what scalac is doing, but I was hoping we could fix that: #4619 for example), which can lead to issues when using scalac-compiled libraries. |
We could potentially have different erasure rules for symbols that are Scala2-defined or override something that is Scala2-defined, but that seems rather involved. |
Why would the current behavior not be specifiable? It seems we need to take erasure into account only for types that are written down. Those won't be re-arranged by the compiler. Going lexicographic has the mentioned disadvantages wrt renaming and Scala-2 interop. |
The error messages given in the issue are confusing. They stem from the fact that methods are classified according to their signature, which is essentially a string representation of their erased type. Since the erasure of |
Another TODO: Be more precise about what we mean in
Something like:
The issue with |
No, you need to take erasure of the result type of a method into account, and that can be an inferred/lub'ed type. For example, what's the erasure of the following method? def foo(x: Int) =
if (x > 0) (??? : (A & B))
else (??? : (B & A)) The spec won't say anything regarding whether |
@sjrd Why does erasure matter for result types? ... and what does scalac do in this case? |
Result types are part of a JVM method signature. scalac appears to select the one coming from the |
It's a separate issue, dotty does not erase intersections like scala 2, and neither of them is commutative. The plan is to handle intersections coming from scala 2 specially, but we didn't reach a decision for this issue on whether we want to change the dotty-defined intersection type erasure to be commutative (which would be nice indeed). |
Thanks to scala#11603, we can now freely decide how we erase our intersection types without compromising compatibility with Scala 2. We take advantage of this by designing a new erasedGlb algorithm which respects associativity and commutativity and can also erase Java intersections without any special case. This commit also improves the way we handle intersections in Java generic signature to produce more precise types when possible and to ensure that we never emit a type that would lead to javac emitting invalid bytecode (which can happen with Scala 2: scala/bug#12300). Fixes scala#5139.
Thanks to scala#11603, we can now freely decide how we erase our intersection types without compromising compatibility with Scala 2. We take advantage of this by designing a new erasedGlb algorithm which respects associativity and commutativity and can also erase Java intersections without any special case. This commit also improves the way we handle intersections in Java generic signature to produce more precise types when possible and to ensure that we never emit a type that would lead to javac emitting invalid bytecode (which can happen with Scala 2: scala/bug#12300). Fixes scala#5139.
Thanks to scala#11603, we can now freely decide how we erase our intersection types without compromising compatibility with Scala 2. We take advantage of this by designing a new erasedGlb algorithm which respects associativity and commutativity and can also erase Java intersections without any special case. Incidentally, this lets us reverse a recent change in scala-stm which was previously required due to two equivalent types ending up with different signatures. This commit also improves the way we handle intersections in Java generic signature to produce more precise types when possible and to ensure that we never emit a type that would lead to javac emitting invalid bytecode (which can happen with Scala 2: scala/bug#12300). Fixes scala#5139.
What about using the LUB? Worst case the JVM sees it as returning Object. I assume Scala will still see it as the correct type either way. |
Thanks to scala#11603, we can now freely decide how we erase our intersection types without compromising compatibility with Scala 2. We take advantage of this by designing a new erasedGlb algorithm which respects associativity and commutativity and can also erase Java intersections without any special case. Incidentally, this lets us reverse a recent change in scala-stm which was previously required due to two equivalent types ending up with different signatures. This commit also improves the way we handle intersections in Java generic signature to produce more precise types when possible and to ensure that we never emit a type that would lead to javac emitting invalid bytecode (which can happen with Scala 2: scala/bug#12300). Fixes scala#5139.
Some problems with using the lub:
In any case, I've already opened #11808 to fix this issue which I believe is optimal. |
Thanks to scala#11603, we can now freely decide how we erase our intersection types without compromising compatibility with Scala 2. We take advantage of this by designing a new erasedGlb algorithm which respects associativity and commutativity and can also erase Java intersections without any special case. Incidentally, this lets us reverse a recent change in scala-stm which was previously required due to two equivalent types ending up with different signatures. This commit also improves the way we handle intersections in Java generic signature to produce more precise types when possible and to ensure that we never emit a type that would lead to javac emitting invalid bytecode (which can happen with Scala 2: scala/bug#12300). Fixes scala#5139.
Thanks to scala#11603, we can now freely decide how we erase our intersection types without compromising compatibility with Scala 2. We take advantage of this by designing a new erasedGlb algorithm which respects associativity and commutativity and can also erase Java intersections without any special case. Incidentally, this lets us reverse a recent change in scala-stm which was previously required due to two equivalent types ending up with different signatures. This commit also improves the way we handle intersections in Java generic signature to produce more precise types when possible and to ensure that we never emit a type that would lead to javac emitting invalid bytecode (which can happen with Scala 2: scala/bug#12300). Fixes scala#5139.
Thanks to scala#11603, we can now freely decide how we erase our intersection types without compromising compatibility with Scala 2. We take advantage of this by designing a new erasedGlb algorithm which respects associativity and commutativity and can also erase Java intersections without any special case. Incidentally, this lets us reverse a recent change in scala-stm which was previously required due to two equivalent types ending up with different signatures. This commit also improves the way we handle intersections in Java generic signature to produce more precise types when possible and to ensure that we never emit a type that would lead to javac emitting invalid bytecode (which can happen with Scala 2: scala/bug#12300). Fixes scala#5139.
Thanks to scala#11603, we can now freely decide how we erase our intersection types without compromising compatibility with Scala 2. We take advantage of this by designing a new erasedGlb algorithm which respects associativity and commutativity and can also erase Java intersections without any special case. Incidentally, this lets us reverse a recent change in scala-stm which was previously required due to two equivalent types ending up with different signatures. This commit also improves the way we handle intersections in Java generic signature to produce more precise types when possible and to ensure that we never emit a type that would lead to javac emitting invalid bytecode (which can happen with Scala 2: scala/bug#12300). Fixes scala#5139.
Although
A & B
andB & A
are claimed to be the same type, the are not the same for overriding and overloading.It seems to be "caused" by erasue, which erases
A & B
toA
andB & A
toB
.Overriding
Output:
On the other hand, if the
override
is omitted, an error is correctly issued.Also, when the first type in the intersection is the same (therefore erased type is the same), overriding works as expected:
Overloading
Similarly, overloading is allowed when the first type differs.
On the other hand, such methods cannot be called, as expected:
That seems to be the same behavior as with scalac.
The text was updated successfully, but these errors were encountered: