Why does cargo fix replace try!() with r#try!() instead of?

Updating an old Rust codebase to edition 2018, it has lots of try!() constructs. cargo fix --edition changes try!() to r#try!(), what is this syntax? I could only find r for “Raw string literals” in the Rust language reference.

The code compiles, but wouldn’t it be more idiomatic to replace r#try!(foo) with “foo?”? I also ran cargo fix --edition-idioms as suggested on https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html but nothing changed.

As a workaround I executed this shell command: find src -name '*.rs' -exec perl -MRegexp::Common -pe'$bp=$RE{balanced}{-parens=>"()"}; s/r#try\!($bp)/substr($1, 1, length($1) - 2) . "?"/ge' -i {} \;

but is there a better way? Is this just a missing feature from cargo fix, should I report it at https://github.com/rust-lang-nursery/rustfix? I’m using rustc 1.31.0-beta.4 (04da282bb 2018-11-01).

1 Like

r#try is using the new raw identifier syntax. I do agree though that try! should probably be replaced by ? instead.

2 Likes

You can automatically fix all of them:

Rustfix only applies suggestions from compiler's error messages. To get the replacement fixed file a bug against the main rust project.

1 Like

Thanks! I see https://rust-lang-nursery.github.io/edition-guide/rust-2018/module-system/raw-identifiers.html explains the motivation for raw identifiers actually was for try!, a macro still usable as long as you can name it:

This feature is useful for a few reasons, but the primary motivation was inter-edition situations. For example, try is not a keyword in the 2015 edition, but is in the 2018 edition. So if you have a library that is written in Rust 2015 and has a try function, to call it in Rust 2018, you’ll need to use the raw identifier.

Wish I would have found Automatically replace all try!() with `?` before I wrote that script, looks a lot more elegant! Impressive you only need to write a rule with replace!(try!(r) => r?) to replace this syntax using cargo rerast, going to have to research more about rerast it looks very useful for many purposes.

Meanwhile I updated my shell/Perl script, this worked for me to replace all instances in my project, leaving it here as an alternative to rerast in case anyone finds it helpful (albeit not as Rust-y as rerast): find src -name '*.rs' -exec perl -MRegexp::Common -0777 -pe'$bp=$RE{balanced}{-parens=>"()"}; s/try\!($bp)/substr($1, 1, length($1) - 2) . "?"/ges' -i {} \;