No, it works for anything you can implement on a tuple. That doesn't include Fn
though.
...but that doesn't help much does it? If you remove
impl MyTrait for (Foo, Bar) {}
from your example it stops compiling..
It doesn't work for anything (unless you actually want to call the trait methods on the tuple), rustc
isn't smart enough to do back-inference that (A, B): Clone ⊢ A: Clone, B: Clone
fn foo<A, B>(a: A, b: B) where (A, B): Clone {
a.clone();
b.clone();
}
fn main() {
foo(1, 2);
}
error[E0599]: no method named `clone` found for type parameter `A` in the current scope
error[E0599]: no method named `clone` found for type parameter `B` in the current scope
I guess it can't be made to, either, if we want to prevent adding impls from breaking code. Because traits are open, A: Tr, B: Tr ⊢ (A, B): Tr
does not work in reverse.
Not with positive rules, certainly. But given the overlap/orphan rules, I wonder if we could allow it via negative rules -- I can't impl Clone for (NotClone, NotClone)
(since tuples aren't #[fundamental]
), so I'm not sure it's be possible to have a Clone tuple without the types inside being Clone.
But I know negative logic is complicated, so someone with better inference wizardry than I would be needed to say anything confidently.
Would we need to add any implementations? (A, B): Clone
can only be true if A
and B
implement Clone
right?
So the compiler could just infer that A
and B
are bound by Clone
.
Edit: Ah, but that doesn't apply for all traits
So in that case I guess the current proposals are
- Local trait aliases
fn foo<'a, X, Y, Z, A: Tr<X>, B: Tr<Y>>(a: A, b: B) where Tr<T> = MyTrait<T> + Z + 'a
- trait bound application on multiple parameters
fn foo<'a, X, A: B: MyTrait<X> + 'a>(a: A, b: B)
- reusable trait bounds (name?)
fn my_fn< 'a, I, A: Really<Item=I> + ALot<'a, I> + ToType, B: A, // <- B has all the same bounds as A >(a: A, b: B) { ... }
This looks good, but I would mark it as a trait alias, otherwise it would conflict with equality constraints between types.. Something like:
fn foo<'a, X, Y, Z, A: Tr<X>, B: Tr<Y>>(a: A, b: B)
where trait Tr<T> = MyTrait<T> + Z + 'a
IMO this is just ugly and confusing. It's also a great way to confuse the parser
I don't know why that shouldn't be parsable. In my opinion it is pretty clear, but I can understand that it adds to the ambiguity of :
A third option would be back-references to already declared type parameters, e.g.:
fn my_fn<'a, I, A : Really<Item=I> + ALot<'a, I> + ToType, B : as A>(a: A, b: B)
That said, I'd personally prefer local trait aliases out of these options.
I’ve occasionally written things like this to approximate them:
trait Is { type Type; }
impl<T> Is for T { type Type = T; }
impl<A,B,TypeAlias> Something<TypeAlias> for B
where Some<Complicated<Struct<A>, B>>: Is<Type=TypeAlias>
{
fn do_something(&self)->TypeAlias { ... }
}
And just A: B
fn my_fn<
'a,
I,
A: Really<Item=I> + ALot<'a, I> + ToType,
B: A, // <- B has all the same bounds as A
>(a: A, b: B)
{ ... }