This isn't really a bug, just a limitation.
When your closure is typechecked, the type of
idx is a type inference variable (the same sort of thing you end up with when you call
.collect() without annotating the output type). This occurs because you assign the closure to an unannotated local; the compiler can only predict the type of closure arguments in certain scenarios (the closure must be passed in as a function argument with known
Fn bounds, or it must be assigned directly to something annotated as
fn(T) -> U or similar).
There's plenty of things you cannot do with type inference variables:
- Access anything through field or method syntax (
- Methods are forbidden because it's impossible to discover the signature of the method otherwise.
- Dereference them (
- Index into them (
- Call them (
(I'm not sure why those operators are forbidden; it might have to do with the fact that they all normally auto-deref, a behavior that would have to be suppressed on type inference variables)
Some things you are allowed to do with type inference variables are:
- You can supply them as arguments to functions. (
- You can use them as an index (
vec[x]). The output is another type inference variable.
- You can use
>, etc. on them.
- You can match on them and use them as
Your first closure creates
v[idx]—a type inference variable, and compares it using
>. This is allowed. When the type checker checks this, it simply adds a constraint that the unknown type implements
PartialEq<i32>[^1]. Later, once it reaches the call to
condition(x), it can determine that
idx is a
v[idx] is an
i32 and it can verify that it implements the trait.
Your second closure creates
v[idx]—a type inference variable, and tries to access the
0 field. This is forbidden.
[^1]: Technically the type of the
i32 there is another type inference variable since
0 can be any integer type, but the mechanics of type inference for literals are complicated and not worth the effort to discuss.