如果整数字面量被转换为通用类型,则在降低时会发生崩溃

作者: zygoloid创建于 2025年12月14日更新于 2026年9月2日
标签long term issuetoolchain

测试案例: carbon fn F(N:! Core.IntLiteral()) -> Core.Int(N) { return 0; } fn G() { var n: i32 = F(32); } 请参阅 在 Discord 上的讨论。在类型检查 F 时,我们发现存在一个适用于 IntLiteralImplicitAs(Int(N)) 的通用实现,但我们不会对其进行承诺,因为它不是 final(并且由于孤儿规则,实际上无法是 final)。但是,当我们使用 N = 32 来形成 F 的具体实现时,我们只重新计算了实现证据的查找,而不重新计算调用该函数的常量值,因为在类型检查 F 时,它没有符号常量值。换句话说,我们对上面的 F 处理就像这样: carbon fn F2(N:! Core.IntLiteral()) -> Core.Int(N) { let k: Core.IntLiteral() = // ... return k; } ... 这应该是无效的,但目前被接受,并且出现这种情况会导致工具链崩溃,原因与第一个示例相同。这里有几个可以帮助的事情: * 我们可能应该将 impl forall [N:! IntLiteral] IntLiteral as ImplicitAs(Int(N)) 视为在实现查找目的上有效的 final,这样当我们在 F 中看到转换时就可以对其进行承诺。这正确,因为类型结构中唯一的 ? 具有类型 IntLiteral,因此无法引入任何更多的关联库。而且,这样做会有所帮助,因为这将允许我们在类型检查 F 时验证调用,并知道在形成具体实现时需要重新验证。 * 一旦我们支持形式,则 IntLiteral as ImplicitAs(Int(N)) 实现应受条件约束,即整数字面量具有编译时常量值(并且应取决于该编译时常量值是什么)。这将允许我们拒绝 F2,因为我们无法找到合适的 impl,但使用这种方法可能无法接受 F,因为我们可能无法在检查 F 的定义时验证常量值是否适合 Int(N)。另一个问题是: F 甚至是否有效?如果我们使用一个较大的常量,而该常量不适合所有可能的 N 值,该如何处理?我认为这里的正确权衡可能是,在检查 F 的定义时,检查常量值是否适合 Int(N) 是一个模板阶段检查,不会影响实现选择(即,impl 总是被选择,但可能导致单形化错误),但也许有更好的方式来模拟这种情况。

内容来源: carbon-language/carbon-lang