为什么在关联类型上未识别出第一个特征以外的特征? [英] Why are supertrait bounds other than the first not recognized on an associated type?

查看:82
本文介绍了为什么在关联类型上未识别出第一个特征以外的特征?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此代码段在Rust 1.26.1中有效:

This snippet is valid in 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 += t2t += &t2均应有效.如图所示,在操场上t += &t2是有效的,但使用t += t2并非如此:

Notice that Trait implements both AddAssign<Self> and AddAssign<&'a Trait> (in that order, which is important later). Therefore, in func we know that both t += t2 and t += &t2 should be valid. As seen on the playground, t += &t2 is valid, but using t += t2 isn't:

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`

我之所以会看到此错误,是因为编译器没有意识到为T::Associated实现了AddAssign<Self>,这显然是错误的,因为它实现了需要AddAssign<Self>Trait.

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>.

如果我们更改TraitAddAssign边界的顺序,则相反成立: t += &t2不是.

If we change the order of the AddAssign bounds on Trait then the opposite holds: t += t2 is valid while t += &t2 isn't.

该问题的快速解决方案是使func

A quick fix for the problem is to make func generic over both traits:

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

这不是必需的;编译器可以识别AddAssign之一,为什么不能识别另一个?似乎最后一个界限是要识别的界限.

This shouldn't be necessary; the compiler can recognize one of the AddAssigns, why not the other? 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.

这是怎么回事?

推荐答案

这是一个已知的错误(或几个错误的组合):

This is a known bug (or a combination of a few):

  1. 未详细说明关联类型的特质范围(#50346).
  2. 其中子句仅针对上级特征而不是其他方面进行了详细说明(#20671)
  3. 在子特性中声明的关联类型的约束不会传播. (#32722)
  4. 绑定在另一个关联类型(#24159)上的无法识别的关联类型
  1. Higher-ranked trait bounds on associated types are not elaborated (#50346).
  2. where clauses are only elaborated for supertraits, and not other things (#20671)
  3. Constraints on associated types declared in subtraits do not propagate. (#32722)
  4. Unrecognized associated type bound on another associated type (#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.

这篇关于为什么在关联类型上未识别出第一个特征以外的特征?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆