diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 6d8a5bc0e9008..17e0aeb044cf8 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -408,7 +408,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { // Create the generic arguments for the associated type or constant by joining the // parent arguments (the arguments of the trait) and the own arguments (the ones of // the associated item itself) and construct an alias type using them. - candidate.map_bound(|trait_ref| { + let alias_ty = candidate.map_bound(|trait_ref| { let ident = Ident::new(assoc_item.name, binding.ident.span); let item_segment = hir::PathSegment { ident, @@ -430,7 +430,25 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { // *constants* to represent *const projections*. Alias *term* would be a more // appropriate name but alas. ty::AliasTy::new(tcx, assoc_item.def_id, alias_args) - }) + }); + + // Provide the resolved type of the associated constant to `type_of(AnonConst)`. + if !speculative + && let hir::TypeBindingKind::Equality { term: hir::Term::Const(anon_const) } = + binding.kind + { + let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args)); + // Since the arguments passed to the alias type above may contain early-bound + // generic parameters, the instantiated type may contain some as well. + // Therefore wrap it in `EarlyBinder`. + // FIXME(fmease): Reject escaping late-bound vars. + tcx.feed_anon_const_type( + anon_const.def_id, + ty::EarlyBinder::bind(ty.skip_binder()), + ); + } + + alias_ty }; match binding.kind { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index a1345c2d81b63..598dba922d0c4 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -79,37 +79,6 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { .expect("const parameter types cannot be generic"); } - Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) - if let Node::TraitRef(trait_ref) = tcx.parent_hir_node(binding_id) => - { - let Some(trait_def_id) = trait_ref.trait_def_id() else { - return Ty::new_error_with_message( - tcx, - tcx.def_span(def_id), - "Could not find trait", - ); - }; - let assoc_items = tcx.associated_items(trait_def_id); - let assoc_item = assoc_items.find_by_name_and_kind( - tcx, - binding.ident, - ty::AssocKind::Const, - def_id.to_def_id(), - ); - return if let Some(assoc_item) = assoc_item { - tcx.type_of(assoc_item.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic") - } else { - // FIXME(associated_const_equality): add a useful error message here. - Ty::new_error_with_message( - tcx, - tcx.def_span(def_id), - "Could not find associated const on trait", - ) - }; - } - // This match arm is for when the def_id appears in a GAT whose // path can't be resolved without typechecking e.g. // diff --git a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs new file mode 100644 index 0000000000000..d5d724c9b1537 --- /dev/null +++ b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs @@ -0,0 +1,16 @@ +// Regression test for issue #118040. +// Ensure that we support assoc const eq bounds where the assoc const comes from a supertrait. + +//@ check-pass + +#![feature(associated_const_equality)] + +trait Trait: SuperTrait {} +trait SuperTrait: SuperSuperTrait {} +trait SuperSuperTrait { + const K: T; +} + +fn take(_: impl Trait) {} + +fn main() {} diff --git a/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs b/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs index 4ff05112897c7..76df014ccd9bd 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs +++ b/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs @@ -1,21 +1,25 @@ // Regression test for issue #112560. // Respect the fact that (associated) types and constants live in different namespaces and // therefore equality bounds involving identically named associated items don't conflict if -// their kind (type vs. const) differs. - -// FIXME(fmease): Extend this test to cover supertraits again -// once #118040 is fixed. See initial version of PR #118360. +// their kind (type vs. const) differs. This obviously extends to supertraits. //@ check-pass #![feature(associated_const_equality)] -trait Trait { +trait Trait: SuperTrait { type N; + type Q; const N: usize; } -fn take(_: impl Trait) {} +trait SuperTrait { + const Q: &'static str; +} + +fn take0(_: impl Trait) {} + +fn take1(_: impl Trait) {} fn main() {} diff --git a/tests/ui/generic-const-items/associated-const-equality.rs b/tests/ui/generic-const-items/associated-const-equality.rs index 3c727097e2b1c..c0179f02fd2eb 100644 --- a/tests/ui/generic-const-items/associated-const-equality.rs +++ b/tests/ui/generic-const-items/associated-const-equality.rs @@ -1,22 +1,31 @@ //@ check-pass -#![feature(generic_const_items, associated_const_equality)] +#![feature(generic_const_items, associated_const_equality, adt_const_params)] #![allow(incomplete_features)] trait Owner { const C: u32; const K: u32; + const Q: Maybe; } impl Owner for () { const C: u32 = N; const K: u32 = N + 1; + const Q: Maybe = Maybe::Nothing; } fn take0(_: impl Owner = { N }>) {} fn take1(_: impl Owner = 100>) {} +fn take2(_: impl Owner = { Maybe::Just(()) }>) {} fn main() { take0::<128>(()); take1(()); } + +#[derive(PartialEq, Eq, std::marker::ConstParamTy)] +enum Maybe { + Nothing, + Just(T), +}