From 9864a2fbca8128be72e6489e782cc56c5c6f023b Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 14 Oct 2025 02:15:16 +0100 Subject: [PATCH] add `const_of_item` query and use it in normalization --- compiler/rustc_hir_analysis/src/collect.rs | 36 ++++++++ .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 18 ++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 13 +++ compiler/rustc_middle/src/ty/context.rs | 3 + .../src/solve/normalizes_to/free_alias.rs | 8 +- .../src/solve/normalizes_to/inherent.rs | 3 +- .../src/solve/normalizes_to/mod.rs | 14 +-- .../src/traits/normalize.rs | 89 +++++++++---------- .../src/traits/project.rs | 23 +---- .../src/normalize_projection_ty.rs | 2 +- compiler/rustc_type_ir/src/interner.rs | 1 + .../duplicate-bound-err.rs | 12 ++- .../duplicate-bound-err.stderr | 64 ++++++------- .../associated-type-bounds/duplicate-bound.rs | 5 +- 16 files changed, 171 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index d6ce5d80c045..302847eca115 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -96,6 +96,7 @@ pub(crate) fn provide(providers: &mut Providers) { rendered_precise_capturing_args, const_param_default, anon_const_kind, + const_of_item, ..*providers }; } @@ -1543,3 +1544,38 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin _ => ty::AnonConstKind::NonTypeSystem, } } + +#[instrument(level = "debug", skip(tcx), ret)] +fn const_of_item<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::EarlyBinder<'tcx, Const<'tcx>> { + let ct_rhs = match tcx.hir_node_by_def_id(def_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(.., ct), .. }) => *ct, + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(.., ct), .. + }) => ct.expect("no default value for trait assoc const"), + hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(.., ct), .. }) => *ct, + _ => { + span_bug!(tcx.def_span(def_id), "`const_of_item` expected a const or assoc const item") + } + }; + let ct_arg = match ct_rhs { + hir::ConstItemRhs::TypeConst(ct_arg) => ct_arg, + hir::ConstItemRhs::Body(body_id) => { + bug!("cannot call const_of_item on a non-type_const {body_id:?}") + } + }; + let icx = ItemCtxt::new(tcx, def_id); + let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); + let ct = icx + .lowerer() + .lower_const_arg(ct_arg, FeedConstTy::Param(def_id.to_def_id(), identity_args)); + if let Err(e) = icx.check_tainted_by_errors() + && !ct.references_error() + { + ty::EarlyBinder::bind(Const::new_error(tcx, e)) + } else { + ty::EarlyBinder::bind(ct) + } +} diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index d20df618b38b..4831395f3164 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -403,6 +403,7 @@ provide! { tcx, def_id, other, cdata, tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index)) } anon_const_kind => { table } + const_of_item => { table } } pub(in crate::rmeta) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index fd73dbde14c5..2c256ee9b702 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1383,6 +1383,21 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } +fn should_encode_const_of_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: DefKind) -> bool { + matches!(def_kind, DefKind::Const | DefKind::AssocConst) + && find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) + // AssocConst ==> assoc item has value + && (!matches!(def_kind, DefKind::AssocConst) || assoc_item_has_value(tcx, def_id)) +} + +fn assoc_item_has_value<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + let assoc_item = tcx.associated_item(def_id); + match assoc_item.container { + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true, + ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(), + } +} + impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_attrs(&mut self, def_id: LocalDefId) { let tcx = self.tcx; @@ -1604,6 +1619,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::AnonConst = def_kind { record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id)); } + if should_encode_const_of_item(self.tcx, def_id, def_kind) { + record!(self.tables.const_of_item[def_id] <- self.tcx.const_of_item(def_id)); + } if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 8f1c7bbb3968..c20c45ae5812 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -471,6 +471,7 @@ define_tables! { assumed_wf_types_for_rpitit: Table, Span)>>, opaque_ty_origin: Table>>, anon_const_kind: Table>, + const_of_item: Table>>>, associated_types_for_impl_traits_in_trait_or_impl: Table>>>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 4dae00c02ccf..53f25ae0840b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -293,6 +293,19 @@ rustc_queries! { separate_provide_extern } + /// Returns the const of the RHS of a (free or assoc) const item, if it is a `#[type_const]`. + /// + /// When a const item is used in a type-level expression, like in equality for an assoc const + /// projection, this allows us to retrieve the typesystem-appropriate representation of the + /// const value. + /// + /// This query will ICE if given a const that is not marked with `#[type_const]`. + query const_of_item(def_id: DefId) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> { + desc { |tcx| "computing the type-level value for `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } + separate_provide_extern + } + /// Returns the *type* of the definition given by `DefId`. /// /// For type aliases (whether eager or lazy) and associated types, this returns diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 60effa13406b..25562999646b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -242,6 +242,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of_opaque_hir_typeck(def_id) } + fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> { + self.const_of_item(def_id) + } type AdtDef = ty::AdtDef<'tcx>; fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs index 8aa6e4a3d711..8777f84957a7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs @@ -30,14 +30,12 @@ where ); let actual = if free_alias.kind(cx).is_type() { - cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args) + cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args).into() } else { - // FIXME(mgca): once const items are actual aliases defined as equal to type system consts - // this should instead return that. - panic!("normalizing free const aliases in the type system is unsupported"); + cx.const_of_item(free_alias.def_id).instantiate(cx, free_alias.args).into() }; - self.instantiate_normalizes_to_term(goal, actual.into()); + self.instantiate_normalizes_to_term(goal, actual); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 2bb1ac8f7426..42aa237762d9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -54,8 +54,7 @@ where let normalized = if inherent.kind(cx).is_type() { cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into() } else { - // FIXME(mgca): Properly handle IACs in the type system - panic!("normalizing inherent associated consts in the type system is unsupported"); + cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).into() }; self.instantiate_normalizes_to_term(goal, normalized); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 0674b3d42ab4..110cc30e740b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -366,19 +366,7 @@ where cx.type_of(target_item_def_id).map_bound(|ty| ty.into()) } ty::AliasTermKind::ProjectionConst => { - // FIXME(mgca): once const items are actual aliases defined as equal to type system consts - // this should instead return that. - if cx.features().associated_const_equality() { - panic!("associated const projection is not supported yet") - } else { - ty::EarlyBinder::bind( - Const::new_error_with_message( - cx, - "associated const projection is not supported yet", - ) - .into(), - ) - } + cx.const_of_item(target_item_def_id).map_bound(|ct| ct.into()) } kind => panic!("expected projection, found {kind:?}"), }; diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 800a599be789..71e9914f93fa 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -333,10 +333,11 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { let res = if free.kind(infcx.tcx).is_type() { infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into() } else { - // FIXME(mgca): once const items are actual aliases defined as equal to type system consts - // this should instead use that rather than evaluating. - super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env) - .super_fold_with(self) + infcx + .tcx + .const_of_item(free.def_id) + .instantiate(infcx.tcx, free.args) + .fold_with(self) .into() }; self.depth -= 1; @@ -436,51 +437,47 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx return ct; } - // Doing "proper" normalization of const aliases is inherently cyclic until const items - // are real aliases instead of having bodies. We gate proper const alias handling behind - // mgca to avoid breaking stable code, though this should become the "main" codepath long - // before mgca is stabilized. + let uv = match ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + _ => return ct.super_fold_with(self), + }; + + // Note that the AssocConst and Const cases are unreachable on stable, + // unless a `min_generic_const_args` feature gate error has already + // been emitted earlier in compilation. // - // FIXME(BoxyUwU): Enabling this by default is blocked on a refactoring to how const items - // are represented. - if tcx.features().min_generic_const_args() { - let uv = match ct.kind() { - ty::ConstKind::Unevaluated(uv) => uv, - _ => return ct.super_fold_with(self), - }; - - let ct = match tcx.def_kind(uv.def) { - DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) { - DefKind::Trait => self.normalize_trait_projection(uv.into()), - DefKind::Impl { of_trait: false } => { - self.normalize_inherent_projection(uv.into()) - } - kind => unreachable!( - "unexpected `DefKind` for const alias' resolution's parent def: {:?}", - kind - ), - }, - DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()), - kind => { - unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind) + // That's because we can only end up with an Unevaluated ty::Const for a const item + // if it was marked with `#[type_const]`. Using this attribute without the mgca + // feature gate causes a parse error. + let ct = match tcx.def_kind(uv.def) { + DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) { + DefKind::Trait => self.normalize_trait_projection(uv.into()).expect_const(), + DefKind::Impl { of_trait: false } => { + self.normalize_inherent_projection(uv.into()).expect_const() } - }; + kind => unreachable!( + "unexpected `DefKind` for const alias' resolution's parent def: {:?}", + kind + ), + }, + DefKind::Const => self.normalize_free_alias(uv.into()).expect_const(), + DefKind::AnonConst => { + let ct = ct.super_fold_with(self); + super::with_replaced_escaping_bound_vars( + self.selcx.infcx, + &mut self.universes, + ct, + |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env), + ) + } + kind => { + unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind) + } + }; - // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be - // unnormalized after const evaluation returns. - ct.expect_const().super_fold_with(self) - } else { - let ct = ct.super_fold_with(self); - return super::with_replaced_escaping_bound_vars( - self.selcx.infcx, - &mut self.universes, - ct, - |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env), - ) - .super_fold_with(self); - // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be - // unnormalized after const evaluation returns. - } + // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be + // unnormalized after const evaluation returns. + ct.super_fold_with(self) } #[inline] diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index fea4b7cec62b..0906284e7019 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -546,7 +546,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( let term: Term<'tcx> = if alias_term.kind(tcx).is_type() { tcx.type_of(alias_term.def_id).instantiate(tcx, args).into() } else { - get_associated_const_value(selcx, alias_term.to_term(tcx).expect_const(), param_env).into() + tcx.const_of_item(alias_term.def_id).instantiate(tcx, args).into() }; let mut term = selcx.infcx.resolve_vars_if_possible(term); @@ -2034,14 +2034,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let term = if obligation.predicate.kind(tcx).is_type() { tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into()) } else { - ty::EarlyBinder::bind( - get_associated_const_value( - selcx, - obligation.predicate.to_term(tcx).expect_const(), - param_env, - ) - .into(), - ) + tcx.const_of_item(assoc_term.item.def_id).map_bound(|ct| ct.into()) }; let progress = if !tcx.check_args_compatible(assoc_term.item.def_id, args) { @@ -2133,15 +2126,3 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> { }) } } - -fn get_associated_const_value<'tcx>( - selcx: &mut SelectionContext<'_, 'tcx>, - alias_ct: ty::Const<'tcx>, - param_env: ty::ParamEnv<'tcx>, -) -> ty::Const<'tcx> { - // FIXME(mgca): We shouldn't be invoking ctfe here, instead const items should be aliases to type - // system consts that we can retrieve with some `query const_arg_of_alias` query. Evaluating the - // constant is "close enough" to getting the actual rhs of the const item for now even if it might - // lead to some cycles - super::evaluate_const(selcx.infcx, alias_ct, param_env) -} diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index fd5795c0fbcc..1d7ea9fe00a3 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -89,7 +89,7 @@ fn normalize_canonicalized_free_alias<'tcx>( let normalized_term = if goal.kind(tcx).is_type() { tcx.type_of(goal.def_id).instantiate(tcx, goal.args).into() } else { - todo!() + tcx.const_of_item(goal.def_id).instantiate(tcx, goal.args).into() }; Ok(NormalizationResult { normalized_term }) }, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index cc56201eb086..3884f29a4fc8 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -205,6 +205,7 @@ pub trait Interner: fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder; fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId) -> ty::EarlyBinder; + fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder; type AdtDef: AdtDef; fn adt_def(self, adt_def_id: Self::AdtId) -> Self::AdtDef; diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs index 01cc05f2545f..72c1ab559bdf 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -1,6 +1,12 @@ //@ edition: 2024 -#![feature(associated_const_equality, type_alias_impl_trait, return_type_notation)] +#![feature( + associated_const_equality, + min_generic_const_args, + type_alias_impl_trait, + return_type_notation +)] +#![expect(incomplete_features)] #![allow(refining_impl_trait_internal)] use std::iter; @@ -45,6 +51,7 @@ fn mismatch_2() -> impl Iterator { trait Trait { type Gat; + #[type_const] const ASSOC: i32; fn foo() -> impl Sized; @@ -53,6 +60,7 @@ trait Trait { impl Trait for () { type Gat = (); + #[type_const] const ASSOC: i32 = 3; fn foo() {} @@ -61,6 +69,7 @@ impl Trait for () { impl Trait for u32 { type Gat = (); + #[type_const] const ASSOC: i32 = 4; fn foo() -> u32 { @@ -79,6 +88,7 @@ type MustFail = dyn Iterator; //~| ERROR conflicting associated type bounds trait Trait2 { + #[type_const] const ASSOC: u32; } diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index 1737d0dc5a38..a54425c3a295 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:9:5 + --> $DIR/duplicate-bound-err.rs:15:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -10,7 +10,7 @@ LL | iter::empty::() | +++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:13:5 + --> $DIR/duplicate-bound-err.rs:19:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -21,7 +21,7 @@ LL | iter::empty::() | +++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:17:5 + --> $DIR/duplicate-bound-err.rs:23:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -32,7 +32,7 @@ LL | iter::empty::() | +++++ error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:21:51 + --> $DIR/duplicate-bound-err.rs:27:51 | LL | type Tait1> = impl Copy; | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | type Tait1> = impl Copy; = note: `Tait1` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:23:51 + --> $DIR/duplicate-bound-err.rs:29:51 | LL | type Tait2> = impl Copy; | ^^^^^^^^^ @@ -48,7 +48,7 @@ LL | type Tait2> = impl Copy; = note: `Tait2` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:25:57 + --> $DIR/duplicate-bound-err.rs:31:57 | LL | type Tait3> = impl Copy; | ^^^^^^^^^ @@ -56,7 +56,7 @@ LL | type Tait3> = impl Copy; = note: `Tait3` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:28:14 + --> $DIR/duplicate-bound-err.rs:34:14 | LL | type Tait4 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | type Tait4 = impl Iterator; = note: `Tait4` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:30:14 + --> $DIR/duplicate-bound-err.rs:36:14 | LL | type Tait5 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | type Tait5 = impl Iterator; = note: `Tait5` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:32:14 + --> $DIR/duplicate-bound-err.rs:38:14 | LL | type Tait6 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | type Tait6 = impl Iterator; = note: `Tait6` must be used in combination with a concrete type within the same crate error[E0277]: `*const ()` cannot be sent between threads safely - --> $DIR/duplicate-bound-err.rs:35:18 + --> $DIR/duplicate-bound-err.rs:41:18 | LL | fn mismatch() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely @@ -91,7 +91,7 @@ LL | iter::empty::<*const ()>() = help: the trait `Send` is not implemented for `*const ()` error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/duplicate-bound-err.rs:40:20 + --> $DIR/duplicate-bound-err.rs:46:20 | LL | fn mismatch_2() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` @@ -100,7 +100,7 @@ LL | iter::empty::() | ----------------------- return type was inferred to be `std::iter::Empty` here error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:100:17 + --> $DIR/duplicate-bound-err.rs:110:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -109,7 +109,7 @@ LL | [2u32].into_iter() | ------------------ return type was inferred to be `std::array::IntoIter` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:77:42 + --> $DIR/duplicate-bound-err.rs:86:42 | LL | type MustFail = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -117,7 +117,7 @@ LL | type MustFail = dyn Iterator; | `Item` bound here first error: conflicting associated type bounds for `Item` - --> $DIR/duplicate-bound-err.rs:77:17 + --> $DIR/duplicate-bound-err.rs:86:17 | LL | type MustFail = dyn Iterator; | ^^^^^^^^^^^^^----------^^----------^ @@ -126,7 +126,7 @@ LL | type MustFail = dyn Iterator; | `Item` is specified to be `i32` here error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:85:43 + --> $DIR/duplicate-bound-err.rs:95:43 | LL | type MustFail2 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -134,7 +134,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` bound here first error: conflicting associated type bounds for `ASSOC` - --> $DIR/duplicate-bound-err.rs:85:18 + --> $DIR/duplicate-bound-err.rs:95:18 | LL | type MustFail2 = dyn Trait2; | ^^^^^^^^^^^------------^^------------^ @@ -143,7 +143,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` is specified to be `3` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:89:43 + --> $DIR/duplicate-bound-err.rs:99:43 | LL | type MustFail3 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -151,7 +151,7 @@ LL | type MustFail3 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:92:43 + --> $DIR/duplicate-bound-err.rs:102:43 | LL | type MustFail4 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -159,19 +159,19 @@ LL | type MustFail4 = dyn Trait2; | `ASSOC` bound here first error[E0271]: expected `impl Iterator` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:100:17 + --> $DIR/duplicate-bound-err.rs:110:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | note: required by a bound in `Trait3::foo::{anon_assoc#0}` - --> $DIR/duplicate-bound-err.rs:96:31 + --> $DIR/duplicate-bound-err.rs:106:31 | LL | fn foo() -> impl Iterator; | ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}` error[E0271]: expected `Empty` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:108:16 + --> $DIR/duplicate-bound-err.rs:118:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -179,13 +179,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:71:32 + --> $DIR/duplicate-bound-err.rs:80:32 | LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: expected `Empty` to be an iterator that yields `u32`, but it yields `i32` - --> $DIR/duplicate-bound-err.rs:109:16 + --> $DIR/duplicate-bound-err.rs:119:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32` @@ -193,13 +193,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:71:44 + --> $DIR/duplicate-bound-err.rs:80:44 | LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:110:22 + --> $DIR/duplicate-bound-err.rs:120:22 | LL | uncallable_const(()); | ---------------- ^^ expected `4`, found `3` @@ -209,13 +209,13 @@ LL | uncallable_const(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:73:46 + --> $DIR/duplicate-bound-err.rs:82:46 | LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:111:22 + --> $DIR/duplicate-bound-err.rs:121:22 | LL | uncallable_const(4u32); | ---------------- ^^^^ expected `3`, found `4` @@ -225,13 +225,13 @@ LL | uncallable_const(4u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:73:35 + --> $DIR/duplicate-bound-err.rs:82:35 | LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:112:20 + --> $DIR/duplicate-bound-err.rs:122:20 | LL | uncallable_rtn(()); | -------------- ^^ expected `4`, found `3` @@ -241,13 +241,13 @@ LL | uncallable_rtn(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:75:75 + --> $DIR/duplicate-bound-err.rs:84:75 | LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} | ^^^^^^^^^ required by this bound in `uncallable_rtn` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:113:20 + --> $DIR/duplicate-bound-err.rs:123:20 | LL | uncallable_rtn(17u32); | -------------- ^^^^^ expected `3`, found `4` @@ -257,7 +257,7 @@ LL | uncallable_rtn(17u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:75:48 + --> $DIR/duplicate-bound-err.rs:84:48 | LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} | ^^^^^^^^^ required by this bound in `uncallable_rtn` diff --git a/tests/ui/associated-type-bounds/duplicate-bound.rs b/tests/ui/associated-type-bounds/duplicate-bound.rs index 696710d76f6d..3f40e429260f 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound.rs @@ -1,7 +1,8 @@ //@ edition: 2024 //@ run-pass -#![feature(associated_const_equality, return_type_notation)] +#![feature(associated_const_equality, min_generic_const_args, return_type_notation)] +#![expect(incomplete_features)] #![allow(dead_code, refining_impl_trait_internal, type_alias_bounds)] use std::iter; @@ -188,6 +189,7 @@ trait Tra3 { trait Trait { type Gat; + #[type_const] const ASSOC: i32; fn foo() -> impl Sized; @@ -196,6 +198,7 @@ trait Trait { impl Trait for () { type Gat = (); + #[type_const] const ASSOC: i32 = 3; fn foo() {}