Scala 3中基于细化类型召唤隐式时,类型别名为何引发编译错误?
在Scala 3中基于细化类型召唤隐式的问题分析
问题描述
在Scala 3中尝试基于细化类型召唤隐式时遇到编译错误,示例代码如下:
{ trait Gen { type S type Ext } type GenAux[_S] = Gen { type S = _S } trait Gen_Fallback1 { given [_S]: GenAux[_S] = new Gen { final override type S = _S final override type Ext = _S } } trait Gen_Fallback0 extends Gen_Fallback1 { given GenAux[Int] = new Gen { final override type S = Int final override type Ext = Long } } object Gen extends Gen_Fallback0 { given GenAux[Float] = new Gen { final override type S = Float final override type Ext = Double } } val gen = summon[GenAux[Int]] summon[gen.Ext =:= Long] }
使用Scala 3.3.0编译时会报错:
summon[gen.Ext =:= Long]
^
Cannot prove that gen.Ext =:= Long.
但如果将GenAux从类型别名改为实际的泛型trait,编译就能成功。
原因分析
这一差异的核心在于细化类型别名与泛型trait在隐式解析时的类型信息保留机制不同:
细化类型别名的类型信息丢失
当GenAux[_S]是类型别名(Gen { type S = _S })时,它只是对Gen类型的一种约束描述,仅限定了S等于_S,但不携带实例特化后的其他类型成员信息。编译器完成隐式解析后,只会记录gen的类型是GenAux[Int],无法从这个别名中推断出Ext的具体类型是Long——对编译器而言,gen.Ext仍是一个未被固化的抽象类型成员。泛型trait的类型信息绑定
如果把GenAux改成泛型trait,比如:trait GenAux[_S] extends Gen { type S = _S }此时
GenAux是具体的泛型类型,每个隐式实例都是GenAux[Int]的特化实现,其Ext类型会被明确绑定为Long。编译器在解析隐式时,会将gen的类型与具体实例的类型信息关联,能完整追踪到Ext的具体类型,因此可以证明gen.Ext =:= Long。
内容的提问来源于stack exchange,提问作者tribbloid
相关产品推荐
相关产品推荐

