diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index eaf5e938d3c..b95c673f3ba 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2471,9 +2471,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::RawPtr(..) => { self.suggest_first_deref_field(&mut err, expr, base, ident); } - ty::Adt(def, _) if !def.is_enum() => { - self.suggest_fields_on_recordish(&mut err, expr, def, ident); - } ty::Param(param_ty) => { self.point_at_param_definition(&mut err, param_ty); } @@ -2633,34 +2630,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(param_span, format!("type parameter '{param_name}' declared here")); } - fn suggest_fields_on_recordish( - &self, - err: &mut Diagnostic, - expr: &hir::Expr<'_>, - def: ty::AdtDef<'tcx>, - field: Ident, - ) { - let available_field_names = self.available_field_names(def.non_enum_variant(), expr, &[]); - if let Some(suggested_field_name) = - find_best_match_for_name(&available_field_names, field.name, None) - { - err.span_suggestion( - field.span, - "a field with a similar name exists", - suggested_field_name, - Applicability::MaybeIncorrect, - ); - } else { - err.span_label(field.span, "unknown field"); - if !available_field_names.is_empty() { - err.note(format!( - "available fields are: {}", - self.name_series_display(available_field_names), - )); - } - } - } - fn maybe_suggest_array_indexing( &self, err: &mut Diagnostic, @@ -2709,7 +2678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = type_error_struct!( self.tcx().sess, - field.span, + span, expr_t, E0609, "no field `{field}` on type `{expr_t}`", @@ -2717,10 +2686,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // try to add a suggestion in case the field is a nested field of a field of the Adt let mod_id = self.tcx.parent_module(id).to_def_id(); - if let Some((fields, args)) = - self.get_field_candidates_considering_privacy(span, expr_t, mod_id) + for (found_fields, args) in + self.get_field_candidates_considering_privacy(span, expr_t, mod_id, id) { - let candidate_fields: Vec<_> = fields + let field_names = found_fields.iter().map(|field| field.name).collect::>(); + let candidate_fields: Vec<_> = found_fields + .into_iter() .filter_map(|candidate_field| { self.check_for_nested_field_satisfying( span, @@ -2729,6 +2700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args, vec![], mod_id, + id, ) }) .map(|mut field_path| { @@ -2753,6 +2725,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_fields.iter().map(|path| format!("{path}.")), Applicability::MaybeIncorrect, ); + } else { + if let Some(field_name) = find_best_match_for_name(&field_names, field.name, None) { + err.span_suggestion( + field.span, + "a field with a similar name exists", + field_name, + Applicability::MaybeIncorrect, + ); + } else if !field_names.is_empty() { + let is = if field_names.len() == 1 { " is" } else { "s are" }; + err.note(format!( + "available field{is}: {}", + self.name_series_display(field_names), + )); + } } } err @@ -2781,33 +2768,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, base_ty: Ty<'tcx>, mod_id: DefId, - ) -> Option<(impl Iterator + 'tcx, GenericArgsRef<'tcx>)> { + hir_id: hir::HirId, + ) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> { debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); - for (base_t, _) in self.autoderef(span, base_ty) { - match base_t.kind() { - ty::Adt(base_def, args) if !base_def.is_enum() => { - let tcx = self.tcx; - let fields = &base_def.non_enum_variant().fields; - // Some struct, e.g. some that impl `Deref`, have all private fields - // because you're expected to deref them to access the _real_ fields. - // This, for example, will help us suggest accessing a field through a `Box`. - if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) { - continue; + self.autoderef(span, base_ty) + .filter_map(move |(base_t, _)| { + match base_t.kind() { + ty::Adt(base_def, args) if !base_def.is_enum() => { + let tcx = self.tcx; + let fields = &base_def.non_enum_variant().fields; + // Some struct, e.g. some that impl `Deref`, have all private fields + // because you're expected to deref them to access the _real_ fields. + // This, for example, will help us suggest accessing a field through a `Box`. + if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) { + return None; + } + return Some(( + fields + .iter() + .filter(move |field| { + field.vis.is_accessible_from(mod_id, tcx) + && self.is_field_suggestable(field, hir_id, span) + }) + // For compile-time reasons put a limit on number of fields we search + .take(100) + .collect::>(), + *args, + )); } - return Some(( - fields - .iter() - .filter(move |field| field.vis.is_accessible_from(mod_id, tcx)) - // For compile-time reasons put a limit on number of fields we search - .take(100), - args, - )); + _ => None, } - _ => {} - } - } - None + }) + .collect() } /// This method is called after we have encountered a missing field error to recursively @@ -2820,6 +2813,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subst: GenericArgsRef<'tcx>, mut field_path: Vec, mod_id: DefId, + hir_id: HirId, ) -> Option> { debug!( "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}", @@ -2835,20 +2829,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_ty = candidate_field.ty(self.tcx, subst); if matches(candidate_field, field_ty) { return Some(field_path); - } else if let Some((nested_fields, subst)) = - self.get_field_candidates_considering_privacy(span, field_ty, mod_id) - { - // recursively search fields of `candidate_field` if it's a ty::Adt - for field in nested_fields { - if let Some(field_path) = self.check_for_nested_field_satisfying( - span, - matches, - field, - subst, - field_path.clone(), - mod_id, - ) { - return Some(field_path); + } else { + for (nested_fields, subst) in + self.get_field_candidates_considering_privacy(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.check_for_nested_field_satisfying( + span, + matches, + field, + subst, + field_path.clone(), + mod_id, + hir_id, + ) { + return Some(field_path); + } } } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 3624b86b575..8dc3927ce33 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1983,69 +1983,72 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: Ident, return_type: Option>, ) { - if let SelfSource::MethodCall(expr) = source - && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id() - && let Some((fields, args)) = - self.get_field_candidates_considering_privacy(span, actual, mod_id) - { - let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)); + 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(span, actual, mod_id, expr.hir_id) + { + let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)); - let lang_items = self.tcx.lang_items(); - let never_mention_traits = [ - lang_items.clone_trait(), - lang_items.deref_trait(), - lang_items.deref_mut_trait(), - self.tcx.get_diagnostic_item(sym::AsRef), - self.tcx.get_diagnostic_item(sym::AsMut), - self.tcx.get_diagnostic_item(sym::Borrow), - self.tcx.get_diagnostic_item(sym::BorrowMut), - ]; - let candidate_fields: Vec<_> = fields - .filter_map(|candidate_field| { - self.check_for_nested_field_satisfying( - span, - &|_, field_ty| { - self.lookup_probe_for_diagnostic( - item_name, - field_ty, - call_expr, - ProbeScope::TraitsInScope, - return_type, - ) - .is_ok_and(|pick| { - !never_mention_traits - .iter() - .flatten() - .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id) - }) - }, - candidate_field, - args, - vec![], - mod_id, - ) - }) - .map(|field_path| { - field_path - .iter() - .map(|id| id.name.to_ident_string()) - .collect::>() - .join(".") - }) - .collect(); + let lang_items = self.tcx.lang_items(); + let never_mention_traits = [ + lang_items.clone_trait(), + lang_items.deref_trait(), + lang_items.deref_mut_trait(), + self.tcx.get_diagnostic_item(sym::AsRef), + self.tcx.get_diagnostic_item(sym::AsMut), + self.tcx.get_diagnostic_item(sym::Borrow), + self.tcx.get_diagnostic_item(sym::BorrowMut), + ]; + let candidate_fields: Vec<_> = fields + .iter() + .filter_map(|candidate_field| { + self.check_for_nested_field_satisfying( + span, + &|_, field_ty| { + self.lookup_probe_for_diagnostic( + item_name, + field_ty, + call_expr, + ProbeScope::TraitsInScope, + return_type, + ) + .is_ok_and(|pick| { + !never_mention_traits + .iter() + .flatten() + .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id) + }) + }, + candidate_field, + args, + vec![], + mod_id, + expr.hir_id, + ) + }) + .map(|field_path| { + field_path + .iter() + .map(|id| id.name.to_ident_string()) + .collect::>() + .join(".") + }) + .collect(); - let len = candidate_fields.len(); - if len > 0 { - err.span_suggestions( - item_name.span.shrink_to_lo(), - format!( - "{} of the expressions' fields {} a method of the same name", - if len > 1 { "some" } else { "one" }, - if len > 1 { "have" } else { "has" }, - ), - candidate_fields.iter().map(|path| format!("{path}.")), - Applicability::MaybeIncorrect, - ); + let len = candidate_fields.len(); + if len > 0 { + err.span_suggestions( + item_name.span.shrink_to_lo(), + format!( + "{} of the expressions' fields {} a method of the same name", + if len > 1 { "some" } else { "one" }, + if len > 1 { "have" } else { "has" }, + ), + candidate_fields.iter().map(|path| format!("{path}.")), + Applicability::MaybeIncorrect, + ); + } } } } diff --git a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs index 4919e0a051d..051e6afd7a7 100644 --- a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs +++ b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs @@ -10,7 +10,6 @@ fn await_on_struct_missing() { let x = S; x.await; //~^ ERROR no field `await` on type - //~| NOTE unknown field //~| NOTE to `.await` a `Future`, switch to Rust 2018 //~| HELP set `edition = "2021"` in `Cargo.toml` //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide @@ -32,7 +31,6 @@ fn await_on_struct_similar() { fn await_on_63533(x: Pin<&mut dyn Future>) { x.await; //~^ ERROR no field `await` on type - //~| NOTE unknown field //~| NOTE to `.await` a `Future`, switch to Rust 2018 //~| HELP set `edition = "2021"` in `Cargo.toml` //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide diff --git a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr index 409eb179e83..1b0912310e8 100644 --- a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr +++ b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr @@ -2,14 +2,14 @@ error[E0609]: no field `await` on type `await_on_struct_missing::S` --> $DIR/suggest-switching-edition-on-await-cargo.rs:11:7 | LL | x.await; - | ^^^^^ unknown field + | ^^^^^ | = note: to `.await` a `Future`, switch to Rust 2018 or later = help: set `edition = "2021"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0609]: no field `await` on type `await_on_struct_similar::S` - --> $DIR/suggest-switching-edition-on-await-cargo.rs:24:7 + --> $DIR/suggest-switching-edition-on-await-cargo.rs:23:7 | LL | x.await; | ^^^^^ help: a field with a similar name exists: `awai` @@ -19,17 +19,17 @@ LL | x.await; = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0609]: no field `await` on type `Pin<&mut dyn Future>` - --> $DIR/suggest-switching-edition-on-await-cargo.rs:33:7 + --> $DIR/suggest-switching-edition-on-await-cargo.rs:32:7 | LL | x.await; - | ^^^^^ unknown field + | ^^^^^ | = note: to `.await` a `Future`, switch to Rust 2018 or later = help: set `edition = "2021"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0609]: no field `await` on type `impl Future` - --> $DIR/suggest-switching-edition-on-await-cargo.rs:42:7 + --> $DIR/suggest-switching-edition-on-await-cargo.rs:40:7 | LL | x.await; | ^^^^^ diff --git a/tests/ui/async-await/suggest-switching-edition-on-await.rs b/tests/ui/async-await/suggest-switching-edition-on-await.rs index 9852e8fc918..4b62713d1b2 100644 --- a/tests/ui/async-await/suggest-switching-edition-on-await.rs +++ b/tests/ui/async-await/suggest-switching-edition-on-await.rs @@ -8,7 +8,6 @@ fn await_on_struct_missing() { let x = S; x.await; //~^ ERROR no field `await` on type - //~| NOTE unknown field //~| NOTE to `.await` a `Future`, switch to Rust 2018 //~| HELP pass `--edition 2021` to `rustc` //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide @@ -30,7 +29,6 @@ fn await_on_struct_similar() { fn await_on_63533(x: Pin<&mut dyn Future>) { x.await; //~^ ERROR no field `await` on type - //~| NOTE unknown field //~| NOTE to `.await` a `Future`, switch to Rust 2018 //~| HELP pass `--edition 2021` to `rustc` //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide diff --git a/tests/ui/async-await/suggest-switching-edition-on-await.stderr b/tests/ui/async-await/suggest-switching-edition-on-await.stderr index ef3334381b7..ddc44562d2c 100644 --- a/tests/ui/async-await/suggest-switching-edition-on-await.stderr +++ b/tests/ui/async-await/suggest-switching-edition-on-await.stderr @@ -2,14 +2,14 @@ error[E0609]: no field `await` on type `await_on_struct_missing::S` --> $DIR/suggest-switching-edition-on-await.rs:9:7 | LL | x.await; - | ^^^^^ unknown field + | ^^^^^ | = note: to `.await` a `Future`, switch to Rust 2018 or later = help: pass `--edition 2021` to `rustc` = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0609]: no field `await` on type `await_on_struct_similar::S` - --> $DIR/suggest-switching-edition-on-await.rs:22:7 + --> $DIR/suggest-switching-edition-on-await.rs:21:7 | LL | x.await; | ^^^^^ help: a field with a similar name exists: `awai` @@ -19,17 +19,17 @@ LL | x.await; = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0609]: no field `await` on type `Pin<&mut dyn Future>` - --> $DIR/suggest-switching-edition-on-await.rs:31:7 + --> $DIR/suggest-switching-edition-on-await.rs:30:7 | LL | x.await; - | ^^^^^ unknown field + | ^^^^^ | = note: to `.await` a `Future`, switch to Rust 2018 or later = help: pass `--edition 2021` to `rustc` = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0609]: no field `await` on type `impl Future` - --> $DIR/suggest-switching-edition-on-await.rs:40:7 + --> $DIR/suggest-switching-edition-on-await.rs:38:7 | LL | x.await; | ^^^^^ diff --git a/tests/ui/did_you_mean/dont-suggest-doc-hidden-fields.rs b/tests/ui/did_you_mean/dont-suggest-doc-hidden-fields.rs index 6040f3f30a7..36a7066e72e 100644 --- a/tests/ui/did_you_mean/dont-suggest-doc-hidden-fields.rs +++ b/tests/ui/did_you_mean/dont-suggest-doc-hidden-fields.rs @@ -21,18 +21,15 @@ fn main() { // `doc(hidden)` because it's defined in this crate. A::default().hey; //~^ ERROR no field `hey` on type `A` - //~| NOTE unknown field //~| NOTE available fields are: `hello`, `bye` // Here we want to hide the field `hello` since it's marked // `doc(hidden)` and comes from an external crate. doc_hidden_fields::B::default().hey; //~^ ERROR no field `hey` on type `B` - //~| NOTE unknown field - //~| NOTE available fields are: `bye` + //~| NOTE available field is: `bye` C::default().hey; //~^ ERROR no field `hey` on type `C` - //~| NOTE unknown field //~| NOTE available fields are: `hello`, `bye` } diff --git a/tests/ui/did_you_mean/dont-suggest-doc-hidden-fields.stderr b/tests/ui/did_you_mean/dont-suggest-doc-hidden-fields.stderr index b7fe3b79b47..abded80066a 100644 --- a/tests/ui/did_you_mean/dont-suggest-doc-hidden-fields.stderr +++ b/tests/ui/did_you_mean/dont-suggest-doc-hidden-fields.stderr @@ -2,23 +2,23 @@ error[E0609]: no field `hey` on type `A` --> $DIR/dont-suggest-doc-hidden-fields.rs:22:18 | LL | A::default().hey; - | ^^^ unknown field + | ^^^ | = note: available fields are: `hello`, `bye` error[E0609]: no field `hey` on type `B` - --> $DIR/dont-suggest-doc-hidden-fields.rs:29:37 + --> $DIR/dont-suggest-doc-hidden-fields.rs:28:37 | LL | doc_hidden_fields::B::default().hey; - | ^^^ unknown field + | ^^^ | - = note: available fields are: `bye` + = note: available field is: `bye` error[E0609]: no field `hey` on type `C` - --> $DIR/dont-suggest-doc-hidden-fields.rs:34:18 + --> $DIR/dont-suggest-doc-hidden-fields.rs:32:18 | LL | C::default().hey; - | ^^^ unknown field + | ^^^ | = note: available fields are: `hello`, `bye` diff --git a/tests/ui/did_you_mean/dont-suggest-hygienic-fields.stderr b/tests/ui/did_you_mean/dont-suggest-hygienic-fields.stderr index 7066d29760e..414590873da 100644 --- a/tests/ui/did_you_mean/dont-suggest-hygienic-fields.stderr +++ b/tests/ui/did_you_mean/dont-suggest-hygienic-fields.stderr @@ -13,13 +13,13 @@ error[E0609]: no field `field` on type `Compound` --> $DIR/dont-suggest-hygienic-fields.rs:24:16 | LL | let _ = ty.field; - | ^^^^^ unknown field + | ^^^^^ error[E0609]: no field `fieeld` on type `Compound` --> $DIR/dont-suggest-hygienic-fields.rs:25:16 | LL | let _ = ty.fieeld; - | ^^^^^^ unknown field + | ^^^^^^ error[E0026]: struct `Compound` does not have a field named `field` --> $DIR/dont-suggest-hygienic-fields.rs:27:20 @@ -42,7 +42,7 @@ error[E0609]: no field `0` on type `Component` --> $DIR/dont-suggest-hygienic-fields.rs:34:16 | LL | let _ = ty.0; - | ^ unknown field + | ^ error: aborting due to 6 previous errors diff --git a/tests/ui/did_you_mean/issue-36798_unknown_field.stderr b/tests/ui/did_you_mean/issue-36798_unknown_field.stderr index 2ed0a092400..4854a9bdeb8 100644 --- a/tests/ui/did_you_mean/issue-36798_unknown_field.stderr +++ b/tests/ui/did_you_mean/issue-36798_unknown_field.stderr @@ -2,9 +2,9 @@ error[E0609]: no field `zz` on type `Foo` --> $DIR/issue-36798_unknown_field.rs:7:7 | LL | f.zz; - | ^^ unknown field + | ^^ | - = note: available fields are: `bar` + = note: available field is: `bar` error: aborting due to previous error diff --git a/tests/ui/did_you_mean/issue-42599_available_fields_note.stderr b/tests/ui/did_you_mean/issue-42599_available_fields_note.stderr index c20bbce3f24..a4c3512eb41 100644 --- a/tests/ui/did_you_mean/issue-42599_available_fields_note.stderr +++ b/tests/ui/did_you_mean/issue-42599_available_fields_note.stderr @@ -22,7 +22,7 @@ error[E0609]: no field `egregiously_nonexistent_field` on type `Demo` --> $DIR/issue-42599_available_fields_note.rs:35:42 | LL | let egregious_field_misaccess = demo.egregiously_nonexistent_field; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown field + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: available fields are: `favorite_integer`, `innocently_misspellable` diff --git a/tests/ui/error-codes/E0609-private-method.stderr b/tests/ui/error-codes/E0609-private-method.stderr index d2a11e90627..a2bfcca5e0b 100644 --- a/tests/ui/error-codes/E0609-private-method.stderr +++ b/tests/ui/error-codes/E0609-private-method.stderr @@ -2,7 +2,7 @@ error[E0609]: no field `method` on type `Foo` --> $DIR/E0609-private-method.rs:15:7 | LL | f.method; - | ^^^^^^ unknown field + | ^^^^^^ error: aborting due to previous error diff --git a/tests/ui/error-codes/E0609.stderr b/tests/ui/error-codes/E0609.stderr index 797e95d02dd..78a61b92c5c 100644 --- a/tests/ui/error-codes/E0609.stderr +++ b/tests/ui/error-codes/E0609.stderr @@ -2,15 +2,15 @@ error[E0609]: no field `foo` on type `Foo` --> $DIR/E0609.rs:8:15 | LL | let _ = x.foo; - | ^^^ unknown field + | ^^^ | - = note: available fields are: `x` + = note: available field is: `x` error[E0609]: no field `1` on type `Bar` --> $DIR/E0609.rs:11:7 | LL | y.1; - | ^ unknown field + | ^ error: aborting due to 2 previous errors diff --git a/tests/ui/infinite/infinite-autoderef.stderr b/tests/ui/infinite/infinite-autoderef.stderr index 51b61e3a66b..1fa53beba68 100644 --- a/tests/ui/infinite/infinite-autoderef.stderr +++ b/tests/ui/infinite/infinite-autoderef.stderr @@ -29,7 +29,7 @@ error[E0609]: no field `foo` on type `Foo` --> $DIR/infinite-autoderef.rs:24:9 | LL | Foo.foo; - | ^^^ unknown field + | ^^^ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` --> $DIR/infinite-autoderef.rs:25:9 diff --git a/tests/ui/issues/issue-19244-2.stderr b/tests/ui/issues/issue-19244-2.stderr index 54529fdf5ba..933371d1e89 100644 --- a/tests/ui/issues/issue-19244-2.stderr +++ b/tests/ui/issues/issue-19244-2.stderr @@ -2,9 +2,9 @@ error[E0609]: no field `nonexistent_field` on type `MyStruct` --> $DIR/issue-19244-2.rs:5:27 | LL | let a: [isize; STRUCT.nonexistent_field]; - | ^^^^^^^^^^^^^^^^^ unknown field + | ^^^^^^^^^^^^^^^^^ | - = note: available fields are: `field` + = note: available field is: `field` error: aborting due to previous error diff --git a/tests/ui/issues/issue-47073-zero-padded-tuple-struct-indices.stderr b/tests/ui/issues/issue-47073-zero-padded-tuple-struct-indices.stderr index 5e1b816defd..193c5aaf72d 100644 --- a/tests/ui/issues/issue-47073-zero-padded-tuple-struct-indices.stderr +++ b/tests/ui/issues/issue-47073-zero-padded-tuple-struct-indices.stderr @@ -8,7 +8,7 @@ error[E0609]: no field `001` on type `Verdict` --> $DIR/issue-47073-zero-padded-tuple-struct-indices.rs:10:31 | LL | let _punishment = justice.001; - | ^^^ unknown field + | ^^^ | = note: available fields are: `0`, `1` diff --git a/tests/ui/offset-of/offset-of-self.stderr b/tests/ui/offset-of/offset-of-self.stderr index df555463f98..2dc17189a70 100644 --- a/tests/ui/offset-of/offset-of-self.stderr +++ b/tests/ui/offset-of/offset-of-self.stderr @@ -54,6 +54,8 @@ error[E0609]: no field `Self` on type `S` | LL | offset_of!(S, Self); | ^^^^ + | + = note: available fields are: `v`, `w` error[E0616]: field `v` of struct `T` is private --> $DIR/offset-of-self.rs:41:30 @@ -66,6 +68,8 @@ error[E0609]: no field `self` on type `S` | LL | offset_of!(S, self); | ^^^^ + | + = note: available fields are: `v`, `w` error[E0609]: no field `self` on type `u8` --> $DIR/offset-of-self.rs:56:21 diff --git a/tests/ui/parser/float-field.stderr b/tests/ui/parser/float-field.stderr index 7090efc5014..a81992c3380 100644 --- a/tests/ui/parser/float-field.stderr +++ b/tests/ui/parser/float-field.stderr @@ -266,7 +266,7 @@ error[E0609]: no field `1e1` on type `S` --> $DIR/float-field.rs:6:7 | LL | s.1e1; - | ^^^ unknown field + | ^^^ | = note: available fields are: `0`, `1` @@ -280,7 +280,7 @@ error[E0609]: no field `0x1e1` on type `S` --> $DIR/float-field.rs:24:7 | LL | s.0x1e1; - | ^^^^^ unknown field + | ^^^^^ | = note: available fields are: `0`, `1` @@ -288,7 +288,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:25:7 | LL | s.0x1.; - | ^^^ unknown field + | ^^^ | = note: available fields are: `0`, `1` @@ -296,7 +296,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:28:7 | LL | s.0x1.1; - | ^^^ unknown field + | ^^^ | = note: available fields are: `0`, `1` @@ -304,7 +304,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:30:7 | LL | s.0x1.1e1; - | ^^^ unknown field + | ^^^ | = note: available fields are: `0`, `1` @@ -312,7 +312,7 @@ error[E0609]: no field `0x1e` on type `S` --> $DIR/float-field.rs:34:7 | LL | s.0x1e+1; - | ^^^^ unknown field + | ^^^^ | = note: available fields are: `0`, `1` @@ -320,7 +320,7 @@ error[E0609]: no field `0x1e` on type `S` --> $DIR/float-field.rs:35:7 | LL | s.0x1e-1; - | ^^^^ unknown field + | ^^^^ | = note: available fields are: `0`, `1` @@ -328,7 +328,7 @@ error[E0609]: no field `1e1` on type `S` --> $DIR/float-field.rs:42:7 | LL | s.1e1f32; - | ^^^^^^ unknown field + | ^^^^^^ | = note: available fields are: `0`, `1` diff --git a/tests/ui/suggestions/call-on-missing.stderr b/tests/ui/suggestions/call-on-missing.stderr index ca9abc7e906..2824343c913 100644 --- a/tests/ui/suggestions/call-on-missing.stderr +++ b/tests/ui/suggestions/call-on-missing.stderr @@ -35,7 +35,7 @@ error[E0609]: no field `i` on type `Box Foo>` --> $DIR/call-on-missing.rs:26:14 | LL | callable.i; - | ^ unknown field + | ^ | help: use parentheses to call this trait object | diff --git a/tests/ui/suggestions/field-access-considering-privacy.stderr b/tests/ui/suggestions/field-access-considering-privacy.stderr index cbf6f3d1002..5bbcfeea474 100644 --- a/tests/ui/suggestions/field-access-considering-privacy.stderr +++ b/tests/ui/suggestions/field-access-considering-privacy.stderr @@ -2,7 +2,7 @@ error[E0609]: no field `opts` on type `TyCtxt<'tcx>` --> $DIR/field-access-considering-privacy.rs:29:13 | LL | tcx.opts; - | ^^^^ unknown field + | ^^^^ | help: one of the expressions' fields has a field of the same name | diff --git a/tests/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr b/tests/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr index b294f4da7db..f4010b39dc4 100644 --- a/tests/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr +++ b/tests/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.stderr @@ -2,7 +2,7 @@ error[E0609]: no field `f` on type `Foo` --> $DIR/non-existent-field-present-in-subfield-recursion-limit.rs:41:22 | LL | let test = fooer.f; - | ^ unknown field + | ^ | = note: available fields are: `first`, `second`, `third` diff --git a/tests/ui/suggestions/non-existent-field-present-in-subfield.stderr b/tests/ui/suggestions/non-existent-field-present-in-subfield.stderr index cc991b915d3..c3e40145038 100644 --- a/tests/ui/suggestions/non-existent-field-present-in-subfield.stderr +++ b/tests/ui/suggestions/non-existent-field-present-in-subfield.stderr @@ -2,9 +2,8 @@ error[E0609]: no field `c` on type `Foo` --> $DIR/non-existent-field-present-in-subfield.rs:37:24 | LL | let _test = &fooer.c; - | ^ unknown field + | ^ | - = note: available fields are: `first`, `_second`, `_third` help: one of the expressions' fields has a field of the same name | LL | let _test = &fooer.first.bar.c; @@ -14,9 +13,8 @@ error[E0609]: no field `test` on type `Foo` --> $DIR/non-existent-field-present-in-subfield.rs:40:24 | LL | let _test2 = fooer.test; - | ^^^^ unknown field + | ^^^^ | - = note: available fields are: `first`, `_second`, `_third` help: one of the expressions' fields has a field of the same name | LL | let _test2 = fooer.first.bar.c.test; diff --git a/tests/ui/suggestions/private-field.stderr b/tests/ui/suggestions/private-field.stderr index c38c795e07a..6a735a163b8 100644 --- a/tests/ui/suggestions/private-field.stderr +++ b/tests/ui/suggestions/private-field.stderr @@ -2,9 +2,9 @@ error[E0609]: no field `cap` on type `S` --> $DIR/private-field.rs:7:12 | LL | dbg!(s.cap) - | ^^^ unknown field + | ^^^ | - = note: available fields are: `val` + = note: available field is: `val` error: aborting due to previous error diff --git a/tests/ui/suggestions/suggest-field-through-deref.fixed b/tests/ui/suggestions/suggest-field-through-deref.fixed new file mode 100644 index 00000000000..a0f20e563f3 --- /dev/null +++ b/tests/ui/suggestions/suggest-field-through-deref.fixed @@ -0,0 +1,13 @@ +// run-rustfix +#![allow(dead_code)] +use std::sync::Arc; +struct S { + long_name: (), + foo: (), +} +fn main() { + let x = Arc::new(S { long_name: (), foo: () }); + let _ = x.long_name; //~ ERROR no field `longname` + let y = S { long_name: (), foo: () }; + let _ = y.long_name; //~ ERROR no field `longname` +} diff --git a/tests/ui/suggestions/suggest-field-through-deref.rs b/tests/ui/suggestions/suggest-field-through-deref.rs new file mode 100644 index 00000000000..729e5db0552 --- /dev/null +++ b/tests/ui/suggestions/suggest-field-through-deref.rs @@ -0,0 +1,13 @@ +// run-rustfix +#![allow(dead_code)] +use std::sync::Arc; +struct S { + long_name: (), + foo: (), +} +fn main() { + let x = Arc::new(S { long_name: (), foo: () }); + let _ = x.longname; //~ ERROR no field `longname` + let y = S { long_name: (), foo: () }; + let _ = y.longname; //~ ERROR no field `longname` +} diff --git a/tests/ui/suggestions/suggest-field-through-deref.stderr b/tests/ui/suggestions/suggest-field-through-deref.stderr new file mode 100644 index 00000000000..649e28be51d --- /dev/null +++ b/tests/ui/suggestions/suggest-field-through-deref.stderr @@ -0,0 +1,15 @@ +error[E0609]: no field `longname` on type `Arc` + --> $DIR/suggest-field-through-deref.rs:10:15 + | +LL | let _ = x.longname; + | ^^^^^^^^ help: a field with a similar name exists: `long_name` + +error[E0609]: no field `longname` on type `S` + --> $DIR/suggest-field-through-deref.rs:12:15 + | +LL | let _ = y.longname; + | ^^^^^^^^ help: a field with a similar name exists: `long_name` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0609`. diff --git a/tests/ui/suggestions/too-many-field-suggestions.stderr b/tests/ui/suggestions/too-many-field-suggestions.stderr index 63ad6fdb169..b556bdda3f6 100644 --- a/tests/ui/suggestions/too-many-field-suggestions.stderr +++ b/tests/ui/suggestions/too-many-field-suggestions.stderr @@ -23,9 +23,8 @@ error[E0609]: no field `field` on type `Thing` --> $DIR/too-many-field-suggestions.rs:26:7 | LL | t.field; - | ^^^^^ unknown field + | ^^^^^ | - = note: available fields are: `a0`, `a1`, `a2`, `a3`, `a4` ... and 5 others help: some of the expressions' fields have a field of the same name | LL | t.a0.field; diff --git a/tests/ui/tuple/tuple-index-not-tuple.stderr b/tests/ui/tuple/tuple-index-not-tuple.stderr index a1bcdfaedbc..cc94a61ae7f 100644 --- a/tests/ui/tuple/tuple-index-not-tuple.stderr +++ b/tests/ui/tuple/tuple-index-not-tuple.stderr @@ -8,7 +8,7 @@ error[E0609]: no field `0` on type `Empty` --> $DIR/tuple-index-not-tuple.rs:8:11 | LL | Empty.0; - | ^ unknown field + | ^ error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/issue-67971.stderr b/tests/ui/typeck/issue-67971.stderr index d50ed9cf13b..4ae0f5d1c5c 100644 --- a/tests/ui/typeck/issue-67971.stderr +++ b/tests/ui/typeck/issue-67971.stderr @@ -2,7 +2,7 @@ error[E0609]: no field `sleep` on type `&mut S` --> $DIR/issue-67971.rs:5:9 | LL | ctx.sleep = 0; - | ^^^^^ unknown field + | ^^^^^ error[E0308]: mismatched types --> $DIR/issue-67971.rs:3:24