简体   繁体   English

为什么在关联类型上无法识别除第一个之外的超特征边界?

[英]Why are supertrait bounds other than the first not recognized on an associated type?

This snippet is valid in Rust 1.26.1:此代码段在 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;
}

Notice that Trait implements both AddAssign<Self> and AddAssign<&'a Trait> (in that order, which is important later).请注意, Trait实现了AddAssign<Self>AddAssign<&'a Trait> (按这个顺序,这在后面很重要)。 Therefore, in func we know that both t += t2 and t += &t2 should be valid.因此,在func我们知道t += t2t += &t2都应该是有效的。 As seen on the playground , t += &t2 is valid, but using t += t2 isn't :正如在操场上看到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`

I read this error as the compiler not recognizing that AddAssign<Self> is implemented for T::Associated , which is clearly wrong, as it implements Trait , which requires AddAssign<Self> .我读到这个错误是因为编译器没有认识到AddAssign<Self>是为T::Associated ,这显然是错误的,因为它实现了Trait ,它需要AddAssign<Self>

If we change the order of the AddAssign bounds on Trait then the opposite holds: t += t2 is valid while t += &t2 isn't .如果我们更改TraitAddAssign边界的顺序,则相反: t += t2有效t += &t2无效

A quick fix for the problem is to make func generic over both traits :该问题的快速解决方法是使func 对两个特征都通用

fn func<T: Trait, T2: Trait2<Associated = T>>() {
    let mut t = T2::method(1);
    let t2 = T2::method(2);
    t += t2;
}

This shouldn't be necessary;这不应该是必要的; the compiler can recognize one of the AddAssign s, why not the other?编译器可以识别AddAssign之一,为什么不能识别另一个? It seems the last bound is the one to be recognized.似乎最后一个界限是要被识别的界限。

My first suspicion was this this has something to do with dynamic dispatch.我的第一个怀疑是这与动态调度有关。 I ruled it out since the order of the bounds shouldn't matter even in dynamic dispatch.我排除了它,因为即使在动态调度中边界的顺序也不重要。 I don't even think it uses it, since all types are known at compile-time using monomorphisation.我什至不认为它使用它,因为所有类型在编译时使用单态化都是已知的。

My current suspicion is a compiler bug where the typechecker doesn't account for generics on trait bounds when it is an associated type.我目前的怀疑是一个编译器错误,当它是关联类型时,类型检查器不考虑特征边界上的泛型。 It is easy to imagine such a specific case being overlooked.很容易想象这样一个特定的案例被忽视了。

What is going here?这是怎么回事?

This is a known bug (or a combination of a few):这是一个已知的错误(或几个的组合):

  1. Higher-ranked trait bounds on associated types are not elaborated (#50346) .没有详细说明相关类型的更高级别特征边界 (#50346)
  2. where clauses are only elaborated for supertraits, and not other things (#20671) where 子句仅针对超特征进行阐述,而不针对其他内容(#20671)
  3. Constraints on associated types declared in subtraits do not propagate.子特征中声明的关联类型的约束不会传播。 (#32722) (#32722)
  4. Unrecognized associated type bound on another associated type (#24159)无法识别的关联类型绑定到另一个关联类型 (#24159)

The workaround is to restate the bounds at every usage site:解决方法是在每个使用站点重新声明边界:

fn func<T2>()
where
    T: Trait2,
    T::Associated: Trait,
{
    let mut t = T::method(1);
    let t2 = T::method(2);
    t += &t2;
    t += t2;
}

This should be addressed when the type system moves from its ad hoc implementation to Chalk , a more principled solver for the types of problems a complicated type system creates.当类型系统从其临时实现转移到Chalk 时,应该解决这个问题, Chalk是一个更原则性的解决方案,用于解决复杂类型系统创建的问题类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM