about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-08-03 07:01:18 +0000
committerMichael Goulet <michael@errs.io>2022-08-03 07:02:56 +0000
commit603ffebd37a26a5b8d3c7372d432f6f2c053371d (patch)
tree9d555a91a44937144767ccac279abbe7ccfb4f89
parent2a3fd5053f9cd5897c4a5eed2b742699aab279a4 (diff)
downloadrust-603ffebd37a26a5b8d3c7372d432f6f2c053371d.tar.gz
rust-603ffebd37a26a5b8d3c7372d432f6f2c053371d.zip
Skip over structs with no private fields that impl Deref
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs11
-rw-r--r--src/test/ui/suggestions/field-access-considering-privacy.rs35
-rw-r--r--src/test/ui/suggestions/field-access-considering-privacy.stderr14
3 files changed, 57 insertions, 3 deletions
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<T>`.
+                    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`.