Consider the following snippet:
object Test extends App {
class X {
class Y
}
class Z(val x: X) {
val y: x.Y = new x.Y
}
val x: X = new X
val z: Z = new Z(x)
val y: x.Y = z.y
println(y)
}
This code won't compile, complaing about incompatible path-dependent types:
[error] 12 | val y: x.Y = z.y
[error] | ^^^
[error] | Found: (Test.z.y : Test.z.x.Y)
[error] | Required: Test.x².Y
[error] |
[error] | where: x is a value in class Z
[error] | x² is a value in object Test
[error] |
Is there a way to gently remind the compiler that zx
is assigned to x
just one line above?
Even if (zx == x) { val y: xY = zy }
does not solve the issue, even though path equivalence should be inferred from control flow.
Background: Scala 3 macro API heavily uses PDT's, and this creates huge amount of pain to deal with --- all this pain is coming from compiler's inability to infer anything, and lack of syntactic structures to explicitly control that inference.
This is correct behavior for path-dependent types (by the way, in Scala 2 it's the same).
Would you be satisfied with
val y: z.x.Y = z.y // compiles
?
zx
equals x
but this doesn't mean that the type zxY
is xY
.
Similarly,
class A {
type T
}
val a = new A
val a1 = a
//implicitly[a.T =:= a1.T] // doesn't compile
a
equals to a1
but this doesn't mean that the type aT
is a1.T
.
This is Scala 2 spec for equivalence of path-dependent types: https://scala-lang.org/files/archive/spec/2.13/03-types.html#equivalence . In our case the prefixes have different singleton types:
implicitly[z.x.type =:= x.type] // doesn't compile
- If a path
p
has a singleton typeq.type
, thenp.type ≡ q.type
.- If
O
is defined by an object definition, andp
is a path consisting only of package or object selectors and ending inO
, thenO.this.type ≡ p.type
.
You can fix the compilation:
class A {
type T
}
val a = new A
val a1: a.type = a
implicitly[a.T =:= a1.T] // compiles
and
class X {
class Y
}
class Z(val x: X) {
type V = x.Y // added
val y: V = new x.Y
}
val x: X = new X
val z: Z = new Z(x)
val y: z.V = z.y // compiles
See also:
In the latest release of scala (2.12.x), is the implementation of path-dependent type incomplete?
Cannot prove equivalence with a path dependent type
Force dependent types resolution for implicit calls
How to help the Scala 3 compiler infer a path-dependent-type?
How to create an instances for typeclass with dependent type using shapeless
If you use REPL you'll see the types inferred by the compiler (removing explicit type annotations as @LuisMiguelMejíaSuárez advised in comments):
scala> class X {
| class Y
| }
class X
scala> class Z(val x: X) {
| val y: x.Y = new x.Y
| }
class Z
scala> val x = new X
val x: X = X@6f76c2cc
scala> val z = new Z(x)
val z: Z = Z@7e62cfa3
scala> val y = z.y
val y: z.x.Y = X$Y@52bd9a27 // notice z.x, not x
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.