about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-11-16 08:36:11 +0100
committerGitHub <noreply@github.com>2022-11-16 08:36:11 +0100
commit3a8cacd7fb4e05df32bb5c94bfe650519bae993e (patch)
tree376f6c8291883f928e102ed134b7b2455f49afcf
parent88a19197b9f57b84a091c34d59c3d9ae72f03511 (diff)
parent70ad2f53449995eb632eb9ef8f7740b34afb46b3 (diff)
downloadrust-3a8cacd7fb4e05df32bb5c94bfe650519bae993e.tar.gz
rust-3a8cacd7fb4e05df32bb5c94bfe650519bae993e.zip
Rollup merge of #104348 - fmease:iat-vis-stab, r=cjgillot
Respect visibility & stability of inherent associated types

As discussed in #103621, this probably won't be the final location of the code that resolves inherent associated types. Still, I think it's valuable to push correctness fixes for this feature (in regards to visibility and stability).

Let me know if I should write a translatable diagnostic instead and if I should move the tests to `privacy/` and `stability-attribute/` respectively.

Fixes #104243.
````@rustbot```` label A-visibility F-inherent_associated_types
r? ````@cjgillot```` (since you reviewed #103621, feel free to reroll though)
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs83
-rw-r--r--src/test/ui/associated-inherent-types/assoc-inherent-private.rs23
-rw-r--r--src/test/ui/associated-inherent-types/assoc-inherent-private.stderr21
-rw-r--r--src/test/ui/associated-inherent-types/assoc-inherent-unstable.rs6
-rw-r--r--src/test/ui/associated-inherent-types/assoc-inherent-unstable.stderr11
-rw-r--r--src/test/ui/associated-inherent-types/auxiliary/assoc-inherent-unstable.rs11
-rw-r--r--src/test/ui/traits/item-privacy.stderr5
7 files changed, 122 insertions, 38 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 4518cf30acd..7a2d98dbe75 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1917,17 +1917,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
 
             // see if we can satisfy using an inherent associated type
-            for impl_ in tcx.inherent_impls(adt_def.did()) {
-                let assoc_ty = tcx.associated_items(impl_).find_by_name_and_kind(
-                    tcx,
-                    assoc_ident,
-                    ty::AssocKind::Type,
-                    *impl_,
-                );
-                if let Some(assoc_ty) = assoc_ty {
-                    let ty = tcx.type_of(assoc_ty.def_id);
-                    return Ok((ty, DefKind::AssocTy, assoc_ty.def_id));
-                }
+            for &impl_ in tcx.inherent_impls(adt_def.did()) {
+                let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else {
+                    continue;
+                };
+                // FIXME(inherent_associated_types): This does not substitute parameters.
+                let ty = tcx.type_of(assoc_ty_did);
+                return Ok((ty, DefKind::AssocTy, assoc_ty_did));
             }
         }
 
@@ -2014,37 +2010,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         };
 
         let trait_did = bound.def_id();
-        let (assoc_ident, def_scope) =
-            tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id);
-
-        // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
-        // of calling `filter_by_name_and_kind`.
-        let item = tcx.associated_items(trait_did).in_definition_order().find(|i| {
-            i.kind.namespace() == Namespace::TypeNS
-                && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
-        });
-        // Assume that if it's not matched, there must be a const defined with the same name
-        // but it was used in a type position.
-        let Some(item) = item else {
+        let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did) else {
+            // Assume that if it's not matched, there must be a const defined with the same name
+            // but it was used in a type position.
             let msg = format!("found associated const `{assoc_ident}` when type was expected");
             let guar = tcx.sess.struct_span_err(span, &msg).emit();
             return Err(guar);
         };
 
-        let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound);
+        let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
         let ty = self.normalize_ty(span, ty);
 
-        let kind = DefKind::AssocTy;
-        if !item.visibility(tcx).is_accessible_from(def_scope, tcx) {
-            let kind = kind.descr(item.def_id);
-            let msg = format!("{} `{}` is private", kind, assoc_ident);
-            tcx.sess
-                .struct_span_err(span, &msg)
-                .span_label(span, &format!("private {}", kind))
-                .emit();
-        }
-        tcx.check_stability(item.def_id, Some(hir_ref_id), span, None);
-
         if let Some(variant_def_id) = variant_resolution {
             tcx.struct_span_lint_hir(
                 AMBIGUOUS_ASSOCIATED_ITEMS,
@@ -2063,7 +2039,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     };
 
                     could_refer_to(DefKind::Variant, variant_def_id, "");
-                    could_refer_to(kind, item.def_id, " also");
+                    could_refer_to(DefKind::AssocTy, assoc_ty_did, " also");
 
                     lint.span_suggestion(
                         span,
@@ -2076,7 +2052,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 },
             );
         }
-        Ok((ty, kind, item.def_id))
+        Ok((ty, DefKind::AssocTy, assoc_ty_did))
+    }
+
+    fn lookup_assoc_ty(
+        &self,
+        ident: Ident,
+        block: hir::HirId,
+        span: Span,
+        scope: DefId,
+    ) -> Option<DefId> {
+        let tcx = self.tcx();
+        let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, block);
+
+        // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
+        // of calling `find_by_name_and_kind`.
+        let item = tcx.associated_items(scope).in_definition_order().find(|i| {
+            i.kind.namespace() == Namespace::TypeNS
+                && i.ident(tcx).normalize_to_macros_2_0() == ident
+        })?;
+
+        let kind = DefKind::AssocTy;
+        if !item.visibility(tcx).is_accessible_from(def_scope, tcx) {
+            let kind = kind.descr(item.def_id);
+            let msg = format!("{kind} `{ident}` is private");
+            let def_span = self.tcx().def_span(item.def_id);
+            tcx.sess
+                .struct_span_err_with_code(span, &msg, rustc_errors::error_code!(E0624))
+                .span_label(span, &format!("private {kind}"))
+                .span_label(def_span, &format!("{kind} defined here"))
+                .emit();
+        }
+        tcx.check_stability(item.def_id, Some(block), span, None);
+
+        Some(item.def_id)
     }
 
     fn qpath_to_ty(
diff --git a/src/test/ui/associated-inherent-types/assoc-inherent-private.rs b/src/test/ui/associated-inherent-types/assoc-inherent-private.rs
new file mode 100644
index 00000000000..53158195443
--- /dev/null
+++ b/src/test/ui/associated-inherent-types/assoc-inherent-private.rs
@@ -0,0 +1,23 @@
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+mod m {
+    pub struct T;
+    impl T {
+        type P = ();
+    }
+}
+type U = m::T::P; //~ ERROR associated type `P` is private
+
+mod n {
+    pub mod n {
+        pub struct T;
+        impl T {
+            pub(super) type P = bool;
+        }
+    }
+    type U = n::T::P;
+}
+type V = n::n::T::P; //~ ERROR associated type `P` is private
+
+fn main() {}
diff --git a/src/test/ui/associated-inherent-types/assoc-inherent-private.stderr b/src/test/ui/associated-inherent-types/assoc-inherent-private.stderr
new file mode 100644
index 00000000000..d67b45dae3f
--- /dev/null
+++ b/src/test/ui/associated-inherent-types/assoc-inherent-private.stderr
@@ -0,0 +1,21 @@
+error[E0624]: associated type `P` is private
+  --> $DIR/assoc-inherent-private.rs:10:10
+   |
+LL |         type P = ();
+   |         ------ associated type defined here
+...
+LL | type U = m::T::P;
+   |          ^^^^^^^ private associated type
+
+error[E0624]: associated type `P` is private
+  --> $DIR/assoc-inherent-private.rs:21:10
+   |
+LL |             pub(super) type P = bool;
+   |             ----------------- associated type defined here
+...
+LL | type V = n::n::T::P;
+   |          ^^^^^^^^^^ private associated type
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0624`.
diff --git a/src/test/ui/associated-inherent-types/assoc-inherent-unstable.rs b/src/test/ui/associated-inherent-types/assoc-inherent-unstable.rs
new file mode 100644
index 00000000000..34b4e47bf46
--- /dev/null
+++ b/src/test/ui/associated-inherent-types/assoc-inherent-unstable.rs
@@ -0,0 +1,6 @@
+// aux-crate:aux=assoc-inherent-unstable.rs
+// edition: 2021
+
+type Data = aux::Owner::Data; //~ ERROR use of unstable library feature 'data'
+
+fn main() {}
diff --git a/src/test/ui/associated-inherent-types/assoc-inherent-unstable.stderr b/src/test/ui/associated-inherent-types/assoc-inherent-unstable.stderr
new file mode 100644
index 00000000000..c0be8bfd79b
--- /dev/null
+++ b/src/test/ui/associated-inherent-types/assoc-inherent-unstable.stderr
@@ -0,0 +1,11 @@
+error[E0658]: use of unstable library feature 'data'
+  --> $DIR/assoc-inherent-unstable.rs:4:13
+   |
+LL | type Data = aux::Owner::Data;
+   |             ^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(data)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/associated-inherent-types/auxiliary/assoc-inherent-unstable.rs b/src/test/ui/associated-inherent-types/auxiliary/assoc-inherent-unstable.rs
new file mode 100644
index 00000000000..6b71ffc97b5
--- /dev/null
+++ b/src/test/ui/associated-inherent-types/auxiliary/assoc-inherent-unstable.rs
@@ -0,0 +1,11 @@
+#![feature(staged_api)]
+#![feature(inherent_associated_types)]
+#![stable(feature = "main", since = "1.0.0")]
+
+#[stable(feature = "main", since = "1.0.0")]
+pub struct Owner;
+
+impl Owner {
+    #[unstable(feature = "data", issue = "none")]
+    pub type Data = ();
+}
diff --git a/src/test/ui/traits/item-privacy.stderr b/src/test/ui/traits/item-privacy.stderr
index 7f78b37ba84..f137a298a7f 100644
--- a/src/test/ui/traits/item-privacy.stderr
+++ b/src/test/ui/traits/item-privacy.stderr
@@ -162,9 +162,12 @@ error[E0223]: ambiguous associated type
 LL |     let _: S::C;
    |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::C`
 
-error: associated type `A` is private
+error[E0624]: associated type `A` is private
   --> $DIR/item-privacy.rs:119:12
    |
+LL |         type A = u8;
+   |         ------ associated type defined here
+...
 LL |     let _: T::A;
    |            ^^^^ private associated type