diff options
| -rw-r--r-- | compiler/rustc_hir_typeck/src/expr.rs | 51 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/method/suggest.rs | 3 | ||||
| -rw-r--r-- | tests/ui/coherence/coherence-tuple-conflict.stderr | 2 | ||||
| -rw-r--r-- | tests/ui/consts/issue-19244-1.stderr | 6 | ||||
| -rw-r--r-- | tests/ui/diagnostic-width/long-E0609.stderr | 1 | ||||
| -rw-r--r-- | tests/ui/offset-of/offset-of-tuple-field.stderr | 48 | ||||
| -rw-r--r-- | tests/ui/parser/float-field.stderr | 6 | ||||
| -rw-r--r-- | tests/ui/traits/well-formed-recursion-limit.stderr | 4 | ||||
| -rw-r--r-- | tests/ui/tuple/index-invalid.stderr | 14 | ||||
| -rw-r--r-- | tests/ui/tuple/missing-field-access.rs | 17 | ||||
| -rw-r--r-- | tests/ui/tuple/missing-field-access.stderr | 38 | ||||
| -rw-r--r-- | tests/ui/tuple/tuple-index-out-of-bounds.stderr | 6 |
12 files changed, 174 insertions, 22 deletions
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 454ec7ddcaf..7ec9e7a19ba 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3321,18 +3321,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { (base_ty, "") }; - for (found_fields, args) in + for found_fields in self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, expr.hir_id) { - let field_names = found_fields.iter().map(|field| field.name).collect::<Vec<_>>(); + let field_names = found_fields.iter().map(|field| field.0.name).collect::<Vec<_>>(); let mut candidate_fields: Vec<_> = found_fields .into_iter() .filter_map(|candidate_field| { self.check_for_nested_field_satisfying_condition_for_diag( span, - &|candidate_field, _| candidate_field.ident(self.tcx()) == field, + &|candidate_field, _| candidate_field == field, candidate_field, - args, vec![], mod_id, expr.hir_id, @@ -3396,7 +3395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_ty: Ty<'tcx>, mod_id: DefId, hir_id: HirId, - ) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> { + ) -> Vec<Vec<(Ident, Ty<'tcx>)>> { debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); let mut autoderef = self.autoderef(span, base_ty).silence_errors(); @@ -3422,7 +3421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) { return None; } - return Some(( + return Some( fields .iter() .filter(move |field| { @@ -3431,9 +3430,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) // For compile-time reasons put a limit on number of fields we search .take(100) + .map(|field_def| { + ( + field_def.ident(self.tcx).normalize_to_macros_2_0(), + field_def.ty(self.tcx, args), + ) + }) + .collect::<Vec<_>>(), + ); + } + ty::Tuple(types) => { + return Some( + types + .iter() + .enumerate() + // For compile-time reasons put a limit on number of fields we search + .take(100) + .map(|(i, ty)| (Ident::from_str(&i.to_string()), ty)) .collect::<Vec<_>>(), - *args, - )); + ); } _ => None, } @@ -3446,9 +3461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn check_for_nested_field_satisfying_condition_for_diag( &self, span: Span, - matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool, - candidate_field: &ty::FieldDef, - subst: GenericArgsRef<'tcx>, + matches: &impl Fn(Ident, Ty<'tcx>) -> bool, + candidate_field: (Ident, Ty<'tcx>), mut field_path: Vec<Ident>, mod_id: DefId, hir_id: HirId, @@ -3463,16 +3477,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // up to a depth of three None } else { - field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0()); - let field_ty = candidate_field.ty(self.tcx, subst); - if matches(candidate_field, field_ty) { + field_path.push(candidate_field.0); + let field_ty = candidate_field.1; + if matches(candidate_field.0, field_ty) { return Some(field_path); } else { - for (nested_fields, subst) in self - .get_field_candidates_considering_privacy_for_diag( - span, field_ty, mod_id, hir_id, - ) - { + for nested_fields in self.get_field_candidates_considering_privacy_for_diag( + span, field_ty, mod_id, hir_id, + ) { // recursively search fields of `candidate_field` if it's a ty::Adt for field in nested_fields { if let Some(field_path) = self @@ -3480,7 +3492,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, matches, field, - subst, field_path.clone(), mod_id, hir_id, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0c0cc752b01..74bfdb5ba01 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2792,7 +2792,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { if let SelfSource::MethodCall(expr) = source { let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); - for (fields, args) in self.get_field_candidates_considering_privacy_for_diag( + for fields in self.get_field_candidates_considering_privacy_for_diag( span, actual, mod_id, @@ -2831,7 +2831,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) }, candidate_field, - args, vec![], mod_id, expr.hir_id, diff --git a/tests/ui/coherence/coherence-tuple-conflict.stderr b/tests/ui/coherence/coherence-tuple-conflict.stderr index 95f9a1a8841..8ce65f79aca 100644 --- a/tests/ui/coherence/coherence-tuple-conflict.stderr +++ b/tests/ui/coherence/coherence-tuple-conflict.stderr @@ -12,6 +12,8 @@ error[E0609]: no field `dummy` on type `&(A, B)` | LL | fn get(&self) -> usize { self.dummy } | ^^^^^ unknown field + | + = note: available fields are: `0`, `1` error: aborting due to 2 previous errors diff --git a/tests/ui/consts/issue-19244-1.stderr b/tests/ui/consts/issue-19244-1.stderr index 9c1336402e6..7d78f954efe 100644 --- a/tests/ui/consts/issue-19244-1.stderr +++ b/tests/ui/consts/issue-19244-1.stderr @@ -3,6 +3,12 @@ error[E0609]: no field `1` on type `(usize,)` | LL | let a: [isize; TUP.1]; | ^ unknown field + | +help: a field with a similar name exists + | +LL - let a: [isize; TUP.1]; +LL + let a: [isize; TUP.0]; + | error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/long-E0609.stderr b/tests/ui/diagnostic-width/long-E0609.stderr index 36ef8545746..70092ea34bc 100644 --- a/tests/ui/diagnostic-width/long-E0609.stderr +++ b/tests/ui/diagnostic-width/long-E0609.stderr @@ -4,6 +4,7 @@ error[E0609]: no field `field` on type `(..., ..., ..., ...)` LL | x.field; | ^^^^^ unknown field | + = note: available fields are: `0`, `1`, `2`, `3` = note: the full name for the type has been written to '$TEST_BUILD_DIR/long-E0609.long-type-$LONG_TYPE_HASH.txt' = note: consider using `--verbose` to print the full type name to the console diff --git a/tests/ui/offset-of/offset-of-tuple-field.stderr b/tests/ui/offset-of/offset-of-tuple-field.stderr index 4da0d851650..e4a5ed09e13 100644 --- a/tests/ui/offset-of/offset-of-tuple-field.stderr +++ b/tests/ui/offset-of/offset-of-tuple-field.stderr @@ -15,60 +15,108 @@ error[E0609]: no field `_0` on type `(u8, u8)` | LL | offset_of!((u8, u8), _0); | ^^ + | +help: a field with a similar name exists + | +LL - offset_of!((u8, u8), _0); +LL + offset_of!((u8, u8), 0); + | error[E0609]: no field `01` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:7:26 | LL | offset_of!((u8, u8), 01); | ^^ + | +help: a field with a similar name exists + | +LL - offset_of!((u8, u8), 01); +LL + offset_of!((u8, u8), 0); + | error[E0609]: no field `1e2` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:8:26 | LL | offset_of!((u8, u8), 1e2); | ^^^ + | + = note: available fields are: `0`, `1` error[E0609]: no field `1_` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:9:26 | LL | offset_of!((u8, u8), 1_u8); | ^^^^ + | +help: a field with a similar name exists + | +LL - offset_of!((u8, u8), 1_u8); +LL + offset_of!((u8, u8), 1); + | error[E0609]: no field `1e2` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:12:35 | LL | builtin # offset_of((u8, u8), 1e2); | ^^^ + | + = note: available fields are: `0`, `1` error[E0609]: no field `_0` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:13:35 | LL | builtin # offset_of((u8, u8), _0); | ^^ + | +help: a field with a similar name exists + | +LL - builtin # offset_of((u8, u8), _0); +LL + builtin # offset_of((u8, u8), 0); + | error[E0609]: no field `01` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:14:35 | LL | builtin # offset_of((u8, u8), 01); | ^^ + | +help: a field with a similar name exists + | +LL - builtin # offset_of((u8, u8), 01); +LL + builtin # offset_of((u8, u8), 0); + | error[E0609]: no field `1_` on type `(u8, u8)` --> $DIR/offset-of-tuple-field.rs:15:35 | LL | builtin # offset_of((u8, u8), 1_u8); | ^^^^ + | +help: a field with a similar name exists + | +LL - builtin # offset_of((u8, u8), 1_u8); +LL + builtin # offset_of((u8, u8), 1); + | error[E0609]: no field `2` on type `(u8, u16)` --> $DIR/offset-of-tuple-field.rs:18:47 | LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2); | ^ + | +help: a field with a similar name exists + | +LL - offset_of!(((u8, u16), (u32, u16, u8)), 0.2); +LL + offset_of!(((u8, u16), (u32, u16, u8)), 0.0); + | error[E0609]: no field `1e2` on type `(u8, u16)` --> $DIR/offset-of-tuple-field.rs:19:47 | LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); | ^^^ + | + = note: available fields are: `0`, `1` error[E0609]: no field `0` on type `u8` --> $DIR/offset-of-tuple-field.rs:21:49 diff --git a/tests/ui/parser/float-field.stderr b/tests/ui/parser/float-field.stderr index 0cc1b0767dc..078d16a4117 100644 --- a/tests/ui/parser/float-field.stderr +++ b/tests/ui/parser/float-field.stderr @@ -305,6 +305,8 @@ error[E0609]: no field `1e1` on type `(u8, u8)` | LL | { s.1.1e1; } | ^^^ unknown field + | + = note: available fields are: `0`, `1` error[E0609]: no field `0x1e1` on type `S` --> $DIR/float-field.rs:34:9 @@ -343,12 +345,16 @@ error[E0609]: no field `f32` on type `(u8, u8)` | LL | { s.1.f32; } | ^^^ unknown field + | + = note: available fields are: `0`, `1` error[E0609]: no field `1e1` on type `(u8, u8)` --> $DIR/float-field.rs:71:9 | LL | { s.1.1e1f32; } | ^^^^^^^^ unknown field + | + = note: available fields are: `0`, `1` error: aborting due to 57 previous errors diff --git a/tests/ui/traits/well-formed-recursion-limit.stderr b/tests/ui/traits/well-formed-recursion-limit.stderr index e0270ecabbd..a4c85c4fcbd 100644 --- a/tests/ui/traits/well-formed-recursion-limit.stderr +++ b/tests/ui/traits/well-formed-recursion-limit.stderr @@ -3,12 +3,16 @@ error[E0609]: no field `ab` on type `(Box<(dyn Fn(Option<A>) -> Option<B> + 'sta | LL | let (ab, ba) = (i.ab, i.ba); | ^^ unknown field + | + = note: available fields are: `0`, `1` error[E0609]: no field `ba` on type `(Box<(dyn Fn(Option<A>) -> Option<B> + 'static)>, Box<(dyn Fn(Option<B>) -> Option<A> + 'static)>)` --> $DIR/well-formed-recursion-limit.rs:12:29 | LL | let (ab, ba) = (i.ab, i.ba); | ^^ unknown field + | + = note: available fields are: `0`, `1` error[E0275]: overflow assigning `_` to `Option<_>` --> $DIR/well-formed-recursion-limit.rs:15:33 diff --git a/tests/ui/tuple/index-invalid.stderr b/tests/ui/tuple/index-invalid.stderr index ae2c275f52c..acc4134d1a6 100644 --- a/tests/ui/tuple/index-invalid.stderr +++ b/tests/ui/tuple/index-invalid.stderr @@ -3,18 +3,32 @@ error[E0609]: no field `1` on type `(((),),)` | LL | let _ = (((),),).1.0; | ^ unknown field + | +help: a field with a similar name exists + | +LL - let _ = (((),),).1.0; +LL + let _ = (((),),).0.0; + | error[E0609]: no field `1` on type `((),)` --> $DIR/index-invalid.rs:4:24 | LL | let _ = (((),),).0.1; | ^ unknown field + | +help: a field with a similar name exists + | +LL - let _ = (((),),).0.1; +LL + let _ = (((),),).0.0; + | error[E0609]: no field `000` on type `(((),),)` --> $DIR/index-invalid.rs:6:22 | LL | let _ = (((),),).000.000; | ^^^ unknown field + | + = note: available field is: `0` error: aborting due to 3 previous errors diff --git a/tests/ui/tuple/missing-field-access.rs b/tests/ui/tuple/missing-field-access.rs new file mode 100644 index 00000000000..4ccd759ccd2 --- /dev/null +++ b/tests/ui/tuple/missing-field-access.rs @@ -0,0 +1,17 @@ +use std::{fs::File, io::BufReader}; + +struct F(BufReader<File>); + +fn main() { + let f = F(BufReader::new(File::open("x").unwrap())); + let x = f.get_ref(); //~ ERROR E0599 + //~^ HELP one of the expressions' fields has a method of the same name + //~| HELP consider pinning the expression + let f = (BufReader::new(File::open("x").unwrap()), ); + let x = f.get_ref(); //~ ERROR E0599 + //~^ HELP one of the expressions' fields has a method of the same name + //~| HELP consider pinning the expression + + // FIXME(estebank): the pinning suggestion should not be included in either case. + // https://github.com/rust-lang/rust/issues/144602 +} diff --git a/tests/ui/tuple/missing-field-access.stderr b/tests/ui/tuple/missing-field-access.stderr new file mode 100644 index 00000000000..711a8906d62 --- /dev/null +++ b/tests/ui/tuple/missing-field-access.stderr @@ -0,0 +1,38 @@ +error[E0599]: no method named `get_ref` found for struct `F` in the current scope + --> $DIR/missing-field-access.rs:7:15 + | +LL | struct F(BufReader<File>); + | -------- method `get_ref` not found for this struct +... +LL | let x = f.get_ref(); + | ^^^^^^^ method not found in `F` + | +help: one of the expressions' fields has a method of the same name + | +LL | let x = f.0.get_ref(); + | ++ +help: consider pinning the expression + | +LL ~ let mut pinned = std::pin::pin!(f); +LL ~ let x = pinned.as_ref().get_ref(); + | + +error[E0599]: no method named `get_ref` found for tuple `(BufReader<File>,)` in the current scope + --> $DIR/missing-field-access.rs:11:15 + | +LL | let x = f.get_ref(); + | ^^^^^^^ method not found in `(BufReader<File>,)` + | +help: one of the expressions' fields has a method of the same name + | +LL | let x = f.0.get_ref(); + | ++ +help: consider pinning the expression + | +LL ~ let mut pinned = std::pin::pin!(f); +LL ~ let x = pinned.as_ref().get_ref(); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/tuple/tuple-index-out-of-bounds.stderr b/tests/ui/tuple/tuple-index-out-of-bounds.stderr index 8b3c835c3e3..72827690909 100644 --- a/tests/ui/tuple/tuple-index-out-of-bounds.stderr +++ b/tests/ui/tuple/tuple-index-out-of-bounds.stderr @@ -15,6 +15,12 @@ error[E0609]: no field `2` on type `({integer}, {integer})` | LL | tuple.2; | ^ unknown field + | +help: a field with a similar name exists + | +LL - tuple.2; +LL + tuple.0; + | error: aborting due to 2 previous errors |
