add const_of_item query and use it in normalization

This commit is contained in:
Noah Lev 2025-10-14 02:15:16 +01:00
parent 0515aa5a3e
commit 9864a2fbca
16 changed files with 171 additions and 122 deletions

View file

@ -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)
}
}

View file

@ -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) {

View file

@ -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)
{

View file

@ -471,6 +471,7 @@ define_tables! {
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
const_of_item: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::Const<'static>>>>,
associated_types_for_impl_traits_in_trait_or_impl: Table<DefIndex, LazyValue<DefIdMap<Vec<DefId>>>>,
}

View file

@ -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

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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)

View file

@ -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:?}"),
};

View file

@ -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<TyCtxt<'tcx>> 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]

View file

@ -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)
}

View file

@ -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 })
},

View file

@ -205,6 +205,7 @@ pub trait Interner:
fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId)
-> ty::EarlyBinder<Self, Self::Ty>;
fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Const>;
type AdtDef: AdtDef<Self>;
fn adt_def(self, adt_def_id: Self::AdtId) -> Self::AdtDef;

View file

@ -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<Item: Copy, Item: Send> {
trait Trait {
type Gat<T>;
#[type_const]
const ASSOC: i32;
fn foo() -> impl Sized;
@ -53,6 +60,7 @@ trait Trait {
impl Trait for () {
type Gat<T> = ();
#[type_const]
const ASSOC: i32 = 3;
fn foo() {}
@ -61,6 +69,7 @@ impl Trait for () {
impl Trait for u32 {
type Gat<T> = ();
#[type_const]
const ASSOC: i32 = 4;
fn foo() -> u32 {
@ -79,6 +88,7 @@ type MustFail = dyn Iterator<Item = i32, Item = u32>;
//~| ERROR conflicting associated type bounds
trait Trait2 {
#[type_const]
const ASSOC: u32;
}

View file

@ -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::<T>()
| +++++
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::<T>()
| +++++
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::<T>()
| +++++
error: unconstrained opaque type
--> $DIR/duplicate-bound-err.rs:21:51
--> $DIR/duplicate-bound-err.rs:27:51
|
LL | type Tait1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
| ^^^^^^^^^
@ -40,7 +40,7 @@ LL | type Tait1<T: Iterator<Item: Copy, Item: Send>> = 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<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
| ^^^^^^^^^
@ -48,7 +48,7 @@ LL | type Tait2<T: Iterator<Item: Copy, Item: Copy>> = 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<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
| ^^^^^^^^^
@ -56,7 +56,7 @@ LL | type Tait3<T: Iterator<Item: 'static, Item: 'static>> = 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<Item: Copy, Item: Send>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -64,7 +64,7 @@ LL | type Tait4 = impl Iterator<Item: Copy, Item: Send>;
= 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<Item: Copy, Item: Copy>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -72,7 +72,7 @@ LL | type Tait5 = impl Iterator<Item: Copy, Item: Copy>;
= 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<Item: 'static, Item: 'static>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -80,7 +80,7 @@ LL | type Tait6 = impl Iterator<Item: 'static, Item: 'static>;
= 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<Item: Copy, Item: Send> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*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<Item: Copy, Item: Send> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
@ -100,7 +100,7 @@ LL | iter::empty::<String>()
| ----------------------- return type was inferred to be `std::iter::Empty<String>` here
error[E0271]: expected `IntoIter<u32, 1>` 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<Item = i32, Item = u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
@ -109,7 +109,7 @@ LL | [2u32].into_iter()
| ------------------ return type was inferred to be `std::array::IntoIter<u32, 1>` 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<Item = i32, Item = u32>;
| ---------- ^^^^^^^^^^ re-bound here
@ -117,7 +117,7 @@ LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
| `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<Item = i32, Item = u32>;
| ^^^^^^^^^^^^^----------^^----------^
@ -126,7 +126,7 @@ LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
| `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<ASSOC = 3u32, ASSOC = 4u32>;
| ------------ ^^^^^^^^^^^^ re-bound here
@ -134,7 +134,7 @@ LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
| `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<ASSOC = 3u32, ASSOC = 4u32>;
| ^^^^^^^^^^^------------^^------------^
@ -143,7 +143,7 @@ LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
| `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<Item = i32, Item = i32>;
| ---------- ^^^^^^^^^^ re-bound here
@ -151,7 +151,7 @@ LL | type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
| `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<ASSOC = 3u32, ASSOC = 3u32>;
| ------------ ^^^^^^^^^^^^ re-bound here
@ -159,19 +159,19 @@ LL | type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
| `ASSOC` bound here first
error[E0271]: expected `impl Iterator<Item = u32>` 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<Item = i32, Item = u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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<Item = i32, Item = u32>;
| ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}`
error[E0271]: expected `Empty<u32>` 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::<u32>());
| ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
@ -179,13 +179,13 @@ LL | uncallable(iter::empty::<u32>());
| 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<Item = i32, Item = u32>) {}
| ^^^^^^^^^^ required by this bound in `uncallable`
error[E0271]: expected `Empty<i32>` 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::<i32>());
| ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
@ -193,13 +193,13 @@ LL | uncallable(iter::empty::<i32>());
| 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<Item = i32, Item = u32>) {}
| ^^^^^^^^^^ 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<ASSOC = 3, ASSOC = 4>) {}
| ^^^^^^^^^ required by this bound in `uncallable_const`
error[E0271]: type mismatch resolving `<u32 as Trait>::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<ASSOC = 3, ASSOC = 4>) {}
| ^^^^^^^^^ 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<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
| ^^^^^^^^^ required by this bound in `uncallable_rtn`
error[E0271]: type mismatch resolving `<u32 as Trait>::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<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
| ^^^^^^^^^ required by this bound in `uncallable_rtn`

View file

@ -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<T>;
#[type_const]
const ASSOC: i32;
fn foo() -> impl Sized;
@ -196,6 +198,7 @@ trait Trait {
impl Trait for () {
type Gat<T> = ();
#[type_const]
const ASSOC: i32 = 3;
fn foo() {}