Почему границы супертрейта, кроме первого, не распознаются для ассоциированного типа? - PullRequest
0 голосов
/ 02 июня 2018

Этот фрагмент действителен в 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>.

Если мы изменим порядок AddAssign границ на Trait тогда справедливо обратное: 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 s, почему не другой?Кажется, последний предел - это тот, который должен быть распознан.

Мое первое подозрение было то, что это как-то связано с динамической диспетчеризацией.Я исключил это, поскольку порядок границ не должен иметь значения даже при динамическом распределении.Я даже не думаю, что он использует его, так как все типы известны во время компиляции с использованием мономорфизации.

Мое текущее подозрение - это ошибка компилятора, когда средство проверки типов не учитывает обобщения в границах признаков, когда оносвязанный тип.Легко представить, что такой конкретный случай упускают из виду.

Что здесь происходит?

1 Ответ

0 голосов
/ 03 июня 2018

Это известная ошибка (или их комбинация):

  1. Границы признаков более высокого ранга для связанных типов не разработаны (# 50346) .
  2. , где предложения разрабатываются только для супертрейтов, а не для других вещей (# 20671)
  3. Ограничения на связанные типы, объявленные в подтрейтах, не распространяются.(# 32722)
  4. Нераспознанный связанный тип, связанный с другим связанным типом (# 24159)

Обходной путь - повторять границы при каждом использовании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;
}

Это следует учитывать , когда система типов перемещает из ее ad hoc реализации в Chalk , более принципиальный решательдля типов задач создает сложную систему типов.

...