Skip to content

Instantly share code, notes, and snippets.

@Centril
Last active August 9, 2018 06:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Centril/7288e8b8f2f232f7eecc1d4d86ccaf5f to your computer and use it in GitHub Desktop.
Save Centril/7288e8b8f2f232f7eecc1d4d86ccaf5f to your computer and use it in GitHub Desktop.
Type ascription inference good/bad list

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) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment