Order-dependent type inference failure with match

4a0a8d4
Opened by Joshua Yanovski at 2023-04-05 17:36:43

Not sure if this has been reported yet, but it really seems like Rust should be able to do better here.

This also works if we replace the match with an if let and move the res assignment below it.

Note that this is a reduced testcase and therefore contrived, but the original issue can be seen here.


struct Foo;

impl Foo {
    fn foo(self) -> () { () }
}

fn main() {
    let mut res = None; // Compiles if we use `None::<Foo>`;
    match res {
        Some(winning) => { let _: () = winning.foo(); },
        None => res = Some(Foo), // Compiles if we move the None clause above the Some.
    }
}
<anon>:10:40: 10:53 error: the type of this value must be known in this context
<anon>:10         Some(winning) => { let _: () = winning.foo(); },
                                                 ^~~~~~~~~~~~~
  1. I think https://github.com/rust-lang/rust/issues/22165 may be related too (in particular https://github.com/rust-lang/rust/issues/22165#issuecomment-75415175).

    Joshua Yanovski at 2015-05-07 06:51:41

  2. Looks identical to https://github.com/rust-lang/rust/issues/19855.

    @nikomatsakis Could you clarify what would be required to fix this? It sort of feels like a natural candidate for a bidirectional typechecking approach.

    I strongly disagree that this is expected behavior from the user side of things, even if it falls out naturally from our current inference system. I've run into this many times before and it's always felt like a pretty substantial wart.

    Joshua Yanovski at 2015-05-07 06:54:39

  3. @pythonesque

    We would probably have to run inference in a loop of some sort.

    Ariel Ben-Yehuda at 2015-05-07 16:56:52

  4. I ran into this in #29834. It definitely is a wart. In my case it prevents me from making wrappers around closures without breaking the inference logic:

    struct Wrapper<F>(F);
    struct Foo;
    
    impl Foo {
        fn stuff(self) { }
    }
    
    fn api<F: Fn(Foo)>(f: Wrapper<F>) { }
    
    fn main() {
        api(Wrapper(|b| {
            b.stuff(); //~ ERROR the type of this value must be known in this context
        }))
    }
    

    ... which makes my API really ugly. I too would like to know what's involved with changing this behavior. Perhaps the new MIR stuff can help?

    ebfull at 2015-11-14 21:18:02

  5. @ebfull

    MIR runs only after typechecking, so it can't help.

    Your example should be able to be made to work, though.

    Ariel Ben-Yehuda at 2015-11-15 09:51:13

  6. cc @nikomatsakis

    Ariel Ben-Yehuda at 2015-11-15 18:14:06

  7. The reason that this doesn't work is that the type checker's current design includes various points where it cannot make progress unless it has enough type information. I think the fix would be to reimplement the type checker so that everything is a generic constraint that can be deferred; this way, we would just postpone processing winning.foo() until we learn the type of winning from the other arm. I've been wanting to do some general refactoring of typeck in this direction for some time, but it'd be a big project. I was hoping though to generally refactor typeck as part of the work on MIR -- specifically, to strip out region processing and move that to MIR -- and I was hoping to explore this at that time.

    Niko Matsakis at 2015-12-01 18:50:40

  8. @nikomatsakis

    This may be somewhat problematic because of coercions and autoderefs. Anyway, I feel like regionck is separated enough from typeck.

    Ariel Ben-Yehuda at 2015-12-01 21:46:12

  9. @arielb1 hmm, yes, I agree there are big challenges around coercion. I was hoping we could work around those by being capturing the source order somewhat in the graph, but it may be that it prevents the whole idea from really panning out.

    I strongly disagree about regionck and typeck though. But we can discuss at another time, it's not really that relevant to this bug.

    Niko Matsakis at 2016-01-11 20:14:55

  10. (switched this from C-bug to C-enhancement, because I do not think this represent anything incorrect in our existing type inference; it just is one of many annoying short-comings that we might attempt to address in the future.)

    Felix S Klock II at 2019-03-18 12:06:53