Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions compiler/rustc_error_codes/src/error_codes/E0719.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
An associated type value was specified more than once.
An associated item value was specified more than once in a trait object.

Erroneous code example:

Expand All @@ -7,21 +7,15 @@ trait FooTrait {}
trait BarTrait {}

// error: associated type `Item` in trait `Iterator` is specified twice
struct Foo<T: Iterator<Item: FooTrait, Item: BarTrait>> { f: T }
type Foo = dyn Iterator<Item = u32, Item = u32>;
```

`Item` in trait `Iterator` cannot be specified multiple times for struct `Foo`.
To fix this, create a new trait that is a combination of the desired traits and
specify the associated type with the new trait.
To fix this, remove the duplicate specifier:

Corrected example:

```
trait FooTrait {}
trait BarTrait {}
trait FooBarTrait: FooTrait + BarTrait {}

struct Foo<T: Iterator<Item: FooBarTrait>> { f: T } // ok!
type Foo = dyn Iterator<Item = u32>; // ok!
```

For more information about associated types, see [the book][bk-at]. For more
Expand Down
27 changes: 15 additions & 12 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
param_ty,
bounds,
predicate_filter,
false,
);
}
hir::GenericBound::Outlives(lifetime) => {
Expand Down Expand Up @@ -402,7 +403,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> {
Expand Down Expand Up @@ -458,17 +459,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);
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
dummy_self,
&mut user_written_bounds,
PredicateFilter::SelfOnly,
true,
);
if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
potential_assoc_types.extend(invalid_args);
Expand Down Expand Up @@ -157,10 +158,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,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>,
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
predicate_filter: PredicateFilter,
for_dyn: bool,
) -> GenericArgCountResult {
let tcx = self.tcx();

Expand Down Expand Up @@ -927,7 +928,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
poly_trait_ref,
constraint,
bounds,
&mut dup_constraints,
for_dyn.then_some(&mut dup_constraints),
constraint.span,
predicate_filter,
);
Expand Down
114 changes: 114 additions & 0 deletions tests/ui/associated-type-bounds/duplicate-bound-err.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//@ edition: 2024

#![feature(associated_const_equality, type_alias_impl_trait, return_type_notation)]
#![allow(refining_impl_trait_internal)]

use std::iter;

fn frpit1() -> impl Iterator<Item: Copy, Item: Send> {
iter::empty()
//~^ ERROR type annotations needed
}
fn frpit2() -> impl Iterator<Item: Copy, Item: Copy> {
iter::empty()
//~^ ERROR type annotations needed
}
fn frpit3() -> impl Iterator<Item: 'static, Item: 'static> {
iter::empty()
//~^ ERROR type annotations needed
}

type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
//~^ ERROR unconstrained opaque type
type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
//~^ ERROR unconstrained opaque type
type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
//~^ ERROR unconstrained opaque type

type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
//~^ ERROR unconstrained opaque type
type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
//~^ ERROR unconstrained opaque type
type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
//~^ ERROR unconstrained opaque type

fn mismatch() -> impl Iterator<Item: Copy, Item: Send> {
//~^ ERROR [E0277]
iter::empty::<*const ()>()
}

fn mismatch_2() -> impl Iterator<Item: Copy, Item: Send> {
//~^ ERROR [E0277]
iter::empty::<String>()
}

trait Trait {
type Gat<T>;

const ASSOC: i32;

fn foo() -> impl Sized;
}

impl Trait for () {
type Gat<T> = ();

const ASSOC: i32 = 3;

fn foo() {}
}

impl Trait for u32 {
type Gat<T> = ();

const ASSOC: i32 = 4;

fn foo() -> u32 {
42
}
}

fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}

fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}

fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}

type MustFail = dyn Iterator<Item = i32, Item = u32>;
//~^ ERROR [E0719]
//~| ERROR conflicting associated type bounds

trait Trait2 {
const ASSOC: u32;
}

type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
//~^ ERROR [E0719]
//~| ERROR conflicting associated type bounds

type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
//~^ ERROR [E0719]

type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
//~^ ERROR [E0719]

trait Trait3 {
fn foo() -> impl Iterator<Item = i32, Item = u32>;
}

impl Trait3 for () {
fn foo() -> impl Iterator<Item = i32, Item = u32> {
//~^ ERROR[E0271]
//~| ERROR[E0271]
[2u32].into_iter()
}
}

fn main() {
uncallable(iter::empty::<u32>()); //~ ERROR [E0271]
uncallable(iter::empty::<i32>()); //~ ERROR [E0271]
uncallable_const(()); //~ ERROR [E0271]
uncallable_const(4u32); //~ ERROR [E0271]
uncallable_rtn(()); //~ ERROR [E0271]
uncallable_rtn(17u32); //~ ERROR [E0271]
}
Loading
Loading