@@ -51,6 +51,7 @@ use rustfix::CodeFix;
51
51
use semver:: Version ;
52
52
use tracing:: { debug, trace, warn} ;
53
53
54
+ pub use self :: fix_edition:: fix_edition;
54
55
use crate :: core:: compiler:: CompileKind ;
55
56
use crate :: core:: compiler:: RustcTargetData ;
56
57
use crate :: core:: resolver:: features:: { DiffMap , FeatureOpts , FeatureResolver , FeaturesFor } ;
@@ -66,6 +67,8 @@ use crate::util::GlobalContext;
66
67
use crate :: util:: { existing_vcs_repo, LockServer , LockServerClient } ;
67
68
use crate :: { drop_eprint, drop_eprintln} ;
68
69
70
+ mod fix_edition;
71
+
69
72
/// **Internal only.**
70
73
/// Indicates Cargo is in fix-proxy-mode if presents.
71
74
/// The value of it is the socket address of the [`LockServer`] being used.
@@ -90,7 +93,7 @@ const IDIOMS_ENV_INTERNAL: &str = "__CARGO_FIX_IDIOMS";
90
93
const SYSROOT_INTERNAL : & str = "__CARGO_FIX_RUST_SRC" ;
91
94
92
95
pub struct FixOptions {
93
- pub edition : bool ,
96
+ pub edition : Option < EditionFixMode > ,
94
97
pub idioms : bool ,
95
98
pub compile_opts : CompileOptions ,
96
99
pub allow_dirty : bool ,
@@ -100,30 +103,66 @@ pub struct FixOptions {
100
103
pub requested_lockfile_path : Option < PathBuf > ,
101
104
}
102
105
106
+ /// The behavior of `--edition` migration.
107
+ #[ derive( Clone , Copy ) ]
108
+ pub enum EditionFixMode {
109
+ /// Migrates the package from the current edition to the next.
110
+ ///
111
+ /// This is the normal (stable) behavior of `--edition`.
112
+ NextRelative ,
113
+ /// Migrates to a specific edition.
114
+ ///
115
+ /// This is used by `-Zfix-edition` to force a specific edition like
116
+ /// `future`, which does not have a relative value.
117
+ OverrideSpecific ( Edition ) ,
118
+ }
119
+
120
+ impl EditionFixMode {
121
+ /// Returns the edition to use for the given current edition.
122
+ pub fn next_edition ( & self , current_edition : Edition ) -> Edition {
123
+ match self {
124
+ EditionFixMode :: NextRelative => current_edition. saturating_next ( ) ,
125
+ EditionFixMode :: OverrideSpecific ( edition) => * edition,
126
+ }
127
+ }
128
+
129
+ /// Serializes to a string.
130
+ fn to_string ( & self ) -> String {
131
+ match self {
132
+ EditionFixMode :: NextRelative => "1" . to_string ( ) ,
133
+ EditionFixMode :: OverrideSpecific ( edition) => edition. to_string ( ) ,
134
+ }
135
+ }
136
+
137
+ /// Deserializes from the given string.
138
+ fn from_str ( s : & str ) -> EditionFixMode {
139
+ match s {
140
+ "1" => EditionFixMode :: NextRelative ,
141
+ edition => EditionFixMode :: OverrideSpecific ( edition. parse ( ) . unwrap ( ) ) ,
142
+ }
143
+ }
144
+ }
145
+
103
146
pub fn fix (
104
147
gctx : & GlobalContext ,
105
148
original_ws : & Workspace < ' _ > ,
106
- root_manifest : & Path ,
107
149
opts : & mut FixOptions ,
108
150
) -> CargoResult < ( ) > {
109
151
check_version_control ( gctx, opts) ?;
110
152
111
153
let mut target_data =
112
154
RustcTargetData :: new ( original_ws, & opts. compile_opts . build_config . requested_kinds ) ?;
113
- if opts. edition {
155
+ if let Some ( edition_mode ) = opts. edition {
114
156
let specs = opts. compile_opts . spec . to_package_id_specs ( & original_ws) ?;
115
157
let members: Vec < & Package > = original_ws
116
158
. members ( )
117
159
. filter ( |m| specs. iter ( ) . any ( |spec| spec. matches ( m. package_id ( ) ) ) )
118
160
. collect ( ) ;
119
- migrate_manifests ( original_ws, & members) ?;
161
+ migrate_manifests ( original_ws, & members, edition_mode ) ?;
120
162
121
163
check_resolver_change ( & original_ws, & mut target_data, opts) ?;
122
164
}
123
- let mut ws = Workspace :: new ( & root_manifest, gctx) ?;
124
- ws. set_resolve_honors_rust_version ( Some ( original_ws. resolve_honors_rust_version ( ) ) ) ;
125
- ws. set_resolve_feature_unification ( original_ws. resolve_feature_unification ( ) ) ;
126
- ws. set_requested_lockfile_path ( opts. requested_lockfile_path . clone ( ) ) ;
165
+ let ws = original_ws. reload ( gctx) ?;
127
166
128
167
// Spin up our lock server, which our subprocesses will use to synchronize fixes.
129
168
let lock_server = LockServer :: new ( ) ?;
@@ -137,8 +176,8 @@ pub fn fix(
137
176
wrapper. env ( BROKEN_CODE_ENV_INTERNAL , "1" ) ;
138
177
}
139
178
140
- if opts. edition {
141
- wrapper. env ( EDITION_ENV_INTERNAL , "1" ) ;
179
+ if let Some ( mode ) = & opts. edition {
180
+ wrapper. env ( EDITION_ENV_INTERNAL , mode . to_string ( ) ) ;
142
181
}
143
182
if opts. idioms {
144
183
wrapper. env ( IDIOMS_ENV_INTERNAL , "1" ) ;
@@ -252,7 +291,11 @@ fn check_version_control(gctx: &GlobalContext, opts: &FixOptions) -> CargoResult
252
291
) ;
253
292
}
254
293
255
- fn migrate_manifests ( ws : & Workspace < ' _ > , pkgs : & [ & Package ] ) -> CargoResult < ( ) > {
294
+ fn migrate_manifests (
295
+ ws : & Workspace < ' _ > ,
296
+ pkgs : & [ & Package ] ,
297
+ edition_mode : EditionFixMode ,
298
+ ) -> CargoResult < ( ) > {
256
299
// HACK: Duplicate workspace migration logic between virtual manifests and real manifests to
257
300
// reduce multiple Migrating messages being reported for the same file to the user
258
301
if matches ! ( ws. root_maybe( ) , MaybePackage :: Virtual ( _) ) {
@@ -263,7 +306,7 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
263
306
. map ( |p| p. manifest ( ) . edition ( ) )
264
307
. max ( )
265
308
. unwrap_or_default ( ) ;
266
- let prepare_for_edition = highest_edition . saturating_next ( ) ;
309
+ let prepare_for_edition = edition_mode . next_edition ( highest_edition ) ;
267
310
if highest_edition == prepare_for_edition
268
311
|| ( !prepare_for_edition. is_stable ( ) && !ws. gctx ( ) . nightly_features_allowed )
269
312
{
@@ -308,7 +351,7 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
308
351
309
352
for pkg in pkgs {
310
353
let existing_edition = pkg. manifest ( ) . edition ( ) ;
311
- let prepare_for_edition = existing_edition . saturating_next ( ) ;
354
+ let prepare_for_edition = edition_mode . next_edition ( existing_edition ) ;
312
355
if existing_edition == prepare_for_edition
313
356
|| ( !prepare_for_edition. is_stable ( ) && !ws. gctx ( ) . nightly_features_allowed )
314
357
{
@@ -1195,10 +1238,10 @@ impl FixArgs {
1195
1238
// ALLOWED: For the internal mechanism of `cargo fix` only.
1196
1239
// Shouldn't be set directly by anyone.
1197
1240
#[ allow( clippy:: disallowed_methods) ]
1198
- let prepare_for_edition = env:: var ( EDITION_ENV_INTERNAL ) . ok ( ) . map ( |_ | {
1199
- enabled_edition
1200
- . unwrap_or ( Edition :: Edition2015 )
1201
- . saturating_next ( )
1241
+ let prepare_for_edition = env:: var ( EDITION_ENV_INTERNAL ) . ok ( ) . map ( |v | {
1242
+ let enabled_edition = enabled_edition . unwrap_or ( Edition :: Edition2015 ) ;
1243
+ let mode = EditionFixMode :: from_str ( & v ) ;
1244
+ mode . next_edition ( enabled_edition )
1202
1245
} ) ;
1203
1246
1204
1247
// ALLOWED: For the internal mechanism of `cargo fix` only.
0 commit comments