Skip to content

Commit

Permalink
Auto merge of #133397 - compiler-errors:fix-dyn-incompleteness, r=<try>
Browse files Browse the repository at this point in the history
Fix dyn incompleteness with multiple supertraits with different substitutions

So much to write about this.

Fixes #133361

r? `@ghost`
  • Loading branch information
bors committed Nov 23, 2024
2 parents 826b673 + 88fa8f4 commit 52ae244
Show file tree
Hide file tree
Showing 35 changed files with 331 additions and 687 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::struct_span_code_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
use rustc_middle::span_bug;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::{
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, Upcast,
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
TypeVisitableExt, Upcast,
};
use rustc_span::{ErrorGuaranteed, Span};
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
use rustc_type_ir::elaborate::ClauseWithSupertraitSpan;
Expand Down Expand Up @@ -92,11 +92,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));

// We don't support >1 principal
if regular_traits.len() > 1 {
let _ = self.report_trait_object_addition_traits_error(&regular_traits);
} else if regular_traits.is_empty() && auto_traits.is_empty() {
let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
return Ty::new_error(tcx, reported);
let guar = self.report_trait_object_addition_traits_error(&regular_traits);
return Ty::new_error(tcx, guar);
}
// We don't support empty trait objects.
if regular_traits.is_empty() && auto_traits.is_empty() {
let guar = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
return Ty::new_error(tcx, guar);
}
// Don't create a dyn trait if we have errors in the principal.
if let Err(guar) = trait_bounds.error_reported() {
return Ty::new_error(tcx, guar);
}

// Check that there are no gross dyn-compatibility violations;
Expand All @@ -118,15 +127,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}

let mut associated_types: FxIndexMap<Span, FxIndexSet<DefId>> = FxIndexMap::default();
let mut needed_associated_types = FxIndexSet::default();

let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1);
let regular_traits_refs_spans = trait_bounds
.into_iter()
.filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));

let mut implied_projection_bounds = vec![];
for (base_trait_ref, original_span) in regular_traits_refs_spans {
let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx);
for ClauseWithSupertraitSpan { pred, original_span, supertrait_span } in
for ClauseWithSupertraitSpan { pred, supertrait_span } in
traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)])
.filter_only_self()
{
Expand All @@ -135,13 +146,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);
associated_types.entry(original_span).or_default().extend(
tcx.associated_items(pred.def_id())
// 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(trait_ref.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| !item.is_impl_trait_in_trait())
.map(|item| item.def_id),
// 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, trait_ref)),
);
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
Expand Down Expand Up @@ -173,7 +189,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// the discussion in #56288 for alternatives.
if !references_self {
// Include projections defined on supertraits.
projection_bounds.push((pred, original_span));
implied_projection_bounds.push(pred);
}

self.check_elaborated_projection_mentions_input_lifetimes(
Expand All @@ -191,27 +207,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
// types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
// corresponding `Projection` clause
for def_ids in associated_types.values_mut() {
for (projection_bound, span) in &projection_bounds {
let def_id = projection_bound.projection_def_id();
// FIXME(#120456) - is `swap_remove` correct?
def_ids.swap_remove(&def_id);
if tcx.generics_require_sized_self(def_id) {
tcx.emit_node_span_lint(
UNUSED_ASSOCIATED_TYPE_BOUNDS,
hir_id,
*span,
crate::errors::UnusedAssociatedTypeBounds { span: *span },
);
}
for (projection_bound, span) in &projection_bounds {
let def_id = projection_bound.projection_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,
hir_id,
*span,
crate::errors::UnusedAssociatedTypeBounds { span: *span },
);
}
// If the associated type has a `where Self: Sized` bound, we do not need to constrain the associated
// type in the `dyn Trait`.
def_ids.retain(|def_id| !tcx.generics_require_sized_self(def_id));
}
for projection_bound in &implied_projection_bounds {
let def_id = projection_bound.projection_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));
}

self.complain_about_missing_assoc_tys(
associated_types,
principal_span,
needed_associated_types,
potential_assoc_types,
hir_trait_bounds,
);
Expand Down
Loading

0 comments on commit 52ae244

Please sign in to comment.