Scala3中的类型投影是否仍存在不健全问题?
Scala3 类型投影的不健全问题与设计意图分析
Scala3 已移除通用类型投影(general type-projection),因其存在不健全问题——可编译通过的代码会在运行时失败。
示例代码
class A: class X: def outer : A.this.type = A.this class B extends A class C extends A val b0 = new B val b1 = b0 val b2 = new B val c0 = new C val c1 = c0 val c2 = new C val b0x : A#X = new b0.X val pathTypeMatch = b0x match case _ : c2.X => "c2.X" case _ : c1.X => "c1.x" case _ : c0.X => "c0.X" case _ : b2.X => "b2.X" case _ : b1.X => "b1.X" case _ : b0.X => "b0.X" case _ => "ELSE" pathTypeMatch // "b1.x" val projectionTypeMatch = b0x match case _ : C#X => "C#X" case _ : B#X => "B#X" case _ : A#X => "A#X" case _ => "ELSE" projectionTypeMatch // "C#X" !!! val failingTypeMatch = b0x match case cx : C#X => val c : C = cx.outer // Fails at runtime
问题现象
上述代码可正常编译,但运行时会抛出class B cannot be cast to class C异常。
原因分析
编译器认为C#X和B#X的擦除类型均为A#X,因此case cx:C#X分支会被匹配。此时编译器推断cx.outer的类型为C(实际是错误的),进而引发类型转换异常。
编译过程中无任何警告,也未涉及TypeTest。查看projectionTypeMatch的字节码可以发现,三个分支的测试逻辑完全一致。
规范与行为对比
根据Scala类型模式规范:
(类型模式T是……)对类C、p.C或T#C的引用。该类型模式匹配给定类的任何非空实例。注意,类的前缀(若存在)对确定类实例至关重要。
事实上,针对路径依赖类型的匹配符合预期(pathTypeMatch的结果为b1.x),编译器在匹配时会考虑X的外部实例。
我们有理由预期针对投影类型的匹配行为保持一致,不是吗?
核心疑问
- 这种设计的意图是什么?
- Scala3中对类型投影仅允许具体类型的限制是否能实现一致的行为?
内容的提问来源于stack exchange,提问作者Jean-Jacques Lecler
相关产品推荐
相关产品推荐

