add const_of_item query and use it in normalization
This commit is contained in:
parent
0515aa5a3e
commit
9864a2fbca
16 changed files with 171 additions and 122 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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>>>>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:?}"),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 })
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue