|
1 |
| -Answer: 112 |
2 |
| -Difficulty: 2 |
| 1 | +Answer: error |
| 2 | +Difficulty: 3 |
3 | 3 |
|
4 | 4 | # Hint
|
5 | 5 |
|
6 |
| -If you are familiar with [higher-rank trait bound][hrtb] syntax, try desugaring |
7 |
| -all the types in the impl signatures and types in `main` into their fully |
8 |
| -explicit form. |
9 |
| - |
10 |
| -[hrtb]: https://doc.rust-lang.org/nomicon/hrtb.html |
| 6 | +The answer is different for Rust versions 1.0 through 1.32 vs 1.33+. The answer |
| 7 | +accepted as correct here is the one for compilers 1.33+. |
11 | 8 |
|
12 | 9 | # Explanation
|
13 | 10 |
|
| 11 | +This is a rare example of a Rust program that *used to* compile. This code |
| 12 | +compiles and runs successfully with every Rust version 1.0 through 1.32, |
| 13 | +printing the output `112`. The reasoning on those compilers is as follows. |
| 14 | + |
14 | 15 | The first impl applies to function pointers of type `fn(T)` where `T` is any
|
15 | 16 | single concrete type. The second impl applies to function pointers of
|
16 |
| -higher-ranked type `for<'a> fn(&'a T)` for some concrete type `T` that outlives |
17 |
| -`'a`. |
| 17 | +[higher-ranked] type `for<'a> fn(&'a T)` for some concrete type `T` that |
| 18 | +outlives `'a`. |
| 19 | + |
| 20 | +[higher-ranked]: https://doc.rust-lang.org/nomicon/hrtb.html |
18 | 21 |
|
19 | 22 | Inside of `main`, the compiler is going to use type inference to substitute all
|
20 | 23 | occurrences of `_` in a type by some concrete type.
|
21 | 24 |
|
22 |
| -For the closure `a` we infer `_ = u8`, yielding the closure type `fn(u8)` taking |
23 |
| -an argument of type `u8` and returning `()`. |
| 25 | +For the function pointer `a` we infer `_ = u8`, yielding the function pointer |
| 26 | +type `fn(u8)` taking an argument of type `u8` and returning `()`. |
24 | 27 |
|
25 | 28 | For `b` we infer `_ = &'x u8` for some concrete lifetime `'x` that will
|
26 | 29 | ultimately feed into the borrow checker. The type of `b` is `fn(&'x u8)`.
|
27 | 30 |
|
28 |
| -And finally for `c` we infer `_ = u8`, yielding the higher-ranked closure type |
29 |
| -`for<'a> fn(&'a u8)`. |
| 31 | +And finally for `c` we infer `_ = u8`, yielding the higher-ranked function |
| 32 | +pointer type `for<'a> fn(&'a u8)`. |
30 | 33 |
|
31 | 34 | Framed in this way, it follows that the trait method calls at the end of `main`
|
32 | 35 | print `112`.
|
| 36 | + |
| 37 | +The compiler's reasoning changed in Rust version 1.33 as part of the ["universe |
| 38 | +transition"] and this program no longer compiles. Under the new model the first |
| 39 | +impl applies to all three function pointers. If the second impl didn't exist, |
| 40 | +the program would compile and print `111`. But with both impls present these are |
| 41 | +considered conflicting impls and the program fails to compile. |
| 42 | + |
| 43 | +["universe transition"]: https://github.com/rust-lang/rust/issues/56105 |
0 commit comments