Skip to content

Commit

Permalink
Fix ICE when multiple supertrait substitutions need assoc but only on…
Browse files Browse the repository at this point in the history
…e is provided
  • Loading branch information
compiler-errors committed Dec 4, 2024
1 parent 8e324b4 commit c977f8e
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
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(
tcx.associated_items(pred.def_id())
tcx.associated_items(trait_ref.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| !item.is_impl_trait_in_trait())
// If the associated type has a `where Self: Sized` bound,
// we do not need to constrain the associated type.
.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)) => {
Expand Down Expand Up @@ -180,7 +182,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// corresponding `Projection` clause
for &(projection_bound, span) in &projection_bounds {
let def_id = projection_bound.projection_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) {
tcx.emit_node_span_lint(
UNUSED_ASSOCIATED_TYPE_BOUNDS,
Expand Down
42 changes: 23 additions & 19 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub(crate) fn check_for_required_assoc_tys(
&self,
spans: SmallVec<[Span; 1]>,
missing_assoc_types: FxIndexSet<DefId>,
missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
potential_assoc_types: Vec<usize>,
trait_bounds: &[hir::PolyTraitRef<'_>],
) -> Result<(), ErrorGuaranteed> {
Expand All @@ -729,27 +729,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let principal_span = *spans.first().unwrap();

let tcx = self.tcx();
let missing_assoc_types: Vec<_> =
missing_assoc_types.into_iter().map(|def_id| tcx.associated_item(def_id)).collect();
let mut names: FxIndexMap<String, Vec<Symbol>> = Default::default();
// FIXME: This logic needs some more care w.r.t handling of conflicts
let missing_assoc_types: Vec<_> = missing_assoc_types
.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;

// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
// `issue-22560.rs`.
let mut dyn_compatibility_violations = Ok(());
for assoc_item in &missing_assoc_types {
let trait_def_id = assoc_item.container_id(tcx);
names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
for (assoc_item, trait_ref) in &missing_assoc_types {
names.entry(trait_ref).or_default().push(assoc_item.name);
names_len += 1;

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() {
dyn_compatibility_violations = Err(report_dyn_incompatibility(
tcx,
principal_span,
None,
trait_def_id,
trait_ref.def_id(),
&violations,
)
.emit());
Expand Down Expand Up @@ -800,6 +802,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.into_iter()
.map(|(trait_, mut assocs)| {
assocs.sort();
let trait_ = trait_.print_trait_sugared();
format!("{} in `{trait_}`", match &assocs[..] {
[] => String::new(),
[only] => format!("`{only}`"),
Expand Down Expand Up @@ -827,19 +830,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut already_has_generics_args_suggestion = false;

let mut names: UnordMap<_, usize> = Default::default();
for item in &missing_assoc_types {
for (item, _) in &missing_assoc_types {
types_count += 1;
*names.entry(item.name).or_insert(0) += 1;
}
let mut dupes = 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 trait_def_id = item.container_id(tcx);
let trait_def_id = trait_ref.def_id();
dupes = true;
format!("{}::", tcx.def_path_str(trait_def_id))
} 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;
format!("{}::", tcx.def_path_str(trait_def_id))
} else {
Expand Down Expand Up @@ -878,8 +881,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} else if let (Ok(snippet), false, false) =
(tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
{
let types: Vec<_> =
missing_assoc_types.iter().map(|item| format!("{} = Type", item.name)).collect();
let types: Vec<_> = missing_assoc_types
.iter()
.map(|(item, _)| format!("{} = Type", item.name))
.collect();
let code = if snippet.ends_with('>') {
// 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
Expand Down Expand Up @@ -911,15 +916,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if suggestions.len() != 1 || already_has_generics_args_suggestion {
// We don't need this label if there's an inline suggestion, show otherwise.
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
for item in &missing_assoc_types {
for (item, _) in &missing_assoc_types {
types_count += 1;
*names.entry(item.name).or_insert(0) += 1;
}
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 trait_def_id = item.container_id(tcx);
format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
} else {
String::new()
};
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/associated-types/missing-associated-types.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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> {}`
= 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
|
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

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/dyn-compatibility/assoc_type_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ trait Foo<T> {
trait Cake {}
impl Cake for () {}

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 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<i32>` must be specified

fn main() {}
4 changes: 2 additions & 2 deletions tests/ui/dyn-compatibility/assoc_type_bounds.stderr
Original file line number Diff line number Diff line change
@@ -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
|
LL | type Bar
Expand All @@ -7,7 +7,7 @@ LL | type Bar
LL | fn foo(_: &dyn Foo<()>) {}
| ^^^^^^^ 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
|
LL | type Bar
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/dyn-compatibility/assoc_type_bounds2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ trait Foo<T> {
trait Cake {}
impl Cake for () {}

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 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<i32>` must be specified

fn main() {}
4 changes: 2 additions & 2 deletions tests/ui/dyn-compatibility/assoc_type_bounds2.stderr
Original file line number Diff line number Diff line change
@@ -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
|
LL | type Bar
Expand All @@ -7,7 +7,7 @@ LL | type Bar
LL | fn foo(_: &dyn Foo<()>) {}
| ^^^^^^^ 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
|
LL | type Bar
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.rs
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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`.
4 changes: 2 additions & 2 deletions tests/ui/issues/issue-28344.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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);
| ++++ +

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
|
LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
Expand All @@ -31,7 +31,7 @@ help: if this is a dyn-compatible trait, use `dyn`
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
|
LL | let g = BitXor::bitor;
Expand Down

0 comments on commit c977f8e

Please sign in to comment.