1
Fork 0

Fix ICE when multiple supertrait substitutions need assoc but only one is provided

This commit is contained in:
Michael Goulet 2024-11-23 18:46:50 +00:00
parent 25a7fdf5bc
commit 43e2fd5086
10 changed files with 71 additions and 35 deletions

View file

@ -145,16 +145,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let bound_predicate = pred.kind(); let bound_predicate = pred.kind();
match bound_predicate.skip_binder() { match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
let pred = bound_predicate.rebind(pred); // FIXME(negative_bounds): Handle this correctly...
let trait_ref =
tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
needed_associated_types.extend( needed_associated_types.extend(
tcx.associated_items(pred.def_id()) tcx.associated_items(trait_ref.def_id())
.in_definition_order() .in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type) .filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| !item.is_impl_trait_in_trait())
// If the associated type has a `where Self: Sized` bound, // If the associated type has a `where Self: Sized` bound,
// we do not need to constrain the associated type. // we do not need to constrain the associated type.
.filter(|item| !tcx.generics_require_sized_self(item.def_id)) .filter(|item| !tcx.generics_require_sized_self(item.def_id))
.map(|item| item.def_id), .map(|item| (item.def_id, trait_ref)),
); );
} }
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
@ -206,7 +208,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// corresponding `Projection` clause // corresponding `Projection` clause
for (projection_bound, span) in &projection_bounds { for (projection_bound, span) in &projection_bounds {
let def_id = projection_bound.item_def_id(); let def_id = projection_bound.item_def_id();
needed_associated_types.swap_remove(&def_id); let trait_ref = tcx.anonymize_bound_vars(
projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
);
needed_associated_types.swap_remove(&(def_id, trait_ref));
if tcx.generics_require_sized_self(def_id) { if tcx.generics_require_sized_self(def_id) {
tcx.emit_node_span_lint( tcx.emit_node_span_lint(
UNUSED_ASSOCIATED_TYPE_BOUNDS, UNUSED_ASSOCIATED_TYPE_BOUNDS,

View file

@ -723,7 +723,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub(crate) fn check_for_required_assoc_tys( pub(crate) fn check_for_required_assoc_tys(
&self, &self,
principal_span: Span, principal_span: Span,
missing_assoc_types: FxIndexSet<DefId>, missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
potential_assoc_types: Vec<usize>, potential_assoc_types: Vec<usize>,
trait_bounds: &[hir::PolyTraitRef<'_>], trait_bounds: &[hir::PolyTraitRef<'_>],
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
@ -732,27 +732,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} }
let tcx = self.tcx(); let tcx = self.tcx();
let missing_assoc_types: Vec<_> = // FIXME: This logic needs some more care w.r.t handling of conflicts
missing_assoc_types.into_iter().map(|def_id| tcx.associated_item(def_id)).collect(); let missing_assoc_types: Vec<_> = missing_assoc_types
let mut names: FxIndexMap<String, Vec<Symbol>> = Default::default(); .into_iter()
.map(|(def_id, trait_ref)| (tcx.associated_item(def_id), trait_ref))
.collect();
let mut names: FxIndexMap<_, Vec<Symbol>> = Default::default();
let mut names_len = 0; let mut names_len = 0;
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
// `issue-22560.rs`. // `issue-22560.rs`.
let mut dyn_compatibility_violations = Ok(()); let mut dyn_compatibility_violations = Ok(());
for assoc_item in &missing_assoc_types { for (assoc_item, trait_ref) in &missing_assoc_types {
let trait_def_id = assoc_item.container_id(tcx); names.entry(trait_ref).or_default().push(assoc_item.name);
names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
names_len += 1; names_len += 1;
let violations = let violations =
dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item); dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), *assoc_item);
if !violations.is_empty() { if !violations.is_empty() {
dyn_compatibility_violations = Err(report_dyn_incompatibility( dyn_compatibility_violations = Err(report_dyn_incompatibility(
tcx, tcx,
principal_span, principal_span,
None, None,
trait_def_id, trait_ref.def_id(),
&violations, &violations,
) )
.emit()); .emit());
@ -803,6 +805,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.into_iter() .into_iter()
.map(|(trait_, mut assocs)| { .map(|(trait_, mut assocs)| {
assocs.sort(); assocs.sort();
let trait_ = trait_.print_trait_sugared();
format!("{} in `{trait_}`", match &assocs[..] { format!("{} in `{trait_}`", match &assocs[..] {
[] => String::new(), [] => String::new(),
[only] => format!("`{only}`"), [only] => format!("`{only}`"),
@ -830,19 +833,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut already_has_generics_args_suggestion = false; let mut already_has_generics_args_suggestion = false;
let mut names: UnordMap<_, usize> = Default::default(); let mut names: UnordMap<_, usize> = Default::default();
for item in &missing_assoc_types { for (item, _) in &missing_assoc_types {
types_count += 1; types_count += 1;
*names.entry(item.name).or_insert(0) += 1; *names.entry(item.name).or_insert(0) += 1;
} }
let mut dupes = false; let mut dupes = false;
let mut shadows = false; let mut shadows = false;
for item in &missing_assoc_types { for (item, trait_ref) in &missing_assoc_types {
let prefix = if names[&item.name] > 1 { let prefix = if names[&item.name] > 1 {
let trait_def_id = item.container_id(tcx); let trait_def_id = trait_ref.def_id();
dupes = true; dupes = true;
format!("{}::", tcx.def_path_str(trait_def_id)) format!("{}::", tcx.def_path_str(trait_def_id))
} else if bound_names.get(&item.name).is_some_and(|x| *x != item) { } else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
let trait_def_id = item.container_id(tcx); let trait_def_id = trait_ref.def_id();
shadows = true; shadows = true;
format!("{}::", tcx.def_path_str(trait_def_id)) format!("{}::", tcx.def_path_str(trait_def_id))
} else { } else {
@ -881,8 +884,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} else if let (Ok(snippet), false, false) = } else if let (Ok(snippet), false, false) =
(tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows) (tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
{ {
let types: Vec<_> = let types: Vec<_> = missing_assoc_types
missing_assoc_types.iter().map(|item| format!("{} = Type", item.name)).collect(); .iter()
.map(|(item, _)| format!("{} = Type", item.name))
.collect();
let code = if snippet.ends_with('>') { let code = if snippet.ends_with('>') {
// The user wrote `Trait<'a>` or similar and we don't have a type we can // The user wrote `Trait<'a>` or similar and we don't have a type we can
// suggest, but at least we can clue them to the correct syntax // suggest, but at least we can clue them to the correct syntax
@ -914,15 +919,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if suggestions.len() != 1 || already_has_generics_args_suggestion { if suggestions.len() != 1 || already_has_generics_args_suggestion {
// We don't need this label if there's an inline suggestion, show otherwise. // We don't need this label if there's an inline suggestion, show otherwise.
let mut names: FxIndexMap<_, usize> = FxIndexMap::default(); let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
for item in &missing_assoc_types { for (item, _) in &missing_assoc_types {
types_count += 1; types_count += 1;
*names.entry(item.name).or_insert(0) += 1; *names.entry(item.name).or_insert(0) += 1;
} }
let mut label = vec![]; let mut label = vec![];
for item in &missing_assoc_types { for (item, trait_ref) in &missing_assoc_types {
let postfix = if names[&item.name] > 1 { let postfix = if names[&item.name] > 1 {
let trait_def_id = item.container_id(tcx); format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
} else { } else {
String::new() String::new()
}; };

View file

@ -42,11 +42,11 @@ LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + Fine<Rhs> {}` = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + Fine<Rhs> {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0191]: the value of the associated types `Output` in `Div`, `Output` in `Mul` must be specified error[E0191]: the value of the associated types `Output` in `Div<Rhs>`, `Output` in `Mul<Rhs>` must be specified
--> $DIR/missing-associated-types.rs:20:21 --> $DIR/missing-associated-types.rs:20:21
| |
LL | type Bal<Rhs> = dyn X<Rhs>; LL | type Bal<Rhs> = dyn X<Rhs>;
| ^^^^^^ associated types `Output` (from trait `Div`), `Output` (from trait `Mul`) must be specified | ^^^^^^ associated types `Output` (from trait `Div<Rhs>`), `Output` (from trait `Mul<Rhs>`) must be specified
| |
= help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types

View file

@ -7,7 +7,7 @@ trait Foo<T> {
trait Cake {} trait Cake {}
impl Cake for () {} impl Cake for () {}
fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<()>` must be specified
fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<i32>` must be specified
fn main() {} fn main() {}

View file

@ -1,4 +1,4 @@
error[E0191]: the value of the associated type `Bar` in `Foo` must be specified error[E0191]: the value of the associated type `Bar` in `Foo<()>` must be specified
--> $DIR/assoc_type_bounds.rs:10:16 --> $DIR/assoc_type_bounds.rs:10:16
| |
LL | type Bar LL | type Bar
@ -7,7 +7,7 @@ LL | type Bar
LL | fn foo(_: &dyn Foo<()>) {} LL | fn foo(_: &dyn Foo<()>) {}
| ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>` | ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>`
error[E0191]: the value of the associated type `Bar` in `Foo` must be specified error[E0191]: the value of the associated type `Bar` in `Foo<i32>` must be specified
--> $DIR/assoc_type_bounds.rs:11:16 --> $DIR/assoc_type_bounds.rs:11:16
| |
LL | type Bar LL | type Bar

View file

@ -7,7 +7,7 @@ trait Foo<T> {
trait Cake {} trait Cake {}
impl Cake for () {} impl Cake for () {}
fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<()>` must be specified
fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<i32>` must be specified
fn main() {} fn main() {}

View file

@ -1,4 +1,4 @@
error[E0191]: the value of the associated type `Bar` in `Foo` must be specified error[E0191]: the value of the associated type `Bar` in `Foo<()>` must be specified
--> $DIR/assoc_type_bounds2.rs:10:16 --> $DIR/assoc_type_bounds2.rs:10:16
| |
LL | type Bar LL | type Bar
@ -7,7 +7,7 @@ LL | type Bar
LL | fn foo(_: &dyn Foo<()>) {} LL | fn foo(_: &dyn Foo<()>) {}
| ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>` | ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>`
error[E0191]: the value of the associated type `Bar` in `Foo` must be specified error[E0191]: the value of the associated type `Bar` in `Foo<i32>` must be specified
--> $DIR/assoc_type_bounds2.rs:11:16 --> $DIR/assoc_type_bounds2.rs:11:16
| |
LL | type Bar LL | type Bar

View file

@ -0,0 +1,15 @@
trait Sup<T> {
type Assoc: Default;
}
impl<T: Default> Sup<T> for () {
type Assoc = T;
}
impl<T: Default, U: Default> Dyn<T, U> for () {}
trait Dyn<A, B>: Sup<A, Assoc = A> + Sup<B> {}
fn main() {
let q: <dyn Dyn<i32, u32> as Sup<u32>>::Assoc = Default::default();
//~^ ERROR the value of the associated type `Assoc` in `Sup<u32>` must be specified
}

View file

@ -0,0 +1,12 @@
error[E0191]: the value of the associated type `Assoc` in `Sup<u32>` must be specified
--> $DIR/require-assoc-for-all-super-substs.rs:13:17
|
LL | type Assoc: Default;
| ------------------- `Assoc` defined here
...
LL | let q: <dyn Dyn<i32, u32> as Sup<u32>>::Assoc = Default::default();
| ^^^^^^^^^^^^^ help: specify the associated type: `Dyn<i32, u32, Assoc = Type>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0191`.

View file

@ -12,7 +12,7 @@ help: if this is a dyn-compatible trait, use `dyn`
LL | let x: u8 = <dyn BitXor>::bitor(0 as u8, 0 as u8); LL | let x: u8 = <dyn BitXor>::bitor(0 as u8, 0 as u8);
| ++++ + | ++++ +
error[E0191]: the value of the associated type `Output` in `BitXor` must be specified error[E0191]: the value of the associated type `Output` in `BitXor<_>` must be specified
--> $DIR/issue-28344.rs:4:17 --> $DIR/issue-28344.rs:4:17
| |
LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
@ -31,7 +31,7 @@ help: if this is a dyn-compatible trait, use `dyn`
LL | let g = <dyn BitXor>::bitor; LL | let g = <dyn BitXor>::bitor;
| ++++ + | ++++ +
error[E0191]: the value of the associated type `Output` in `BitXor` must be specified error[E0191]: the value of the associated type `Output` in `BitXor<_>` must be specified
--> $DIR/issue-28344.rs:9:13 --> $DIR/issue-28344.rs:9:13
| |
LL | let g = BitXor::bitor; LL | let g = BitXor::bitor;