Skip to content

Commit 0fa4c17

Browse files
committed
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.
1 parent a6dfd89 commit 0fa4c17

36 files changed

+223
-194
lines changed

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ hir_analysis_unused_associated_type_bounds =
363363
.suggestion = remove this bound
364364
365365
hir_analysis_value_of_associated_struct_already_specified =
366-
the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified
366+
the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified
367367
.label = re-bound here
368368
.previous_bound_label = `{$item_name}` bound here first
369369

compiler/rustc_hir_analysis/src/astconv/errors.rs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::errors::{
33
AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
44
ParenthesizedFnTraitExpansion,
55
};
6+
use crate::traits::error_reporting::report_object_safety_error;
67
use rustc_data_structures::fx::FxHashMap;
78
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
89
use rustc_hir as hir;
@@ -14,6 +15,7 @@ use rustc_session::parse::feature_err;
1415
use rustc_span::edit_distance::find_best_match_for_name;
1516
use rustc_span::symbol::{sym, Ident};
1617
use rustc_span::{Span, Symbol, DUMMY_SP};
18+
use rustc_trait_selection::traits::object_safety_violation_for_assoc_item;
1719

1820
use std::collections::BTreeSet;
1921

@@ -472,24 +474,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
472474
(span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
473475
})
474476
.collect();
475-
let mut names = vec![];
477+
let mut names: FxHashMap<String, Vec<Symbol>> = Default::default();
478+
let mut names_len = 0;
476479

477480
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
478481
// `issue-22560.rs`.
479482
let mut trait_bound_spans: Vec<Span> = vec![];
483+
let mut object_safety_violations = false;
480484
for (span, items) in &associated_types {
481485
if !items.is_empty() {
482486
trait_bound_spans.push(*span);
483487
}
484488
for assoc_item in items {
485489
let trait_def_id = assoc_item.container_id(tcx);
486-
names.push(format!(
487-
"`{}` (from trait `{}`)",
488-
assoc_item.name,
489-
tcx.def_path_str(trait_def_id),
490-
));
490+
names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
491+
names_len += 1;
492+
493+
if let Some(violation) =
494+
object_safety_violation_for_assoc_item(tcx, trait_def_id, *assoc_item)
495+
{
496+
report_object_safety_error(tcx, *span, trait_def_id, &[violation]).emit();
497+
object_safety_violations = true;
498+
}
491499
}
492500
}
501+
if object_safety_violations {
502+
return;
503+
}
493504
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
494505
match bound.trait_ref.path.segments {
495506
// FIXME: `trait_ref.path.span` can point to a full path with multiple
@@ -525,15 +536,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
525536
_ => {}
526537
}
527538
}
528-
names.sort();
539+
540+
let names = names
541+
.into_iter()
542+
.map(|(trait_, assocs)| {
543+
format!(
544+
"{} in `{trait_}`",
545+
match &assocs[..] {
546+
[] => String::new(),
547+
[only] => format!("`{only}`"),
548+
[assocs @ .., last] => format!(
549+
"{} and `{last}`",
550+
assocs.iter().map(|a| format!("`{a}`")).collect::<Vec<_>>().join(", ")
551+
),
552+
}
553+
)
554+
})
555+
.collect::<Vec<String>>()
556+
.join(", ");
557+
529558
trait_bound_spans.sort();
530559
let mut err = struct_span_err!(
531560
tcx.sess,
532561
trait_bound_spans,
533562
E0191,
534563
"the value of the associated type{} {} must be specified",
535-
pluralize!(names.len()),
536-
names.join(", "),
564+
pluralize!(names_len),
565+
names,
537566
);
538567
let mut suggestions = vec![];
539568
let mut types_count = 0;

compiler/rustc_hir_analysis/src/astconv/object_safety.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
380380
span,
381381
E0228,
382382
"the lifetime bound for this object type cannot be deduced \
383-
from context; please supply an explicit bound"
383+
from context; please supply an explicit bound"
384384
);
385385
let e = if borrowed {
386386
// We will have already emitted an error E0106 complaining about a

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub use self::engine::{ObligationCtxt, TraitEngineExt};
5252
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
5353
pub use self::object_safety::astconv_object_safety_violations;
5454
pub use self::object_safety::is_vtable_safe_method;
55-
pub use self::object_safety::MethodViolationCode;
55+
pub use self::object_safety::object_safety_violation_for_assoc_item;
5656
pub use self::object_safety::ObjectSafetyViolation;
5757
pub use self::project::NormalizeExt;
5858
pub use self::project::{normalize_inherent_projection, normalize_projection_type};

compiler/rustc_trait_selection/src/traits/object_safety.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
357357

358358
/// Returns `Some(_)` if this item makes the containing trait not object safe.
359359
#[instrument(level = "debug", skip(tcx), ret)]
360-
fn object_safety_violation_for_assoc_item(
360+
pub fn object_safety_violation_for_assoc_item(
361361
tcx: TyCtxt<'_>,
362362
trait_def_id: DefId,
363363
item: ty::AssocItem,

0 commit comments

Comments
 (0)