This question is derived from:
Scala: Abstract types vs generics
In Scala 3, a path-dependent type is a type/bound that binds term(s)/object(s) with a distinct compile-time path signature. As a result, once it is defined (with its upper bound == lowerbound) for a trait, it is considered final and cannot be overridden in any implementing objects:
object Case1 {
trait Sub {
type EE
}
trait S1 extends Sub { type EE = Product }
trait S2 extends Sub { type EE = Tuple }
trait A1 extends S1
trait A2 extends A1 with S2
}
---
: error overriding type EE in trait S1, which equals Product;
type EE in trait S2, which equals Tuple trait A2 inherits conflicting members:
type EE in trait S1, which equals Product and
type EE in trait S2, which equals Tuple
(Note: this can be resolved by declaring an override in trait A2.)
But there is one exception to this rule: this.type
can easily bypass it:
object Case2 {
trait Supe {
type E
trait Sub {
type EE = Supe.this.E
}
}
object S1 extends Supe {
type E = Product
}
object S2 extends Supe {
type E = Tuple
}
trait A1 extends S1.Sub
trait A2 extends A1 with S2.Sub
}
// No compilation error
Why is it special as a path-dependent type? If it is not, what is it? I cannot find any part of the DOT calculus that propose an exclusive rule for it.