about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkadmin <julianknodt@gmail.com>2022-02-02 16:42:37 +0000
committerkadmin <julianknodt@gmail.com>2022-02-03 15:17:51 +0000
commit2dfd77d67555ab9a5a76002bb47749a795f3a5bf (patch)
tree79ebd4003c143deb2e9e696b057ea95ffbc712a8
parentd5f9c40e6a9ecc62432e71e886cef83a4c2c9b98 (diff)
downloadrust-2dfd77d67555ab9a5a76002bb47749a795f3a5bf.tar.gz
rust-2dfd77d67555ab9a5a76002bb47749a795f3a5bf.zip
Fix ret > 1 bound if shadowed by const
Prior to a change, it would only look at types in bounds. When it started looking for consts,
shadowing type variables with a const would cause an ICE, so now defer looking at consts only if
there are no types present.
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs5
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs59
-rw-r--r--src/test/ui/associated-consts/shadowed-const.rs23
-rw-r--r--src/test/ui/associated-consts/shadowed-const.stderr8
4 files changed, 63 insertions, 32 deletions
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index c23d4eae1a4..49f846562a3 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -160,12 +160,11 @@ impl<'tcx> AssocItems<'tcx> {
         &self,
         tcx: TyCtxt<'_>,
         ident: Ident,
+        // Sorted in order of what kinds to look at
         kinds: &[AssocKind],
         parent_def_id: DefId,
     ) -> Option<&ty::AssocItem> {
-        self.filter_by_name_unhygienic(ident.name)
-            .filter(|item| kinds.contains(&item.kind))
-            .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
+        kinds.iter().find_map(|kind| self.find_by_name_and_kind(tcx, ident, *kind, parent_def_id))
     }
 
     /// Returns the associated item with the given name in the given `Namespace`, if one exists.
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 3e2d7fc3820..0ad2242f667 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -887,15 +887,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
             .is_some()
     }
-    fn trait_defines_associated_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
+    fn trait_defines_associated_const_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
         self.tcx()
             .associated_items(trait_def_id)
-            .find_by_name_and_kinds(
-                self.tcx(),
-                assoc_name,
-                &[ty::AssocKind::Type, ty::AssocKind::Const],
-                trait_def_id,
-            )
+            .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Const, trait_def_id)
             .is_some()
     }
 
@@ -1145,13 +1140,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         // 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 assoc_item = tcx
-            .associated_items(candidate.def_id())
-            .filter_by_name_unhygienic(assoc_ident.name)
-            .find(|i| {
-                (i.kind == ty::AssocKind::Type || i.kind == ty::AssocKind::Const)
-                    && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
-            })
+        let find_item_of_kind = |kind| {
+            tcx.associated_items(candidate.def_id())
+                .filter_by_name_unhygienic(assoc_ident.name)
+                .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
+        };
+        let assoc_item = find_item_of_kind(ty::AssocKind::Type)
+            .or_else(|| find_item_of_kind(ty::AssocKind::Const))
             .expect("missing associated type");
 
         if !assoc_item.vis.is_accessible_from(def_scope, tcx) {
@@ -1657,11 +1652,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
     {
         let mut matching_candidates = all_candidates()
-            .filter(|r| self.trait_defines_associated_named(r.def_id(), assoc_name));
-
-        let bound = match matching_candidates.next() {
-            Some(bound) => bound,
-            None => {
+            .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
+        let mut const_candidates = all_candidates()
+            .filter(|r| self.trait_defines_associated_const_named(r.def_id(), assoc_name));
+
+        let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) {
+            (Some(bound), _) => (bound, matching_candidates.next()),
+            (None, Some(bound)) => (bound, const_candidates.next()),
+            (None, None) => {
                 self.complain_about_assoc_type_not_found(
                     all_candidates,
                     &ty_param_name(),
@@ -1671,10 +1669,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 return Err(ErrorReported);
             }
         };
-
         debug!("one_bound_for_assoc_type: bound = {:?}", bound);
 
-        if let Some(bound2) = matching_candidates.next() {
+        if let Some(bound2) = next_cand {
             debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
 
             let is_equality = is_equality();
@@ -1759,6 +1756,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 return Err(ErrorReported);
             }
         }
+
         Ok(bound)
     }
 
@@ -1893,14 +1891,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         // 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
-            })
-            .expect("missing associated type");
+        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 msg = format!("found associated const `{assoc_ident}` when type was expected");
+            tcx.sess.struct_span_err(span, &msg).emit();
+            return Err(ErrorReported);
+        };
 
         let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound);
         let ty = self.normalize_ty(span, ty);
diff --git a/src/test/ui/associated-consts/shadowed-const.rs b/src/test/ui/associated-consts/shadowed-const.rs
new file mode 100644
index 00000000000..cfdb391d39d
--- /dev/null
+++ b/src/test/ui/associated-consts/shadowed-const.rs
@@ -0,0 +1,23 @@
+// Checking that none of these ICE, which was introduced in
+// https://github.com/rust-lang/rust/issues/93553
+trait Foo {
+    type Bar;
+}
+
+trait Baz: Foo {
+    const Bar: Self::Bar;
+}
+
+trait Baz2: Foo {
+    const Bar: u32;
+
+    fn foo() -> Self::Bar;
+}
+
+trait Baz3 {
+  const BAR: usize;
+  const QUX: Self::BAR;
+  //~^ ERROR found associated const
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-consts/shadowed-const.stderr b/src/test/ui/associated-consts/shadowed-const.stderr
new file mode 100644
index 00000000000..fe21d2aec00
--- /dev/null
+++ b/src/test/ui/associated-consts/shadowed-const.stderr
@@ -0,0 +1,8 @@
+error: found associated const `BAR` when type was expected
+  --> $DIR/shadowed-const.rs:19:14
+   |
+LL |   const QUX: Self::BAR;
+   |              ^^^^^^^^^
+
+error: aborting due to previous error
+