Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to edition handling. #9184

Merged
merged 11 commits into from
Feb 23, 2021
2 changes: 2 additions & 0 deletions crates/cargo-test-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1524,6 +1524,7 @@ fn substitute_macros(input: &str) -> String {
("[REPLACING]", " Replacing"),
("[UNPACKING]", " Unpacking"),
("[SUMMARY]", " Summary"),
("[FIXED]", " Fixed"),
("[FIXING]", " Fixing"),
("[EXE]", env::consts::EXE_SUFFIX),
("[IGNORED]", " Ignored"),
Expand All @@ -1534,6 +1535,7 @@ fn substitute_macros(input: &str) -> String {
("[LOGOUT]", " Logout"),
("[YANK]", " Yank"),
("[OWNER]", " Owner"),
("[MIGRATING]", " Migrating"),
];
let mut result = input.to_owned();
for &(pat, subst) in &macros {
Expand Down
12 changes: 0 additions & 12 deletions src/bin/cargo/commands/fix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,6 @@ pub fn cli() -> App {
.long("edition")
.help("Fix in preparation for the next edition"),
)
.arg(
// This is a deprecated argument, we'll want to phase it out
// eventually.
Arg::with_name("prepare-for")
.long("prepare-for")
.help("Fix warnings in preparation of an edition upgrade")
.takes_value(true)
.possible_values(&["2018"])
.conflicts_with("edition")
.hidden(true),
)
.arg(
Arg::with_name("idioms")
.long("edition-idioms")
Expand Down Expand Up @@ -111,7 +100,6 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
&ws,
&mut ops::FixOptions {
edition: args.is_present("edition"),
prepare_for: args.value_of("prepare-for"),
idioms: args.is_present("idioms"),
compile_opts: opts,
allow_dirty: args.is_present("allow-dirty"),
Expand Down
6 changes: 2 additions & 4 deletions src/cargo/core/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use semver::Version;

use super::BuildContext;
use crate::core::compiler::{CompileKind, Metadata, Unit};
use crate::core::{Edition, Package};
use crate::core::Package;
use crate::util::{self, config, join_paths, process, CargoResult, Config, ProcessBuilder};

/// Structure with enough information to run `rustdoc --test`.
Expand Down Expand Up @@ -187,9 +187,7 @@ impl<'cfg> Compilation<'cfg> {
let rustdoc = process(&*self.config.rustdoc()?);
let cmd = fill_rustc_tool_env(rustdoc, unit);
let mut p = self.fill_env(cmd, &unit.pkg, script_meta, unit.kind, true)?;
if unit.target.edition() != Edition::Edition2015 {
p.arg(format!("--edition={}", unit.target.edition()));
}
unit.target.edition().cmd_edition_arg(&mut p);

for crate_type in unit.target.rustc_crate_types() {
p.arg("--crate-type").arg(crate_type.as_str());
Expand Down
6 changes: 2 additions & 4 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub use crate::core::compiler::unit::{Unit, UnitInterner};
use crate::core::features::nightly_features_allowed;
use crate::core::manifest::TargetSourcePath;
use crate::core::profiles::{PanicStrategy, Profile, Strip};
use crate::core::{Edition, Feature, PackageId, Target};
use crate::core::{Feature, PackageId, Target};
use crate::util::errors::{self, CargoResult, CargoResultExt, ProcessError, VerboseError};
use crate::util::interning::InternedString;
use crate::util::machine_message::Message;
Expand Down Expand Up @@ -782,9 +782,7 @@ fn build_base_args(
cmd.arg("--crate-name").arg(&unit.target.crate_name());

let edition = unit.target.edition();
if edition != Edition::Edition2015 {
cmd.arg(format!("--edition={}", edition));
}
edition.cmd_edition_arg(cmd);

add_path_args(bcx, unit, cmd);
add_error_format_and_color(cx, cmd, cx.rmeta_required(unit));
Expand Down
107 changes: 106 additions & 1 deletion src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ use anyhow::{bail, Error};
use serde::{Deserialize, Serialize};

use crate::util::errors::CargoResult;
use crate::util::indented_lines;
use crate::util::{indented_lines, ProcessBuilder};

pub const SEE_CHANNELS: &str =
"See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information \
Expand All @@ -118,15 +118,117 @@ pub enum Edition {
Edition2021,
}

// Adding a new edition:
// - Add the next edition to the enum.
// - Update every match expression that now fails to compile.
// - Update the `FromStr` impl.
// - Update CLI_VALUES to include the new edition.
// - Set LATEST_UNSTABLE to Some with the new edition.
// - Add an unstable feature to the features! macro below for the new edition.
// - Gate on that new feature in TomlManifest::to_real_manifest.
// - Update the shell completion files.
// - Update any failing tests (hopefully there are very few).
//
// Stabilization instructions:
// - Set LATEST_UNSTABLE to None.
// - Set LATEST_STABLE to the new version.
// - Update `is_stable` to `true`.
// - Set the editionNNNN feature to stable in the features macro below.
// - Update the man page for the --edition flag.
impl Edition {
/// The latest edition that is unstable.
///
/// This is `None` if there is no next unstable edition.
pub const LATEST_UNSTABLE: Option<Edition> = Some(Edition::Edition2021);
/// The latest stable edition.
pub const LATEST_STABLE: Edition = Edition::Edition2018;
/// Possible values allowed for the `--edition` CLI flag.
///
/// This requires a static value due to the way clap works, otherwise I
/// would have built this dynamically.
pub const CLI_VALUES: &'static [&'static str] = &["2015", "2018", "2021"];

/// Returns the first version that a particular edition was released on
/// stable.
pub(crate) fn first_version(&self) -> Option<semver::Version> {
use Edition::*;
match self {
Edition2015 => None,
Edition2018 => Some(semver::Version::new(1, 31, 0)),
// FIXME: This will likely be 1.56, update when that seems more likely.
Edition2021 => Some(semver::Version::new(1, 62, 0)),
}
}

/// Returns `true` if this edition is stable in this release.
pub fn is_stable(&self) -> bool {
use Edition::*;
match self {
Edition2015 => true,
Edition2018 => true,
Edition2021 => false,
}
}

/// Returns the previous edition from this edition.
///
/// Returns `None` for 2015.
pub fn previous(&self) -> Option<Edition> {
use Edition::*;
match self {
Edition2015 => None,
Edition2018 => Some(Edition2015),
Edition2021 => Some(Edition2018),
}
}

/// Returns the next edition from this edition, returning the last edition
/// if this is already the last one.
pub fn saturating_next(&self) -> Edition {
use Edition::*;
match self {
Edition2015 => Edition2018,
Edition2018 => Edition2021,
Edition2021 => Edition2021,
}
}

/// Updates the given [`ProcessBuilder`] to include the appropriate flags
/// for setting the edition.
pub(crate) fn cmd_edition_arg(&self, cmd: &mut ProcessBuilder) {
if *self != Edition::Edition2015 {
cmd.arg(format!("--edition={}", self));
}
if !self.is_stable() {
cmd.arg("-Z").arg("unstable-options");
}
}

/// Whether or not this edition supports the `rust_*_compatibility` lint.
///
/// Ideally this would not be necessary, but currently 2021 does not have
/// any lints, and thus `rustc` doesn't recognize it. Perhaps `rustc`
/// could create an empty group instead?
pub(crate) fn supports_compat_lint(&self) -> bool {
use Edition::*;
match self {
Edition2015 => false,
Edition2018 => true,
Edition2021 => false,
}
}

/// Whether or not this edition supports the `rust_*_idioms` lint.
///
/// Ideally this would not be necessary...
pub(crate) fn supports_idiom_lint(&self) -> bool {
use Edition::*;
match self {
Edition2015 => false,
Edition2018 => true,
Edition2021 => false,
}
}
}

impl fmt::Display for Edition {
Expand Down Expand Up @@ -282,6 +384,9 @@ features! {

// Specifying a minimal 'rust-version' attribute for crates
(unstable, rust_version, "", "reference/unstable.html#rust-version"),

// Support for 2021 edition.
(unstable, edition2021, "", "reference/unstable.html#edition-2021"),
}

const PUBLISH_LOCKFILE_REMOVED: &str = "The publish-lockfile key in Cargo.toml \
Expand Down
45 changes: 30 additions & 15 deletions src/cargo/core/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::core::features::Features;
use crate::core::registry::PackageRegistry;
use crate::core::resolver::features::RequestedFeatures;
use crate::core::resolver::ResolveBehavior;
use crate::core::{Dependency, PackageId, PackageIdSpec};
use crate::core::{Dependency, Edition, PackageId, PackageIdSpec};
use crate::core::{EitherManifest, Package, SourceId, VirtualManifest};
use crate::ops;
use crate::sources::PathSource;
Expand Down Expand Up @@ -88,7 +88,7 @@ pub struct Workspace<'cfg> {
ignore_lock: bool,

/// The resolver behavior specified with the `resolver` field.
resolve_behavior: Option<ResolveBehavior>,
resolve_behavior: ResolveBehavior,

/// Workspace-level custom metadata
custom_metadata: Option<toml::Value>,
Expand Down Expand Up @@ -164,10 +164,7 @@ impl<'cfg> Workspace<'cfg> {
.load_workspace_config()?
.and_then(|cfg| cfg.custom_metadata);
ws.find_members()?;
ws.resolve_behavior = match ws.root_maybe() {
MaybePackage::Package(p) => p.manifest().resolve_behavior(),
MaybePackage::Virtual(vm) => vm.resolve_behavior(),
};
ws.set_resolve_behavior();
ws.validate()?;
Ok(ws)
}
Expand All @@ -189,7 +186,7 @@ impl<'cfg> Workspace<'cfg> {
require_optional_deps: true,
loaded_packages: RefCell::new(HashMap::new()),
ignore_lock: false,
resolve_behavior: None,
resolve_behavior: ResolveBehavior::V1,
custom_metadata: None,
}
}
Expand All @@ -203,11 +200,11 @@ impl<'cfg> Workspace<'cfg> {
let mut ws = Workspace::new_default(current_manifest, config);
ws.root_manifest = Some(root_path.join("Cargo.toml"));
ws.target_dir = config.target_dir()?;
ws.resolve_behavior = manifest.resolve_behavior();
ws.packages
.packages
.insert(root_path, MaybePackage::Virtual(manifest));
ws.find_members()?;
ws.set_resolve_behavior();
// TODO: validation does not work because it walks up the directory
// tree looking for the root which is a fake file that doesn't exist.
Ok(ws)
Expand All @@ -231,7 +228,6 @@ impl<'cfg> Workspace<'cfg> {
let mut ws = Workspace::new_default(package.manifest_path().to_path_buf(), config);
ws.is_ephemeral = true;
ws.require_optional_deps = require_optional_deps;
ws.resolve_behavior = package.manifest().resolve_behavior();
let key = ws.current_manifest.parent().unwrap();
let id = package.package_id();
let package = MaybePackage::Package(package);
Expand All @@ -244,9 +240,28 @@ impl<'cfg> Workspace<'cfg> {
ws.members.push(ws.current_manifest.clone());
ws.member_ids.insert(id);
ws.default_members.push(ws.current_manifest.clone());
ws.set_resolve_behavior();
Ok(ws)
}

fn set_resolve_behavior(&mut self) {
// - If resolver is specified in the workspace definition, use that.
// - If the root package specifies the resolver, use that.
// - If the root package specifies edition 2021, use v2.
// - Otherwise, use the default v1.
self.resolve_behavior = match self.root_maybe() {
MaybePackage::Package(p) => p.manifest().resolve_behavior().or_else(|| {
if p.manifest().edition() >= Edition::Edition2021 {
Some(ResolveBehavior::V2)
} else {
None
}
}),
MaybePackage::Virtual(vm) => vm.resolve_behavior(),
}
.unwrap_or(ResolveBehavior::V1);
}

/// Returns the current package of this workspace.
///
/// Note that this can return an error if it the current manifest is
Expand Down Expand Up @@ -634,7 +649,7 @@ impl<'cfg> Workspace<'cfg> {
}

pub fn resolve_behavior(&self) -> ResolveBehavior {
self.resolve_behavior.unwrap_or(ResolveBehavior::V1)
self.resolve_behavior
}

/// Returns `true` if this workspace uses the new CLI features behavior.
Expand Down Expand Up @@ -843,11 +858,11 @@ impl<'cfg> Workspace<'cfg> {
if !manifest.patch().is_empty() {
emit_warning("patch")?;
}
if manifest.resolve_behavior().is_some()
&& manifest.resolve_behavior() != self.resolve_behavior
{
// Only warn if they don't match.
emit_warning("resolver")?;
if let Some(behavior) = manifest.resolve_behavior() {
if behavior != self.resolve_behavior {
// Only warn if they don't match.
emit_warning("resolver")?;
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/cargo/ops/cargo_new.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::core::{Shell, Workspace};
use crate::core::{Edition, Shell, Workspace};
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo};
use crate::util::{paths, restricted_names, Config};
Expand Down Expand Up @@ -743,7 +743,7 @@ edition = {}
},
match opts.edition {
Some(edition) => toml::Value::String(edition.to_string()),
None => toml::Value::String("2018".to_string()),
None => toml::Value::String(Edition::LATEST_STABLE.to_string()),
},
match opts.registry {
Some(registry) => format!(
Expand Down
Loading