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 you have a project that's using Rust 2015, and you'd like to use Rust 2018 for it instead, there's a few steps that you need to take.

It's our intention that the migration to new editions is as smooth an experience 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, please file a bug. Thank you!

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


# #![allow(unused_variables)]
#fn main() {
trait Foo {
    fn foo(&self, Box<Foo>);
}
#}

This code uses an anonymous parameter, that Box<Foo>. This is not supported in Rust 2018, and so 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 new edition. In order to help transition to Rust 2018, we've included a new subcommand with Cargo. To start, let's run it:

> cargo fix --edition

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


# #![allow(unused_variables)]
#fn main() {
trait Foo {
    fn foo(&self, _: Box<Foo>);
}
#}

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 is still pretty new, and so it can't always fix your code automatically. If cargo fix can't fix something, it will print the warning that it cannot fix to the console. If you see one of these warnings, you'll have to update your code manually. See the corresponding section of this guide for help, and if you have problems, 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 new edition. Once you're ready to commit, change your Cargo.toml to add the new edition key/value pair. For example:

[package]
name = "foo"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
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 programming language, idioms change over time, and Rust is no exception. While old code will continue to compile, it might be written with different idioms today.

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


# #![allow(unused_variables)]
#fn main() {
trait Foo {
    fn foo(&self, _: Box<Foo>);
}
#}

In Rust 2018, it's considered idiomatic to use the dyn keyword for trait objects.

Eventually, we want cargo fix to fix all these idioms automatically in the same manner we did for upgrading to the 2018 edition. Currently, though, the "idiom lints" are not ready for widespread automatic fixing. The compiler isn't making cargo fix-compatible suggestions in many cases right now, 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 many warnings still remaining.

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

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

$ cargo fix --edition-idioms

Afterwards, src/lib.rs looks like this:


# #![allow(unused_variables)]
#fn main() {
trait Foo {
    fn foo(&self, _: Box<dyn Foo>);
}
#}

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, and you'll have to fix it manually.

As mentioned before, there are known bugs around the idiom lints which means they're not all ready for prime time yet. You may get a scary-looking warning to report a bug to Cargo, which happens whenever a fix proposed by rustc 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 stop compiling, you can execute:

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

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

Enjoy the new edition!