Input: Gauging feelings about syntax

Does type inference ever need to do a search? I was under the impression it simply look from the other side. I mean, consider the most simple example of type inference:

let foo = "bar";

A search would mean the compiler goes "Does let foo: i32 = "bar"; work? No. Does let foo: Result<bool, f64> = "bar"; work? No..." and so on, until finally it reaches "Does let foo: &str = "bar"; work? Yes!" and picks that type.

I'd be very very surprised if this is how it works. The more logical way to do this is "I don't know what foo is, but I know that bar is &str, so foo is also going to be an &str". Which does not involve a search. And this is how these new inference rules should work as well.

2 Likes

A better case for why an enum should be preferable to a boolean is if you have a single two-options argument, and you pass true because you want to enable cookies, but the argument's name is actually disable_cookies.

3 Likes

If I call a function fn next_enum<T: impl EnumRange>(val: T) -> Option<T> as next_enum(_::Enabled), how deep does searching go before it says "no, I'm not going there"? Because if this is the case, whether _:: works or not depends on the callee signature which feels even worse than not working at all because I have more rules to have to remember about what might or might not work.

1 Like

Exactly as deep as it'd go for next_enum(Default::default()), using exactly the same logic and exactly the same rules.

Of course, instead of "a type that implements Default" it should find "an enum that has an Enabled variant" - but that's a check that's done after the type is inferred, rather than part of the type lookup itself, and if the type that was inferred does not have an Enabled variant - the compiler error should be about the specific type (mentioned by name) not having an Enabled variant, rather about not being able to find a type with that variant. Just like my version with the Default will show an error about the type not implementing Default rather than about not being able to infer a type.

2 Likes

As an example of a real "two unit variant" enum, see Mutability in rustc_middle::mir - Rust

It's really nice in other tuple variants to have a real type that can be passed around, Debuged more clearly, etc.

3 Likes

std::ops::ControlFlow is a good example of this, although it also does some FromResidual magic (which is somehow useable on stable, despite FromResidual being unstable. probably has something to do with the fact that using a trait through an operator doesn't require that trait to be in scope)

solution: don't use this feature here, only use it when it doesn't significantly impair readability.

i think the biggest usecase is in match statements, perhaps clippy could implement a wildcard_enum_outside_match restriction lint.

1 Like