Given the following type definitions:
struct Foo(usize);
struct Wrapping<T>(T);
struct Product<A, B>(A, B);
trait Trait { type Assoc; }
struct Bar<'a>(&'a bool);
struct Wibble<'a>(&'a i32, Bar<'a>);
struct Quux<'a, 'b: 'a>(&'a Foo, Bar<'b>);
struct Beta<'a>(&'a Bar<'a>);
The following example definitions are accepted:
// + `fn : fn(usize) -> ()`.
// + `x : usize`
fn good_0(x: usize) {}
// + `good_1 : for<'a> fn(&'a usize) -> ()`.
// + `x : &'a usize`
fn good_1(x: &'a usize) {}
// + `good_2 : for<'a> fn(&'a usize) -> ()`.
// + `x : &'a usize`
fn good_2<'a>(x: &'a usize) {}
// + `good_3 : for<'a> fn(&'a usize) -> ()`.
// + `x : usize`
fn good_3(&x: &usize) {}
// + `good_4 : for fn(usize) -> ()`.
// + `x : &'<tmp> usize`
fn good_4(ref x: usize) {}
// + `good_5 : fn(Foo) -> ()`.
// + `x : usize`
fn good_5(Foo(x)) {}
// + `good_6 : fn(Foo) -> ()`.
// + `x : usize`
fn good_6(Foo(x)) {}
// + `good_7 : for<'a> fn(&'a Foo) -> ()`.
// + `x : &'a usize`
fn good_7(Foo(x): &_) {}
// + `good_8 : fn(Foo) -> ()`.
// + `x : &'<tmp> usize`
fn good_8(Foo(ref x)) {}
// + `good_9 : for<'a> fn(&'a Foo) -> ()`.
// + `x : &'a usize`
fn good_9(Foo(ref x): &_) {}
// + `good_10 : fn([u8; 3]) -> ()`.
// + `a: u8`
// + `b: u8`
// + `c: &'<tmp> u8`
fn good_10([a: u8, b, ref c]) {}
// + `good_11 : for<T: Debug> fn([T; 3]) -> ()`.
// + `a: T`
// + `b: T`
// + `c: T`
fn good_11([a: impl Debug, b, c]) {}
// + `good_13 : fn(Wrapping<usize>) -> ()`.
// + `x : usize`
fn good_13(Wrapping(x: usize)) {}
// + `good_14 : for<T> fn(Wrapping<T>) -> ()`.
// + `x : T`
fn good_14<T>(Wrapping(x: T)) {}
// + `good_15 : for<T: Display> fn(Wrapping<T>) -> ()`.
// + `x : T`
fn good_15(Wrapping(x: impl Display)) {}
// + `good_16 : for<X: Trait> fn(Wrapping<X::Assoc>) -> ()`.
// + `x : <X as Trait>::Assoc`
fn good_16<X: Trait>(Wrapping(x: <X as Trait>::Assoc)) {}
// + `good_17 : for<'a> fn(Wrapping<Bar<'a>>) -> ()`.
// + `x : Bar<'a>`
fn good_17(Wrapping(x: Bar<'_>)) {}
// + `good_18 : for<'a, 'b> fn(Product<&'a i32, &'b u32>) -> ()`.
fn good_18(Product(x: &i32, y: &u32)) {}
impl Foo {
//
// + `good19 : for<'self, 'a, 'b, 'c>
// fn(
// &'self Foo,
// Product<
// &'a u8,
// Product<
// &'b u16,
// &'c u32
// >
// >
// ) -> &'self str`
fn good_19(&self, Product(x: &u8, Product(y: &u16, z: &u32))) -> &str { .. }
}
fn good_20(Wibble(x: &'a i32, y: Bar<'a>)) {}
// + `good_21 : for<'a, 'b: 'a> fn(Quux<'a, 'b>) -> ()`.
fn good_21(Quux(x: &'a Foo, Bar(y: &'b bool))) {}
// + `good_22 : for<'a> fn(Wrapping<&'a usize>) -> ()`.
// + `x : &'a usize'
fn good_22(Wrapping(x: &usize)) {}
// + `good_23 : for<'a: 'b, 'b> fn(&'a Wrapping<&'b usize>) -> ()`.
// + `x : &'a usize'
fn good_23(Wrapping(x: &usize): &_) {}
But the following definitions are rejected:
// The type of `x` is fully ambiguous even if we look at the body.
// The type of `bad_0: fn(?T) -> ()`.
fn bad_0(x) {}
// The compiler has to look at the body to see that `x: u8`:
// The type of `bad_1: fn(?T) -> ()`.
fn bad_1(x) {
let y: u8 = x;
}
// There is an unconstrained unification variable `?T` from `Wrapping<?T>`.
// The type of `bad_2: fn(Wrapping<?T>) -> ()`
fn bad_2(Wrapping(x)) {}
// No lifetime parameter added for `Quux<'?>` to unify with.
fn bad_3(Quux(x, Bar(y))) {}
// Inferred `x: &'a`, `y: &'b Bar<'a>` but `'a != 'b` which `Wibble<'?>` requires.
fn bad_4(Wibble(x: &i32, y: Bar<'_>)) {}
// Rejected because parameter has & but not fully spec type.
fn bad_6(&(x: usize)) {}
// Rejected because parameter has & but not fully spec type.
fn bad_7(&[a: u8, ref b]) {}
// Rejected because parameter has & but not fully spec type.
fn bad_9<T>(Wrapping(x: &T)) {}
// Rejected because parameter has & but not fully spec type.
fn bad_10(Beta(&Bar(&x))) {}
// The two separate `impl Trait`s get each one type parameter
// T and U leading to: [x: T, y: U] which is not well formed.
fn bad_11([x: impl Trait, y: impl Trait]) {}
impl From<usize> for Foo {
// The compiler is not allowed to look at `From<usize>` to
// understand that `x: usize`.
fn from(x) -> Self { Self(x) }
}