1
Fork 0

Detect object safety errors when assoc type is missing

When an associated type with GATs isn't specified in a `dyn Trait`, emit
an object safety error instead of only complaining about the missing
associated type, as it will lead the user down a path of three different
errors before letting them know that what they were trying to do is
impossible to begin with.

Fix #103155.
This commit is contained in:
Esteban Küber 2023-10-04 01:10:51 +00:00
parent 6d1fc53cf4
commit 17a6ae2df3
36 changed files with 223 additions and 194 deletions

View file

@ -3,6 +3,7 @@ use crate::errors::{
AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
ParenthesizedFnTraitExpansion,
};
use crate::traits::error_reporting::report_object_safety_error;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
@ -13,6 +14,7 @@ use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
use std::collections::BTreeSet;
@ -520,24 +522,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
})
.collect();
let mut names = vec![];
let mut names: FxHashMap<String, 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 trait_bound_spans: Vec<Span> = vec![];
let mut object_safety_violations = false;
for (span, items) in &associated_types {
if !items.is_empty() {
trait_bound_spans.push(*span);
}
for assoc_item in items {
let trait_def_id = assoc_item.container_id(tcx);
names.push(format!(
"`{}` (from trait `{}`)",
assoc_item.name,
tcx.def_path_str(trait_def_id),
));
names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
names_len += 1;
let violations =
object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
if !violations.is_empty() {
report_object_safety_error(tcx, *span, trait_def_id, &violations).emit();
object_safety_violations = true;
}
}
}
if object_safety_violations {
return;
}
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
match bound.trait_ref.path.segments {
// FIXME: `trait_ref.path.span` can point to a full path with multiple
@ -573,15 +584,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
_ => {}
}
}
names.sort();
let names = names
.into_iter()
.map(|(trait_, assocs)| {
format!(
"{} in `{trait_}`",
match &assocs[..] {
[] => String::new(),
[only] => format!("`{only}`"),
[assocs @ .., last] => format!(
"{} and `{last}`",
assocs.iter().map(|a| format!("`{a}`")).collect::<Vec<_>>().join(", ")
),
}
)
})
.collect::<Vec<String>>()
.join(", ");
trait_bound_spans.sort();
let mut err = struct_span_err!(
tcx.sess,
trait_bound_spans,
E0191,
"the value of the associated type{} {} must be specified",
pluralize!(names.len()),
names.join(", "),
pluralize!(names_len),
names,
);
let mut suggestions = vec![];
let mut types_count = 0;

View file

@ -380,7 +380,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span,
E0228,
"the lifetime bound for this object type cannot be deduced \
from context; please supply an explicit bound"
from context; please supply an explicit bound"
);
let e = if borrowed {
// We will have already emitted an error E0106 complaining about a