[英]Why are supertrait bounds other than the first not recognized on an associated type?
此代码段在 Rust 1.26.1 中有效:
use std::ops::AddAssign;
trait Trait
where
for<'a> Self: AddAssign<Self> + AddAssign<&'a Self> + Sized,
{
}
trait Trait2 {
type Associated: Trait;
fn method(u32) -> Self::Associated;
}
fn func<T2: Trait2>() {
let mut t = T2::method(1);
let t2 = T2::method(2);
t += &t2;
}
请注意, Trait
实现了AddAssign<Self>
和AddAssign<&'a Trait>
(按这个顺序,这在后面很重要)。 因此,在func
我们知道t += t2
和t += &t2
都应该是有效的。 正如在操场上看到的, t += &t2
是有效的,但使用t += t2
不是:
error[E0308]: mismatched types
--> src/main.rs:19:10
|
19 | t += t2;
| ^^
| |
| expected reference, found associated type
| help: consider borrowing here: `&t2`
|
= note: expected type `&<T2 as Trait2>::Associated`
found type `<T2 as Trait2>::Associated`
我读到这个错误是因为编译器没有认识到AddAssign<Self>
是为T::Associated
,这显然是错误的,因为它实现了Trait
,它需要AddAssign<Self>
。
如果我们更改Trait
上AddAssign
边界的顺序,则相反: t += t2
有效而t += &t2
无效。
该问题的快速解决方法是使func
对两个特征都通用:
fn func<T: Trait, T2: Trait2<Associated = T>>() {
let mut t = T2::method(1);
let t2 = T2::method(2);
t += t2;
}
这不应该是必要的; 编译器可以识别AddAssign
之一,为什么不能识别另一个? 似乎最后一个界限是要被识别的界限。
我的第一个怀疑是这与动态调度有关。 我排除了它,因为即使在动态调度中边界的顺序也不重要。 我什至不认为它使用它,因为所有类型在编译时使用单态化都是已知的。
我目前的怀疑是一个编译器错误,当它是关联类型时,类型检查器不考虑特征边界上的泛型。 很容易想象这样一个特定的案例被忽视了。
这是怎么回事?
这是一个已知的错误(或几个的组合):
解决方法是在每个使用站点重新声明边界:
fn func<T2>()
where
T: Trait2,
T::Associated: Trait,
{
let mut t = T::method(1);
let t2 = T::method(2);
t += &t2;
t += t2;
}
当类型系统从其临时实现转移到Chalk 时,应该解决这个问题, Chalk是一个更原则性的解决方案,用于解决复杂类型系统创建的问题类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.