From 603ffebd37a26a5b8d3c7372d432f6f2c053371d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 3 Aug 2022 07:01:18 +0000 Subject: [PATCH] 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 523a10cc36a..67d0e331012 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 00000000000..3de06b21420 --- /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 00000000000..cbf6f3d1002 --- /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`.