From 9cf570995cded5e224d5dba8296a85fdbe1c6918 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 3 Aug 2022 06:28:45 +0000 Subject: [PATCH 1/4] Suggest expressions' fields even if they're not ADTs --- compiler/rustc_typeck/src/check/expr.rs | 12 ++++++------ src/test/ui/copy-a-resource.stderr | 4 ++++ src/test/ui/issues/issue-2823.stderr | 4 ++++ src/test/ui/issues/issue-31173.stderr | 4 ++++ src/test/ui/issues/issue-39175.stderr | 4 ++++ src/test/ui/mismatched_types/issue-36053-2.stderr | 4 ++++ src/test/ui/noncopyable-class.stderr | 8 ++++++++ .../suggestions/import-trait-for-method-call.stderr | 4 ++++ .../ui/suggestions/mut-borrow-needed-by-trait.stderr | 10 ++++++++++ src/test/ui/suggestions/suggest-using-chars.stderr | 8 ++++++++ .../ui/union/union-derive-clone.mirunsafeck.stderr | 4 ++++ .../ui/union/union-derive-clone.thirunsafeck.stderr | 4 ++++ src/test/ui/unique-object-noncopyable.stderr | 8 ++++++++ src/test/ui/unique-pinned-nocopy.stderr | 8 ++++++++ 14 files changed, 80 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 6e97b0bf2ab7d..a93588351361e 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2611,15 +2611,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // up to a depth of three None } else { - // recursively search fields of `candidate_field` if it's a ty::Adt field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0()); let field_ty = candidate_field.ty(self.tcx, subst); - if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) { - for field in nested_fields.iter() { + if matches(candidate_field, field_ty) { + return Some(field_path); + } else if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) { + // recursively search fields of `candidate_field` if it's a ty::Adt + for field in nested_fields { if field.vis.is_accessible_from(id, self.tcx) { - if matches(candidate_field, field_ty) { - return Some(field_path); - } else if let Some(field_path) = self.check_for_nested_field_satisfying( + if let Some(field_path) = self.check_for_nested_field_satisfying( span, matches, field, diff --git a/src/test/ui/copy-a-resource.stderr b/src/test/ui/copy-a-resource.stderr index 128087f1e3755..b92449c6e0aff 100644 --- a/src/test/ui/copy-a-resource.stderr +++ b/src/test/ui/copy-a-resource.stderr @@ -10,6 +10,10 @@ LL | let _y = x.clone(); = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `Clone` +help: one of the expressions' fields has a method of the same name + | +LL | let _y = x.i.clone(); + | ++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2823.stderr b/src/test/ui/issues/issue-2823.stderr index b5a2b2f55a6d4..208b340d06410 100644 --- a/src/test/ui/issues/issue-2823.stderr +++ b/src/test/ui/issues/issue-2823.stderr @@ -10,6 +10,10 @@ LL | let _d = c.clone(); = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `Clone` +help: one of the expressions' fields has a method of the same name + | +LL | let _d = c.x.clone(); + | ++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index 68337a715e14f..e8797ea7b5b4c 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -33,6 +33,10 @@ LL | pub struct TakeWhile { which is required by `Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` `Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` which is required by `&mut Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` +help: one of the expressions' fields has a method of the same name + | +LL | .it.collect(); + | +++ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-39175.stderr b/src/test/ui/issues/issue-39175.stderr index afceae82e68be..b19f58d2a381b 100644 --- a/src/test/ui/issues/issue-39175.stderr +++ b/src/test/ui/issues/issue-39175.stderr @@ -5,6 +5,10 @@ LL | Command::new("echo").arg("hello").exec(); | ^^^^ method not found in `&mut Command` | = help: items from traits can only be used if the trait is in scope +help: one of the expressions' fields has a method of the same name + | +LL | Command::new("echo").arg("hello").inner.exec(); + | ++++++ help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use std::os::unix::process::CommandExt; diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index b11ea97d160be..c3c8e5f272e3f 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -35,6 +35,10 @@ LL | pub struct Filter { which is required by `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator` `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator` which is required by `&mut Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator` +help: one of the expressions' fields has a method of the same name + | +LL | once::<&str>("str").fuse().filter(|a: &str| true).iter.count(); + | +++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/noncopyable-class.stderr b/src/test/ui/noncopyable-class.stderr index 0c696163a26c5..15e22e946da8a 100644 --- a/src/test/ui/noncopyable-class.stderr +++ b/src/test/ui/noncopyable-class.stderr @@ -10,6 +10,14 @@ LL | let _y = x.clone(); = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `Clone` +help: one of the expressions' fields has a method of the same name + | +LL | let _y = x.i.clone(); + | ++ +help: one of the expressions' fields has a method of the same name + | +LL | let _y = x.j.x.clone(); + | ++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/import-trait-for-method-call.stderr b/src/test/ui/suggestions/import-trait-for-method-call.stderr index bac8de7987256..f220458f321f0 100644 --- a/src/test/ui/suggestions/import-trait-for-method-call.stderr +++ b/src/test/ui/suggestions/import-trait-for-method-call.stderr @@ -10,6 +10,10 @@ LL | fn finish(&self) -> u64; | ------ the method is available for `DefaultHasher` here | = help: items from traits can only be used if the trait is in scope +help: one of the expressions' fields has a method of the same name + | +LL | h.0.finish() + | ++ help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use std::hash::Hasher; diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index d121932c842e3..e19bc5a1fd48d 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -41,6 +41,16 @@ LL | pub struct BufWriter { `&dyn std::io::Write: std::io::Write` which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) +help: one of the expressions' fields has a method of the same name + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | +LL | $dst.inner.write_fmt($crate::format_args_nl!($($arg)*)) + | ++++++ +help: one of the expressions' fields has a method of the same name + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | +LL | $dst.buf.write_fmt($crate::format_args_nl!($($arg)*)) + | ++++ error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/suggest-using-chars.stderr b/src/test/ui/suggestions/suggest-using-chars.stderr index 99bcfb08a0892..1690309719fa7 100644 --- a/src/test/ui/suggestions/suggest-using-chars.stderr +++ b/src/test/ui/suggestions/suggest-using-chars.stderr @@ -25,6 +25,10 @@ help: because of the in-memory representation of `&str`, to obtain an `Iterator` | LL | let _ = String::from("bar").chars(); | ~~~~~ +help: one of the expressions' fields has a method of the same name + | +LL | let _ = String::from("bar").vec.iter(); + | ++++ error[E0599]: no method named `iter` found for reference `&String` in the current scope --> $DIR/suggest-using-chars.rs:5:36 @@ -36,6 +40,10 @@ help: because of the in-memory representation of `&str`, to obtain an `Iterator` | LL | let _ = (&String::from("bar")).chars(); | ~~~~~ +help: one of the expressions' fields has a method of the same name + | +LL | let _ = (&String::from("bar")).vec.iter(); + | ++++ error[E0599]: no method named `iter` found for type `{integer}` in the current scope --> $DIR/suggest-using-chars.rs:6:15 diff --git a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr index 148fb5046705b..44c9d4a84387e 100644 --- a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr @@ -42,6 +42,10 @@ help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | LL | #[derive(Clone, Copy)] | +help: one of the expressions' fields has a method of the same name + | +LL | let w = u.a.clone(); + | ++ error: aborting due to 2 previous errors diff --git a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr index 148fb5046705b..44c9d4a84387e 100644 --- a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr @@ -42,6 +42,10 @@ help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | LL | #[derive(Clone, Copy)] | +help: one of the expressions' fields has a method of the same name + | +LL | let w = u.a.clone(); + | ++ error: aborting due to 2 previous errors diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 98a9bd07ed21d..12917d54114e9 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -23,6 +23,14 @@ LL | | >(Unique, A); which is required by `Box: Clone` `dyn Foo: Clone` which is required by `Box: Clone` +help: one of the expressions' fields has a method of the same name + | +LL | let _z = y.0.clone(); + | ++ +help: one of the expressions' fields has a method of the same name + | +LL | let _z = y.1.clone(); + | ++ error: aborting due to previous error diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index 7af9c684b72e3..cc9bdd26e11c5 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -25,6 +25,14 @@ help: consider annotating `R` with `#[derive(Clone)]` | LL | #[derive(Clone)] | +help: one of the expressions' fields has a method of the same name + | +LL | let _j = i.0.clone(); + | ++ +help: one of the expressions' fields has a method of the same name + | +LL | let _j = i.1.clone(); + | ++ error: aborting due to previous error From 4df6cbe96fe3e356aff89155f58a497d48bc78ee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 3 Aug 2022 06:42:19 +0000 Subject: [PATCH 2/4] Consider privacy more carefully when suggesting accessing fields --- compiler/rustc_typeck/src/check/expr.rs | 63 +++++++++++-------- .../rustc_typeck/src/check/method/suggest.rs | 7 ++- src/test/ui/issues/issue-31173.stderr | 4 -- src/test/ui/issues/issue-39175.stderr | 4 -- .../ui/mismatched_types/issue-36053-2.stderr | 4 -- .../import-trait-for-method-call.stderr | 4 -- .../mut-borrow-needed-by-trait.stderr | 10 --- .../ui/suggestions/suggest-using-chars.stderr | 8 --- src/test/ui/unique-object-noncopyable.stderr | 8 --- src/test/ui/unique-pinned-nocopy.stderr | 8 --- 10 files changed, 40 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index a93588351361e..523a10cc36a9e 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2535,15 +2535,18 @@ 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 - if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) { - for candidate_field in fields.iter() { + let mod_id = self.tcx.parent_module(id).to_def_id(); + if let Some((fields, substs)) = + self.get_field_candidates_considering_privacy(span, expr_t, mod_id) + { + for candidate_field in fields { if let Some(mut field_path) = self.check_for_nested_field_satisfying( span, &|candidate_field, _| candidate_field.ident(self.tcx()) == field, candidate_field, substs, vec![], - self.tcx.parent_module(id).to_def_id(), + mod_id, ) { // field_path includes `field` that we're looking for, so pop it. field_path.pop(); @@ -2567,22 +2570,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err } - pub(crate) fn get_field_candidates( + pub(crate) fn get_field_candidates_considering_privacy( &self, span: Span, - base_t: Ty<'tcx>, - ) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> { - debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t); + base_ty: Ty<'tcx>, + mod_id: DefId, + ) -> Option<(impl Iterator + 'tcx, SubstsRef<'tcx>)> { + debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); - for (base_t, _) in self.autoderef(span, base_t) { + for (base_t, _) in self.autoderef(span, base_ty) { match base_t.kind() { ty::Adt(base_def, substs) if !base_def.is_enum() => { - let fields = &base_def.non_enum_variant().fields; - // For compile-time reasons put a limit on number of fields we search - if fields.len() > 100 { - return None; - } - return Some((fields, substs)); + let tcx = self.tcx; + return Some(( + base_def + .non_enum_variant() + .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), + substs, + )); } _ => {} } @@ -2599,7 +2608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_field: &ty::FieldDef, subst: SubstsRef<'tcx>, mut field_path: Vec, - id: DefId, + mod_id: DefId, ) -> Option> { debug!( "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}", @@ -2615,20 +2624,20 @@ 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(span, field_ty) { + } 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 field.vis.is_accessible_from(id, self.tcx) { - if let Some(field_path) = self.check_for_nested_field_satisfying( - span, - matches, - field, - subst, - field_path.clone(), - id, - ) { - return Some(field_path); - } + if let Some(field_path) = self.check_for_nested_field_satisfying( + span, + matches, + field, + subst, + field_path.clone(), + mod_id, + ) { + return Some(field_path); } } } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index c92b93cbc22d2..ee6fe8699e129 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1334,10 +1334,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: Ident, ) { if let SelfSource::MethodCall(expr) = source - && let Some((fields, substs)) = self.get_field_candidates(span, actual) + && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id() + && let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id) { let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)); - for candidate_field in fields.iter() { + for candidate_field in fields { if let Some(field_path) = self.check_for_nested_field_satisfying( span, &|_, field_ty| { @@ -1353,7 +1354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_field, substs, vec![], - self.tcx.parent_module(expr.hir_id).to_def_id(), + mod_id, ) { let field_path_str = field_path .iter() diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index e8797ea7b5b4c..68337a715e14f 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -33,10 +33,6 @@ LL | pub struct TakeWhile { which is required by `Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` `Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` which is required by `&mut Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` -help: one of the expressions' fields has a method of the same name - | -LL | .it.collect(); - | +++ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-39175.stderr b/src/test/ui/issues/issue-39175.stderr index b19f58d2a381b..afceae82e68be 100644 --- a/src/test/ui/issues/issue-39175.stderr +++ b/src/test/ui/issues/issue-39175.stderr @@ -5,10 +5,6 @@ LL | Command::new("echo").arg("hello").exec(); | ^^^^ method not found in `&mut Command` | = help: items from traits can only be used if the trait is in scope -help: one of the expressions' fields has a method of the same name - | -LL | Command::new("echo").arg("hello").inner.exec(); - | ++++++ help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use std::os::unix::process::CommandExt; diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index c3c8e5f272e3f..b11ea97d160be 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -35,10 +35,6 @@ LL | pub struct Filter { which is required by `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator` `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator` which is required by `&mut Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator` -help: one of the expressions' fields has a method of the same name - | -LL | once::<&str>("str").fuse().filter(|a: &str| true).iter.count(); - | +++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/import-trait-for-method-call.stderr b/src/test/ui/suggestions/import-trait-for-method-call.stderr index f220458f321f0..bac8de7987256 100644 --- a/src/test/ui/suggestions/import-trait-for-method-call.stderr +++ b/src/test/ui/suggestions/import-trait-for-method-call.stderr @@ -10,10 +10,6 @@ LL | fn finish(&self) -> u64; | ------ the method is available for `DefaultHasher` here | = help: items from traits can only be used if the trait is in scope -help: one of the expressions' fields has a method of the same name - | -LL | h.0.finish() - | ++ help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use std::hash::Hasher; diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index e19bc5a1fd48d..d121932c842e3 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -41,16 +41,6 @@ LL | pub struct BufWriter { `&dyn std::io::Write: std::io::Write` which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) -help: one of the expressions' fields has a method of the same name - --> $SRC_DIR/core/src/macros/mod.rs:LL:COL - | -LL | $dst.inner.write_fmt($crate::format_args_nl!($($arg)*)) - | ++++++ -help: one of the expressions' fields has a method of the same name - --> $SRC_DIR/core/src/macros/mod.rs:LL:COL - | -LL | $dst.buf.write_fmt($crate::format_args_nl!($($arg)*)) - | ++++ error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/suggest-using-chars.stderr b/src/test/ui/suggestions/suggest-using-chars.stderr index 1690309719fa7..99bcfb08a0892 100644 --- a/src/test/ui/suggestions/suggest-using-chars.stderr +++ b/src/test/ui/suggestions/suggest-using-chars.stderr @@ -25,10 +25,6 @@ help: because of the in-memory representation of `&str`, to obtain an `Iterator` | LL | let _ = String::from("bar").chars(); | ~~~~~ -help: one of the expressions' fields has a method of the same name - | -LL | let _ = String::from("bar").vec.iter(); - | ++++ error[E0599]: no method named `iter` found for reference `&String` in the current scope --> $DIR/suggest-using-chars.rs:5:36 @@ -40,10 +36,6 @@ help: because of the in-memory representation of `&str`, to obtain an `Iterator` | LL | let _ = (&String::from("bar")).chars(); | ~~~~~ -help: one of the expressions' fields has a method of the same name - | -LL | let _ = (&String::from("bar")).vec.iter(); - | ++++ error[E0599]: no method named `iter` found for type `{integer}` in the current scope --> $DIR/suggest-using-chars.rs:6:15 diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 12917d54114e9..98a9bd07ed21d 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -23,14 +23,6 @@ LL | | >(Unique, A); which is required by `Box: Clone` `dyn Foo: Clone` which is required by `Box: Clone` -help: one of the expressions' fields has a method of the same name - | -LL | let _z = y.0.clone(); - | ++ -help: one of the expressions' fields has a method of the same name - | -LL | let _z = y.1.clone(); - | ++ error: aborting due to previous error diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index cc9bdd26e11c5..7af9c684b72e3 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -25,14 +25,6 @@ help: consider annotating `R` with `#[derive(Clone)]` | LL | #[derive(Clone)] | -help: one of the expressions' fields has a method of the same name - | -LL | let _j = i.0.clone(); - | ++ -help: one of the expressions' fields has a method of the same name - | -LL | let _j = i.1.clone(); - | ++ error: aborting due to previous error From 2a3fd5053f9cd5897c4a5eed2b742699aab279a4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 3 Aug 2022 06:54:21 +0000 Subject: [PATCH 3/4] Don't suggest field method if it's just missing some bounds --- compiler/rustc_typeck/src/check/method/suggest.rs | 6 +++++- src/test/ui/hrtb/issue-30786.stderr | 8 -------- src/test/ui/union/union-derive-clone.mirunsafeck.stderr | 4 ---- src/test/ui/union/union-derive-clone.thirunsafeck.stderr | 4 ---- 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index ee6fe8699e129..f73d0fbb27716 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1000,7 +1000,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { label_span_not_found(&mut err); } - self.check_for_field_method(&mut err, source, span, actual, item_name); + // Don't suggest (for example) `expr.field.method()` if `expr.method()` + // doesn't exist due to unsatisfied predicates. + if unsatisfied_predicates.is_empty() { + self.check_for_field_method(&mut err, source, span, actual, item_name); + } self.check_for_unwrap_self(&mut err, source, span, actual, item_name); diff --git a/src/test/ui/hrtb/issue-30786.stderr b/src/test/ui/hrtb/issue-30786.stderr index bc7b5e914e127..ffe3d7b81f51e 100644 --- a/src/test/ui/hrtb/issue-30786.stderr +++ b/src/test/ui/hrtb/issue-30786.stderr @@ -18,10 +18,6 @@ note: the following trait bounds were not satisfied: | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here -help: one of the expressions' fields has a method of the same name - | -LL | let filter = map.stream.filterx(|x: &_| true); - | +++++++ error[E0599]: the method `countx` exists for struct `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied --> $DIR/issue-30786.rs:130:24 @@ -43,10 +39,6 @@ note: the following trait bounds were not satisfied: | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here -help: one of the expressions' fields has a method of the same name - | -LL | let count = filter.stream.countx(); - | +++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr index 44c9d4a84387e..148fb5046705b 100644 --- a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr @@ -42,10 +42,6 @@ help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | LL | #[derive(Clone, Copy)] | -help: one of the expressions' fields has a method of the same name - | -LL | let w = u.a.clone(); - | ++ error: aborting due to 2 previous errors diff --git a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr index 44c9d4a84387e..148fb5046705b 100644 --- a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr @@ -42,10 +42,6 @@ help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | LL | #[derive(Clone, Copy)] | -help: one of the expressions' fields has a method of the same name - | -LL | let w = u.a.clone(); - | ++ error: aborting due to 2 previous errors From 603ffebd37a26a5b8d3c7372d432f6f2c053371d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 3 Aug 2022 07:01:18 +0000 Subject: [PATCH 4/4] Skip over structs with no private fields that impl Deref --- compiler/rustc_typeck/src/check/expr.rs | 11 ++++-- .../field-access-considering-privacy.rs | 35 +++++++++++++++++++ .../field-access-considering-privacy.stderr | 14 ++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/suggestions/field-access-considering-privacy.rs create mode 100644 src/test/ui/suggestions/field-access-considering-privacy.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 523a10cc36a9e..67d0e331012f2 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2582,10 +2582,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match base_t.kind() { ty::Adt(base_def, substs) 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; + } return Some(( - base_def - .non_enum_variant() - .fields + 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 diff --git a/src/test/ui/suggestions/field-access-considering-privacy.rs b/src/test/ui/suggestions/field-access-considering-privacy.rs new file mode 100644 index 0000000000000..3de06b21420b4 --- /dev/null +++ b/src/test/ui/suggestions/field-access-considering-privacy.rs @@ -0,0 +1,35 @@ +use a::TyCtxt; + +mod a { + use std::ops::Deref; + pub struct TyCtxt<'tcx> { + gcx: &'tcx GlobalCtxt<'tcx>, + } + + impl<'tcx> Deref for TyCtxt<'tcx> { + type Target = &'tcx GlobalCtxt<'tcx>; + + fn deref(&self) -> &Self::Target { + &self.gcx + } + } + + pub struct GlobalCtxt<'tcx> { + pub sess: &'tcx Session, + _t: &'tcx (), + } + + pub struct Session { + pub opts: (), + } +} + +mod b { + fn foo<'tcx>(tcx: crate::TyCtxt<'tcx>) { + tcx.opts; + //~^ ERROR no field `opts` on type `TyCtxt<'tcx>` + //~| HELP one of the expressions' fields has a field of the same name + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/field-access-considering-privacy.stderr b/src/test/ui/suggestions/field-access-considering-privacy.stderr new file mode 100644 index 0000000000000..cbf6f3d100258 --- /dev/null +++ b/src/test/ui/suggestions/field-access-considering-privacy.stderr @@ -0,0 +1,14 @@ +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 + | +LL | tcx.sess.opts; + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0609`.