Skip to content

Allow specifying multiple bounds for same associated item (remove E0719) #143146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
4 changes: 3 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0719.md
Copy link
Member

@fmease fmease Jun 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(commenting on a random file so it's threaded)

Thanks for incorporating my suggestion about adding more tests!

What are the interactions with trait object types? It's possible that lower_trait_object_ty still ends up rejecting such dyn-Traits (e.g., dyn Trait<X = i32, X = u64>) due to its intricate and delicate logic but I might not be right. For example, we currently reject:

#![feature(trait_alias)]
trait Iter = Iterator<Item = ()>;
fn f(_: Box<dyn Iter<Item = u64>>) {} //~ ERROR conflicting associated type bounds for `Item` when expanding trait alias

I'm curious about whether that gets triggered for sth. like dyn Trait<X = i32, X = u64> 🤔 If not, I wonder if we should then also lift this trait alias restriction?

I don't know the soundness implications of allowing these equality predicates in trait object types since I haven't spent much thought on it. In my mind, a trait object type with "impossible" existential projection predicates should be fine, it would just be impossible to construct a value of it. Anyhow, I'm not qualified enough to draw a proper conclusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! It looks like we do trigger that error. I added tests, and tweaked the error message to be more generic.

Interestingly, it seems that if you do:

trait Sup {
    type Assoc;
}

trait Sub: Sup<Assoc = u32> {}

type Foo = dyn Sub<Assoc = i32>;

Then no error is emitted, but Foo does not implement Sub.

Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#### Note: this error code is no longer emitted by the compiler.

An associated type value was specified more than once.

Erroneous code example:

```compile_fail,E0719
```
trait FooTrait {}
trait BarTrait {}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ E0716: 0716,
E0711: 0711,
E0717: 0717,
E0718: 0718,
E0719: 0719,
E0719: 0719, // REMOVED: no longer an error
E0720: 0720,
E0722: 0722,
E0724: 0724,
Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -600,11 +600,6 @@ hir_analysis_unused_generic_parameter_ty_alias_help =

hir_analysis_useless_impl_item = this item cannot be used as its where bounds are not satisfied for the `Self` type

hir_analysis_value_of_associated_struct_already_specified =
the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified
.label = re-bound here
.previous_bound_label = `{$item_name}` bound here first

hir_analysis_variadic_function_compatible_convention = C-variadic functions with the {$convention} calling convention are not supported
.label = C-variadic function must have a compatible calling convention

Expand Down
12 changes: 0 additions & 12 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,18 +401,6 @@ pub(crate) struct TypeofReservedKeywordUsed<'tcx> {
pub opt_sugg: Option<(Span, Applicability)>,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_value_of_associated_struct_already_specified, code = E0719)]
pub(crate) struct ValueOfAssociatedStructAlreadySpecified {
#[primary_span]
#[label]
pub span: Span,
#[label(hir_analysis_previous_bound_label)]
pub prev_span: Span,
pub item_name: Ident,
pub def_path: String,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_unconstrained_opaque_type)]
#[note]
Expand Down
17 changes: 2 additions & 15 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::ops::ControlFlow;

use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::codes::*;
use rustc_errors::struct_span_code_err;
use rustc_hir as hir;
Expand Down Expand Up @@ -524,14 +524,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// the `trait_ref` here will be `for<'a> T: Iterator`.
/// The `constraint` data however is from *inside* the binder
/// (e.g., `&'a u32`) and hence may reference bound regions.
#[instrument(level = "debug", skip(self, bounds, duplicates, path_span))]
#[instrument(level = "debug", skip(self, bounds, path_span))]
pub(super) fn lower_assoc_item_constraint(
&self,
hir_ref_id: hir::HirId,
trait_ref: ty::PolyTraitRef<'tcx>,
constraint: &hir::AssocItemConstraint<'tcx>,
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
duplicates: &mut FxIndexMap<DefId, Span>,
path_span: Span,
predicate_filter: PredicateFilter,
) -> Result<(), ErrorGuaranteed> {
Expand Down Expand Up @@ -587,18 +586,6 @@ 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);

let projection_term = if let ty::AssocTag::Fn = assoc_tag {
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
ty::Binder::bind_with_vars(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,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
5 changes: 1 addition & 4 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use std::assert_matches::assert_matches;
use std::slice;

use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err,
Expand Down Expand Up @@ -801,7 +801,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
poly_trait_ref,
constraint,
&mut Default::default(),
&mut Default::default(),
constraint.span,
predicate_filter,
);
Expand Down Expand Up @@ -907,7 +906,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}

let mut dup_constraints = 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
Expand All @@ -926,7 +924,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
poly_trait_ref,
constraint,
bounds,
&mut dup_constraints,
constraint.span,
predicate_filter,
);
Expand Down
Loading
Loading