Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't the compiler parse "a as u32 < b" or similar?

The following code appears to be trivial and unambiguous (Playground):

let a: u16 = 5;
let b: u32 = 10;

let c = a as u32 < b;

Yet the compiler (as of 2017-05-30) fails with a syntax error:

error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `;`
 --> src/main.rs:6:25
  |
6 |     let c = a as u32 < b;
  |        

What is wrong with the compiler?

like image 587
E_net4 stands with Ukraine Avatar asked May 29 '17 16:05

E_net4 stands with Ukraine


1 Answers

Note: The latest Rust compilers now provide a more useful error message (#42578):

error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison
 --> src/main.rs:6:22
  |
6 |     let c = a as u32 < b;
  |             -------- ^ -- interpreted as generic arguments
  |             |        |
  |             |        not interpreted as comparison
  |             help: try comparing the casted value: `(a as u32)`

This is a known compiler issue (#22644). Simply put, since a type (u32) was followed by <, the compiler attempted to parse < as the beginning of a type parameter list. Hence, the compiler was expecting something like u32 < b >, which would be syntactically valid, even though it doesn't make sense. However, an example that makes perfectly valid Rust is foo as Rc < fmt::Debug >, and if the syntax was too eager to make < the less-than operator, this one would fail just the same.

Of course, technically there are ways around it: C++ and C# have had the same ambiguity from the beginning, they just happen to have a combination of means to disambiguate these cases:

  • different syntax;
  • symbol tables at the parser level;
  • or some form of look-ahead.

Any of these will either have implications in the complexity of the parser or in the complexity of the language's syntax definition. The inclusion of those mechanisms in Rust could lead to breaking changes in the syntax (or probably just the rustc syntax crate).

As there is currently no active discussion to address this issue, a fairly simple and long-term solution is to wrap the cast around parentheses:

let c = (a as u32) < b;
like image 163
E_net4 stands with Ukraine Avatar answered Oct 19 '22 05:10

E_net4 stands with Ukraine