diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index c23d4eae1a400..49f846562a3cc 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 3e2d7fc382050..0ad2242f6677c 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>, { 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 0000000000000..cfdb391d39d51 --- /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 0000000000000..fe21d2aec00bc --- /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 +