Transitioning an existing project to a new edition

New editions might change the way you write Rust – they add new syntax,language, and library features, and also remove features. For example, try,async, and await are keywords in Rust 2018, but not Rust 2015. If youhave a project that's using Rust 2015, and you'd like to use Rust 2018 for itinstead, there's a few steps that you need to take.

It's our intention that the migration to new editions is as smooth anexperience as possible. If it's difficult for you to upgrade to Rust 2018,we consider that a bug. If you run into problems with this process, pleasefile a bug. Thank you!

Here's an example. Imagine we have a crate that has this code insrc/lib.rs:

  1. #![allow(unused_variables)]
  2. fn main() {
  3. trait Foo {
  4. fn foo(&self, Box<Foo>);
  5. }
  6. }

This code uses an anonymous parameter, that Box<Foo>. This is notsupported in Rust 2018, andso this would fail to compile. Let's get this code up to date!

Updating your code to be compatible with the new edition

Your code may or may not use features that are incompatible with the newedition. In order to help transition to Rust 2018, we've included a newsubcommand with Cargo. To start, let's run it:

  1. > cargo fix --edition

This will check your code, and automatically fix any issues that it can.Let's look at src/lib.rs again:

  1. #![allow(unused_variables)]
  2. fn main() {
  3. trait Foo {
  4. fn foo(&self, _: Box<Foo>);
  5. }
  6. }

It's re-written our code to introduce a parameter name for that trait object.In this case, since it had no name, cargo fix will replace it with _,which is conventional for unused variables.

cargo fix can't always fix your code automatically.If cargo fix can't fix something, it will print the warning that it cannot fixto the console. If you see one of these warnings, you'll have to update your codemanually. See the corresponding section of this guide for help, and if you haveproblems, please seek help at the user's forums.

Keep running cargo fix —edition until you have no more warnings.

Congrats! Your code is now valid in both Rust 2015 and Rust 2018!

Enabling the new edition to use new features

In order to use some new features, you must explicitly opt in to the newedition. Once you're ready to commit, change your Cargo.toml to add the newedition key/value pair. For example:

  1. [package]
  2. name = "foo"
  3. version = "0.1.0"
  4. authors = ["Your Name <you@example.com>"]
  5. edition = "2018"

If there's no edition key, Cargo will default to Rust 2015. But in this case,we've chosen 2018, and so our code is compiling with Rust 2018!

Writing idiomatic code in a new edition

Editions are not only about new features and removing old ones. In any programminglanguage, idioms change over time, and Rust is no exception. While old codewill continue to compile, it might be written with different idioms today.

Our sample code contains an outdated idiom. Here it is again:

  1. #![allow(unused_variables)]
  2. fn main() {
  3. trait Foo {
  4. fn foo(&self, _: Box<Foo>);
  5. }
  6. }

In Rust 2018, it's considered idiomatic to use the dynkeyword fortrait objects.

Eventually, we want cargo fix to fix all these idioms automatically in the samemanner we did for upgrading to the 2018 edition. Currently,though, the "idiom lints" are not ready for widespread automatic fixing. Thecompiler isn't making cargo fix-compatible suggestions in many cases rightnow, and it is making incorrect suggestions in others. Enabling the idiom lints,even with cargo fix, is likely to leave your crate either broken or with manywarnings still remaining.

We have plans to make these idiom migrations a seamless part of the Rust 2018experience, but we're not there yet. As a result the following instructions arerecommended only for the intrepid who are willing to work through a fewcompiler/Cargo bugs!

With that out of the way, we can instruct Cargo to fix our code snippet with:

  1. $ cargo fix --edition-idioms

Afterwards, src/lib.rs looks like this:

  1. #![allow(unused_variables)]
  2. fn main() {
  3. trait Foo {
  4. fn foo(&self, _: Box<dyn Foo>);
  5. }
  6. }

We're now more idiomatic, and we didn't have to fix our code manually!

Note that cargo fix may still not be able to automatically update our code.If cargo fix can't fix something, it will print a warning to the console, andyou'll have to fix it manually.

As mentioned before, there are known bugs around the idiom lints whichmeans they're not all ready for prime time yet. You may get a scary-lookingwarning to report a bug to Cargo, which happens whenever a fix proposed byrustc actually caused code to stop compiling by accident. If you'd like cargo fix to make as much progress as possible, even if it causes code to stopcompiling, you can execute:

  1. $ cargo fix --edition-idioms --broken-code

This will instruct cargo fix to apply automatic suggestions regardless ofwhether they work or not. Like usual, you'll see the compilation result afterall fixes are applied. If you notice anything wrong or unusual, please feel freeto report an issue to Cargo and we'll help prioritize and fix it.

Enjoy the new edition!