对象内不透明类型与匹配类型结合时无法summon实例求助
Scala 3匹配类型与路径依赖Opaque类型的兼容问题
问题现象
核心矛盾是顶级Opaque类型和嵌套在object中的路径依赖Opaque类型,在匹配类型Flatten中的表现不一致:
- 顶级
MyString作为二元组元素时,summon[(MyString, Int) =:= Flatten[(MyString, Int)]]编译正常 - 嵌套的
Bar.MyString做同样操作时,编译失败 - 注释掉
Flatten中第一个递归分支后,两个summon都能通过
根因
这是Scala 3匹配类型的行为细节:处理路径依赖的Opaque类型时,编译器尝试匹配第一个分支((a, b), c)时,会错误地认为Bar.MyString可能是元组(哪怕它实际是String的Opaque别名),从而进入递归分支推导Flatten[(Bar.MyString, Int)],最终推导结果和原类型不匹配。而顶级Opaque类型的类型信息更明确,编译器能直接判定它不是元组,不会触发误匹配。
解决方案
有两种简单修复方式:
方案1:调整匹配分支顺序
把普通二元组的分支case (_, _) => A移到递归分支前面,让编译器优先匹配普通二元组,避免误触发嵌套元组的递归逻辑:
import scala.deriving.* type Flatten[A <: Tuple] <: Tuple = A match case (_, _) => A // 优先匹配普通二元组 case ((a, b), c) => Tuple.Append[Flatten[(a, b)], c] case Tuple1[_] => A case EmptyTuple => EmptyTuple opaque type MyString = String object Bar: opaque type MyString = String def run = summon[(MyString, Int) =:= Flatten[(MyString, Int)]] summon[(Bar.MyString, Int) =:= Flatten[(Bar.MyString, Int)]] // 现在编译正常
方案2:给递归分支加显式约束
如果需要保留原分支顺序,可以给递归分支的嵌套元组元素加上Tuple约束,明确只有当嵌套的第一个元素是元组时才进入递归:
type Flatten[A <: Tuple] <: Tuple = A match case ((a <: Tuple, b), c) => Tuple.Append[Flatten[(a, b)], c] // 显式约束a是Tuple case (_, _) => A case Tuple1[_] => A case EmptyTuple => EmptyTuple
这样编译器会直接排除Bar.MyString(不是Tuple),不会进入递归分支,直接匹配普通二元组分支。
验证
两种方案在Scala 3.3+版本中都能正常编译,两个summon语句都能成功推导类型相等性。
内容的提问来源于stack exchange,提问作者Taig
相关产品推荐
相关产品推荐

