最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

rust - implied bounds on associated type work independently but don't compose - Stack Overflow

programmeradmin2浏览0评论

Here is a stripped-down reproduction. The idea is to avoid having to repeat a bunch of bounds on an associated type by using a subtrait to add those as implied bounds on the associated type of the supertrait. It works great (foo and bar in the example), but apparently doesn't compose (baz).

  • Is this a fundamental issue with my approach?
  • Is this a non-fundamental limitation in rustc that might someday be improved?
  • Is there a workaround?

Note that the key issue, afaik, is that rustc understands that W::X = W_Ord::X_Ord, and that W::X = W_Clone::X_Clone, but it has trouble transitively unifying W_Ord::X_Ord = W_Clone::X_Clone

/?version=stable&mode=debug&edition=2024&gist=ab5f8a6621c82c84da2b50b9eb5b3048

trait W {
    type X;
}

/// Trait which provides an implied bound that
// W::X: Ord, with an automatic blanket impl
trait W_Ord: W<X=Self::X_Ord> {
    type X_Ord: Ord;
}
impl<T:W > W_Ord for T where T::X: Ord {
    type X_Ord = T::X;
}

/// Trait which provides an implied bound that
// W::X: Clone, with an automatic blanket impl
trait W_Clone: W<X=Self::X_Clone> {
    type X_Clone: Clone;
}
impl<T:W > W_Clone for T where T::X: Clone {
    type X_Clone = T::X;
}

impl W for u32 {
    type X = u32;
}

/// by using W_Ord, we can rely on T::X: Ord
/// without having to put it in a where clause
fn foo<T: W_Ord>(t: T::X) { t == t; }

/// by using W_Clone, we can rely on T::X: Clone
/// without having to put it in a where clause
fn bar<T: W_Clone>(t: T::X) { t.clone(); }

/// using both at once produces the following error:
/*
error[E0284]: type annotations needed
  --> src/lib.rs:27:31
   |
51 | fn baz<T: W_Ord + W_Clone>(t: T::X) { t == t.clone(); }
   |                               ^^^^ cannot infer type
   |
   = note: cannot satisfy `<T as W>::X == _`

error[E0282]: type annotations needed
  --> src/lib.rs:27:44
   |
51 | fn baz<T: W_Ord + W_Clone>(t: T::X) { t == t.clone(); }
   |                                            ^ cannot infer type
*/
fn baz<T: W_Ord + W_Clone>(t: T::X) { t == t.clone(); }

Here is a stripped-down reproduction. The idea is to avoid having to repeat a bunch of bounds on an associated type by using a subtrait to add those as implied bounds on the associated type of the supertrait. It works great (foo and bar in the example), but apparently doesn't compose (baz).

  • Is this a fundamental issue with my approach?
  • Is this a non-fundamental limitation in rustc that might someday be improved?
  • Is there a workaround?

Note that the key issue, afaik, is that rustc understands that W::X = W_Ord::X_Ord, and that W::X = W_Clone::X_Clone, but it has trouble transitively unifying W_Ord::X_Ord = W_Clone::X_Clone

https://play.rust-lang./?version=stable&mode=debug&edition=2024&gist=ab5f8a6621c82c84da2b50b9eb5b3048

trait W {
    type X;
}

/// Trait which provides an implied bound that
// W::X: Ord, with an automatic blanket impl
trait W_Ord: W<X=Self::X_Ord> {
    type X_Ord: Ord;
}
impl<T:W > W_Ord for T where T::X: Ord {
    type X_Ord = T::X;
}

/// Trait which provides an implied bound that
// W::X: Clone, with an automatic blanket impl
trait W_Clone: W<X=Self::X_Clone> {
    type X_Clone: Clone;
}
impl<T:W > W_Clone for T where T::X: Clone {
    type X_Clone = T::X;
}

impl W for u32 {
    type X = u32;
}

/// by using W_Ord, we can rely on T::X: Ord
/// without having to put it in a where clause
fn foo<T: W_Ord>(t: T::X) { t == t; }

/// by using W_Clone, we can rely on T::X: Clone
/// without having to put it in a where clause
fn bar<T: W_Clone>(t: T::X) { t.clone(); }

/// using both at once produces the following error:
/*
error[E0284]: type annotations needed
  --> src/lib.rs:27:31
   |
51 | fn baz<T: W_Ord + W_Clone>(t: T::X) { t == t.clone(); }
   |                               ^^^^ cannot infer type
   |
   = note: cannot satisfy `<T as W>::X == _`

error[E0282]: type annotations needed
  --> src/lib.rs:27:44
   |
51 | fn baz<T: W_Ord + W_Clone>(t: T::X) { t == t.clone(); }
   |                                            ^ cannot infer type
*/
fn baz<T: W_Ord + W_Clone>(t: T::X) { t == t.clone(); }
Share Improve this question asked Mar 14 at 18:32 ajpajp 2,52518 silver badges23 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

I think you've over-complicated things. This simpler example works:

trait W {
    type X;
}

trait W_Ord: W<X: Ord> {}
impl<T: W> W_Ord for T where T::X: Ord {}

trait W_Clone: W<X: Clone> {}
impl<T: W> W_Clone for T where T::X: Clone {}

impl W for u32 {
    type X = u32;
}

fn baz<T: W_Ord + W_Clone>(t: T::X) { t == t.clone(); }

I believe by having X_Ord and X_Clone as additional associated types and implying the bounds on those separately, its harder for the compiler to link those bounds to T::X.

发布评论

评论列表(0)

  1. 暂无评论