Skip to content

Commit f9aa989

Browse files
authored
Rollup merge of #99629 - obeis:issue-99470, r=compiler-errors
Improve `cannot move out of` error message Closes #99470 r? `@bjorn3`
2 parents 58042bf + 86dd457 commit f9aa989

10 files changed

+154
-61
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+20-10
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use crate::{
3939

4040
use super::{
4141
explain_borrow::{BorrowExplanation, LaterUseKind},
42-
IncludingDowncast, RegionName, RegionNameSource, UseSpans,
42+
DescribePlaceOpt, RegionName, RegionNameSource, UseSpans,
4343
};
4444

4545
#[derive(Debug)]
@@ -137,7 +137,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
137137
span,
138138
desired_action.as_noun(),
139139
partially_str,
140-
self.describe_place_with_options(moved_place, IncludingDowncast(true)),
140+
self.describe_place_with_options(
141+
moved_place,
142+
DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
143+
),
141144
);
142145

143146
let reinit_spans = maybe_reinitialized_locations
@@ -274,8 +277,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
274277
}
275278
}
276279

277-
let opt_name =
278-
self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
280+
let opt_name = self.describe_place_with_options(
281+
place.as_ref(),
282+
DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
283+
);
279284
let note_msg = match opt_name {
280285
Some(ref name) => format!("`{}`", name),
281286
None => "value".to_owned(),
@@ -341,12 +346,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
341346
}
342347
}
343348

344-
let (name, desc) =
345-
match self.describe_place_with_options(moved_place, IncludingDowncast(true)) {
346-
Some(name) => (format!("`{name}`"), format!("`{name}` ")),
347-
None => ("the variable".to_string(), String::new()),
348-
};
349-
let path = match self.describe_place_with_options(used_place, IncludingDowncast(true)) {
349+
let (name, desc) = match self.describe_place_with_options(
350+
moved_place,
351+
DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
352+
) {
353+
Some(name) => (format!("`{name}`"), format!("`{name}` ")),
354+
None => ("the variable".to_string(), String::new()),
355+
};
356+
let path = match self.describe_place_with_options(
357+
used_place,
358+
DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
359+
) {
350360
Some(name) => format!("`{name}`"),
351361
None => "value".to_string(),
352362
};

compiler/rustc_borrowck/src/diagnostics/mod.rs

+57-17
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use itertools::Itertools;
44
use rustc_const_eval::util::{call_kind, CallDesugaringKind};
55
use rustc_errors::{Applicability, Diagnostic};
66
use rustc_hir as hir;
7-
use rustc_hir::def::Namespace;
7+
use rustc_hir::def::{CtorKind, Namespace};
88
use rustc_hir::GeneratorKind;
99
use rustc_infer::infer::TyCtxtInferExt;
1010
use rustc_middle::mir::tcx::PlaceTy;
@@ -16,7 +16,7 @@ use rustc_middle::ty::print::Print;
1616
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
1717
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
1818
use rustc_span::def_id::LocalDefId;
19-
use rustc_span::{symbol::sym, Span, DUMMY_SP};
19+
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
2020
use rustc_target::abi::VariantIdx;
2121
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
2222

@@ -43,7 +43,15 @@ pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionError
4343
pub(crate) use region_name::{RegionName, RegionNameSource};
4444
pub(crate) use rustc_const_eval::util::CallKind;
4545

46-
pub(super) struct IncludingDowncast(pub(super) bool);
46+
pub(super) struct DescribePlaceOpt {
47+
pub including_downcast: bool,
48+
49+
/// Enable/Disable tuple fields.
50+
/// For example `x` tuple. if it's `true` `x.0`. Otherwise `x`
51+
pub including_tuple_field: bool,
52+
}
53+
54+
pub(super) struct IncludingTupleField(pub(super) bool);
4755

4856
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
4957
/// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
@@ -164,7 +172,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
164172
/// End-user visible description of `place` if one can be found.
165173
/// If the place is a temporary for instance, `None` will be returned.
166174
pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
167-
self.describe_place_with_options(place_ref, IncludingDowncast(false))
175+
self.describe_place_with_options(
176+
place_ref,
177+
DescribePlaceOpt { including_downcast: false, including_tuple_field: true },
178+
)
168179
}
169180

170181
/// End-user visible description of `place` if one can be found. If the place is a temporary
@@ -174,7 +185,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
174185
pub(super) fn describe_place_with_options(
175186
&self,
176187
place: PlaceRef<'tcx>,
177-
including_downcast: IncludingDowncast,
188+
opt: DescribePlaceOpt,
178189
) -> Option<String> {
179190
let local = place.local;
180191
let mut autoderef_index = None;
@@ -224,7 +235,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
224235
}
225236
}
226237
}
227-
ProjectionElem::Downcast(..) if including_downcast.0 => return None,
238+
ProjectionElem::Downcast(..) if opt.including_downcast => return None,
228239
ProjectionElem::Downcast(..) => (),
229240
ProjectionElem::Field(field, _ty) => {
230241
// FIXME(project-rfc_2229#36): print capture precisely here.
@@ -238,9 +249,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
238249
let field_name = self.describe_field(
239250
PlaceRef { local, projection: place.projection.split_at(index).0 },
240251
*field,
252+
IncludingTupleField(opt.including_tuple_field),
241253
);
242-
buf.push('.');
243-
buf.push_str(&field_name);
254+
if let Some(field_name_str) = field_name {
255+
buf.push('.');
256+
buf.push_str(&field_name_str);
257+
}
244258
}
245259
}
246260
ProjectionElem::Index(index) => {
@@ -261,6 +275,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
261275
ok.ok().map(|_| buf)
262276
}
263277

278+
fn describe_name(&self, place: PlaceRef<'tcx>) -> Option<Symbol> {
279+
for elem in place.projection.into_iter() {
280+
match elem {
281+
ProjectionElem::Downcast(Some(name), _) => {
282+
return Some(*name);
283+
}
284+
_ => {}
285+
}
286+
}
287+
None
288+
}
289+
264290
/// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
265291
/// a name, or its name was generated by the compiler, then `Err` is returned
266292
fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
@@ -275,7 +301,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
275301
}
276302

277303
/// End-user visible description of the `field`nth field of `base`
278-
fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
304+
fn describe_field(
305+
&self,
306+
place: PlaceRef<'tcx>,
307+
field: Field,
308+
including_tuple_field: IncludingTupleField,
309+
) -> Option<String> {
279310
let place_ty = match place {
280311
PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
281312
PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
@@ -289,7 +320,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
289320
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
290321
},
291322
};
292-
self.describe_field_from_ty(place_ty.ty, field, place_ty.variant_index)
323+
self.describe_field_from_ty(
324+
place_ty.ty,
325+
field,
326+
place_ty.variant_index,
327+
including_tuple_field,
328+
)
293329
}
294330

295331
/// End-user visible description of the `field_index`nth field of `ty`
@@ -298,10 +334,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
298334
ty: Ty<'_>,
299335
field: Field,
300336
variant_index: Option<VariantIdx>,
301-
) -> String {
337+
including_tuple_field: IncludingTupleField,
338+
) -> Option<String> {
302339
if ty.is_box() {
303340
// If the type is a box, the field is described from the boxed type
304-
self.describe_field_from_ty(ty.boxed_ty(), field, variant_index)
341+
self.describe_field_from_ty(ty.boxed_ty(), field, variant_index, including_tuple_field)
305342
} else {
306343
match *ty.kind() {
307344
ty::Adt(def, _) => {
@@ -311,14 +348,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
311348
} else {
312349
def.non_enum_variant()
313350
};
314-
variant.fields[field.index()].name.to_string()
351+
if !including_tuple_field.0 && variant.ctor_kind == CtorKind::Fn {
352+
return None;
353+
}
354+
Some(variant.fields[field.index()].name.to_string())
315355
}
316-
ty::Tuple(_) => field.index().to_string(),
356+
ty::Tuple(_) => Some(field.index().to_string()),
317357
ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
318-
self.describe_field_from_ty(ty, field, variant_index)
358+
self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
319359
}
320360
ty::Array(ty, _) | ty::Slice(ty) => {
321-
self.describe_field_from_ty(ty, field, variant_index)
361+
self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
322362
}
323363
ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
324364
// We won't be borrowck'ing here if the closure came from another crate,
@@ -335,7 +375,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
335375
.unwrap()
336376
.get_root_variable();
337377

338-
self.infcx.tcx.hir().name(var_id).to_string()
378+
Some(self.infcx.tcx.hir().name(var_id).to_string())
339379
}
340380
_ => {
341381
// Might need a revision when the fields in trait RFC is implemented

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_mir_dataflow::move_paths::{
66
};
77
use rustc_span::Span;
88

9-
use crate::diagnostics::UseSpans;
9+
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
1010
use crate::prefixes::PrefixSet;
1111
use crate::MirBorrowckCtxt;
1212

@@ -368,13 +368,31 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
368368
}
369369
_ => {
370370
let source = self.borrowed_content_source(deref_base);
371-
match (self.describe_place(move_place.as_ref()), source.describe_for_named_place())
372-
{
373-
(Some(place_desc), Some(source_desc)) => self.cannot_move_out_of(
371+
let move_place_ref = move_place.as_ref();
372+
match (
373+
self.describe_place_with_options(
374+
move_place_ref,
375+
DescribePlaceOpt {
376+
including_downcast: false,
377+
including_tuple_field: false,
378+
},
379+
),
380+
self.describe_name(move_place_ref),
381+
source.describe_for_named_place(),
382+
) {
383+
(Some(place_desc), Some(name), Some(source_desc)) => self.cannot_move_out_of(
384+
span,
385+
&format!("`{place_desc}` as enum variant `{name}` which is behind a {source_desc}"),
386+
),
387+
(Some(place_desc), Some(name), None) => self.cannot_move_out_of(
388+
span,
389+
&format!("`{place_desc}` as enum variant `{name}`"),
390+
),
391+
(Some(place_desc), _, Some(source_desc)) => self.cannot_move_out_of(
374392
span,
375393
&format!("`{place_desc}` which is behind a {source_desc}"),
376394
),
377-
(_, _) => self.cannot_move_out_of(
395+
(_, _, _) => self.cannot_move_out_of(
378396
span,
379397
&source.describe_for_unnamed_place(self.infcx.tcx),
380398
),

src/test/ui/borrowck/access-mode-in-closures.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0507]: cannot move out of `s.0` which is behind a shared reference
1+
error[E0507]: cannot move out of `s` which is behind a shared reference
22
--> $DIR/access-mode-in-closures.rs:8:15
33
|
44
LL | match *s { S(v) => v }

src/test/ui/borrowck/borrowck-move-error-with-note.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0507]: cannot move out of `f.0` which is behind a shared reference
1+
error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference
22
--> $DIR/borrowck-move-error-with-note.rs:11:11
33
|
44
LL | match *f {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn main() {
2+
let x: &Option<Box<i32>> = &Some(Box::new(0));
3+
4+
match x {
5+
//~^ ERROR cannot move out of `x` as enum variant `Some` which is behind a shared reference
6+
&Some(_y) => (),
7+
&None => (),
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0507]: cannot move out of `x` as enum variant `Some` which is behind a shared reference
2+
--> $DIR/issue-99470-move-out-of-some.rs:4:11
3+
|
4+
LL | match x {
5+
| ^
6+
LL |
7+
LL | &Some(_y) => (),
8+
| ---------
9+
| | |
10+
| | data moved here
11+
| | move occurs because `_y` has type `Box<i32>`, which does not implement the `Copy` trait
12+
| help: consider removing the `&`: `Some(_y)`
13+
14+
error: aborting due to previous error
15+
16+
For more information about this error, try `rustc --explain E0507`.

src/test/ui/moves/moves-based-on-type-block-bad.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0507]: cannot move out of `hellothere.x.0` which is behind a shared reference
1+
error[E0507]: cannot move out of `hellothere.x` as enum variant `Bar` which is behind a shared reference
22
--> $DIR/moves-based-on-type-block-bad.rs:22:19
33
|
44
LL | match hellothere.x {

src/test/ui/nll/move-errors.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ LL | let a = [A("".to_string())][0];
4545
| move occurs because value has type `A`, which does not implement the `Copy` trait
4646
| help: consider borrowing here: `&[A("".to_string())][0]`
4747

48-
error[E0507]: cannot move out of `a.0` which is behind a shared reference
48+
error[E0507]: cannot move out of `a` which is behind a shared reference
4949
--> $DIR/move-errors.rs:38:16
5050
|
5151
LL | let A(s) = *a;
@@ -134,7 +134,7 @@ LL | F(s, mut t) => (),
134134
|
135135
= note: move occurs because these variables have types that don't implement the `Copy` trait
136136

137-
error[E0507]: cannot move out of `x.0` which is behind a shared reference
137+
error[E0507]: cannot move out of `x` as enum variant `Err` which is behind a shared reference
138138
--> $DIR/move-errors.rs:110:11
139139
|
140140
LL | match *x {

0 commit comments

Comments
 (0)