Rollup merge of #146593 - Jules-Bertholet:restrict-e0719, r=BoxyUwU
Allow specifying multiple bounds for same associated item, except in trait objects Supersedes https://github.com/rust-lang/rust/pull/143146, fixes https://github.com/rust-lang/rust/issues/143143. This PR proposes to stop enforcing E0719 in all contexts other than trait object types. E0719 forbids constraining the same associated item twice within the same angle-bracket delimited associated item bound list (the `…` inside `T: Trait<…>`). For example, the following are forbidden: | Forbidden | Working alternative | |--------------------------------------------|--------------------------------------------------------------------| | `T: Trait<Gat<u32> = u32, Gat<u64> = u64>` | `T: Trait<Gat<u32> = u32> + Trait<Gat<u64> = u64>` | | `T: Iterator<Item = u32, Item = i32>` | `T: Iterator<Item = u32> + Iterator<Item = i32>` (trivially false) | | `T: Iterator<Item = u32, Item = u32>` | `T: Iterator<Item = u32>` | | `T: Iterator<Item: Send, Item: Sync>` | `T: Iterator<Item: Send + Sync>` | | `T: Trait<ASSOC = 3, ASSOC = 4>` | `T: Trait<ASSOC = 3> + Trait<ASSOC = 4>` (trivially false) | | `T: Trait<ASSOC = 3, ASSOC = 3>` | `T: Trait<ASSOC = 3>` | With this PR, all those previously forbidden examples would start working, as well as their APIT and RPIT equivalents. Types like `dyn Iterator<Item = u32, Item = u32>` will continue to be rejected, however. See https://github.com/rust-lang/rust/pull/143146#issuecomment-3274421752 for the reason why. ```@rustbot``` label T-lang T-types needs-fcp
This commit is contained in:
@@ -12,7 +12,7 @@ use tracing::{debug, instrument};
|
||||
|
||||
use super::ItemCtxt;
|
||||
use super::predicates_of::assert_only_contains_predicates_from;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter};
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter};
|
||||
|
||||
/// For associated types we include both bounds written on the type
|
||||
/// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
|
||||
@@ -37,7 +37,14 @@ fn associated_type_bounds<'tcx>(
|
||||
|
||||
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||
icx.lowerer().lower_bounds(
|
||||
item_ty,
|
||||
hir_bounds,
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
@@ -347,7 +354,14 @@ fn opaque_type_bounds<'tcx>(
|
||||
ty::print::with_reduced_queries!({
|
||||
let icx = ItemCtxt::new(tcx, opaque_def_id);
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||
icx.lowerer().lower_bounds(
|
||||
item_ty,
|
||||
hir_bounds,
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
// Implicit bounds are added to opaque types unless a `?Trait` bound is found
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
|
||||
@@ -18,7 +18,9 @@ use super::item_bounds::explicit_item_bounds_with_filter;
|
||||
use crate::collect::ItemCtxt;
|
||||
use crate::constrained_generic_params as cgp;
|
||||
use crate::delegation::inherit_predicates_for_delegation_item;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason};
|
||||
use crate::hir_ty_lowering::{
|
||||
HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason,
|
||||
};
|
||||
|
||||
/// Returns a list of all type predicates (explicit and implicit) for the definition with
|
||||
/// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus
|
||||
@@ -187,6 +189,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::All,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
icx.lowerer().add_sizedness_bounds(
|
||||
&mut bounds,
|
||||
@@ -289,6 +292,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
&mut bounds,
|
||||
bound_vars,
|
||||
PredicateFilter::All,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
predicates.extend(bounds);
|
||||
}
|
||||
@@ -659,7 +663,14 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
|
||||
|
||||
let self_param_ty = tcx.types.self_param;
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter);
|
||||
icx.lowerer().lower_bounds(
|
||||
self_param_ty,
|
||||
superbounds,
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
| PredicateFilter::SelfOnly
|
||||
@@ -984,6 +995,7 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||
&mut bounds,
|
||||
bound_vars,
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1063,6 +1075,7 @@ pub(super) fn const_conditions<'tcx>(
|
||||
&mut bounds,
|
||||
bound_vars,
|
||||
PredicateFilter::ConstIfConst,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
@@ -1083,6 +1096,7 @@ pub(super) fn const_conditions<'tcx>(
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::ConstIfConst,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ use tracing::{debug, instrument};
|
||||
use super::errors::GenericsArgsErrExtend;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{
|
||||
AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason,
|
||||
AssocItemQSelf, FeedConstTy, HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter,
|
||||
RegionInferReason,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@@ -338,6 +339,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
|
||||
predicate_filter: PredicateFilter,
|
||||
overlapping_assoc_constraints: OverlappingAsssocItemConstraints,
|
||||
) where
|
||||
'tcx: 'hir,
|
||||
{
|
||||
@@ -362,6 +364,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
param_ty,
|
||||
bounds,
|
||||
predicate_filter,
|
||||
overlapping_assoc_constraints,
|
||||
);
|
||||
}
|
||||
hir::GenericBound::Outlives(lifetime) => {
|
||||
@@ -402,7 +405,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
constraint: &hir::AssocItemConstraint<'tcx>,
|
||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
duplicates: &mut FxIndexMap<DefId, Span>,
|
||||
duplicates: Option<&mut FxIndexMap<DefId, Span>>,
|
||||
path_span: Span,
|
||||
predicate_filter: PredicateFilter,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
@@ -458,17 +461,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
)
|
||||
.expect("failed to find associated item");
|
||||
|
||||
duplicates
|
||||
.entry(assoc_item.def_id)
|
||||
.and_modify(|prev_span| {
|
||||
self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
|
||||
span: constraint.span,
|
||||
prev_span: *prev_span,
|
||||
item_name: constraint.ident,
|
||||
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
|
||||
});
|
||||
})
|
||||
.or_insert(constraint.span);
|
||||
if let Some(duplicates) = duplicates {
|
||||
duplicates
|
||||
.entry(assoc_item.def_id)
|
||||
.and_modify(|prev_span| {
|
||||
self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
|
||||
span: constraint.span,
|
||||
prev_span: *prev_span,
|
||||
item_name: constraint.ident,
|
||||
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
|
||||
});
|
||||
})
|
||||
.or_insert(constraint.span);
|
||||
}
|
||||
|
||||
let projection_term = if let ty::AssocTag::Fn = assoc_tag {
|
||||
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
|
||||
@@ -600,6 +605,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
bounds,
|
||||
projection_ty.bound_vars(),
|
||||
predicate_filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
PredicateFilter::SelfOnly
|
||||
|
||||
@@ -23,7 +23,9 @@ use tracing::{debug, instrument};
|
||||
|
||||
use super::HirTyLowerer;
|
||||
use crate::errors::SelfInTypeAlias;
|
||||
use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason};
|
||||
use crate::hir_ty_lowering::{
|
||||
GenericArgCountMismatch, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason,
|
||||
};
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// Lower a trait object type from the HIR to our internal notion of a type.
|
||||
@@ -60,6 +62,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
dummy_self,
|
||||
&mut user_written_bounds,
|
||||
PredicateFilter::SelfOnly,
|
||||
OverlappingAsssocItemConstraints::Forbidden,
|
||||
);
|
||||
if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
|
||||
potential_assoc_types.extend(invalid_args);
|
||||
@@ -157,10 +160,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
self.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
format!(
|
||||
"conflicting associated type bounds for `{item}` when \
|
||||
expanding trait alias"
|
||||
),
|
||||
format!("conflicting associated type bounds for `{item}`"),
|
||||
)
|
||||
.with_span_label(
|
||||
old_proj_span,
|
||||
|
||||
@@ -332,6 +332,15 @@ pub(crate) enum GenericArgPosition {
|
||||
MethodCall,
|
||||
}
|
||||
|
||||
/// Whether to allow duplicate associated iten constraints in a trait ref, e.g.
|
||||
/// `Trait<Assoc = Ty, Assoc = Ty>`. This is forbidden in `dyn Trait<...>`
|
||||
/// but allowed everywhere else.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub(crate) enum OverlappingAsssocItemConstraints {
|
||||
Allowed,
|
||||
Forbidden,
|
||||
}
|
||||
|
||||
/// A marker denoting that the generic arguments that were
|
||||
/// provided did not match the respective generic parameters.
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -752,6 +761,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
self_ty: Ty<'tcx>,
|
||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
predicate_filter: PredicateFilter,
|
||||
overlapping_assoc_item_constraints: OverlappingAsssocItemConstraints,
|
||||
) -> GenericArgCountResult {
|
||||
let tcx = self.tcx();
|
||||
|
||||
@@ -908,7 +918,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
}
|
||||
|
||||
let mut dup_constraints = FxIndexMap::default();
|
||||
let mut dup_constraints = (overlapping_assoc_item_constraints
|
||||
== OverlappingAsssocItemConstraints::Forbidden)
|
||||
.then_some(FxIndexMap::default());
|
||||
|
||||
for constraint in trait_segment.args().constraints {
|
||||
// Don't register any associated item constraints for negative bounds,
|
||||
// since we should have emitted an error for them earlier, and they
|
||||
@@ -927,7 +940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
poly_trait_ref,
|
||||
constraint,
|
||||
bounds,
|
||||
&mut dup_constraints,
|
||||
dup_constraints.as_mut(),
|
||||
constraint.span,
|
||||
predicate_filter,
|
||||
);
|
||||
@@ -2484,6 +2497,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::All,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
self.add_sizedness_bounds(
|
||||
&mut bounds,
|
||||
|
||||
Reference in New Issue
Block a user