Skip to content

Commit

Permalink
Auto merge of #116405 - estebank:issue-103155, r=davidtwco
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Oct 30, 2023
2 parents 31bc7e2 + b8a8ba9 commit a395214
Show file tree
Hide file tree
Showing 38 changed files with 249 additions and 193 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ hir_analysis_unused_associated_type_bounds =
.suggestion = remove this bound
hir_analysis_value_of_associated_struct_already_specified =
the value of the associated type `{$item_name}` (from trait `{$def_path}`) is 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
Expand Down
47 changes: 39 additions & 8 deletions compiler/rustc_hir_analysis/src/astconv/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -573,15 +584,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
_ => {}
}
}

let mut names = names
.into_iter()
.map(|(trait_, mut assocs)| {
assocs.sort();
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>>();
names.sort();
let names = names.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;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/astconv/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub use self::engine::{ObligationCtxt, TraitEngineExt};
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::is_vtable_safe_method;
pub use self::object_safety::MethodViolationCode;
pub use self::object_safety::object_safety_violations_for_assoc_item;
pub use self::object_safety::ObjectSafetyViolation;
pub use self::project::NormalizeExt;
pub use self::project::{normalize_inherent_projection, normalize_projection_type};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {

/// Returns `Some(_)` if this item makes the containing trait not object safe.
#[instrument(level = "debug", skip(tcx), ret)]
fn object_safety_violations_for_assoc_item(
pub fn object_safety_violations_for_assoc_item(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
item: ty::AssocItem,
Expand Down
Loading

0 comments on commit a395214

Please sign in to comment.