Skip to content

Commit

Permalink
Auto merge of rust-lang#133397 - compiler-errors:fix-dyn-incompletene…
Browse files Browse the repository at this point in the history
…ss, r=<try>

Fix dyn incompleteness with multiple supertraits with different substitutions

So much to write about this.

Fixes rust-lang#133361

r? `@ghost`
  • Loading branch information
bors committed Nov 29, 2024
2 parents a45391f + 22cb94a commit 3165a83
Show file tree
Hide file tree
Showing 23 changed files with 369 additions and 241 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ 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,
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 @@ -62,7 +61,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}

let mut trait_bounds = vec![];
let mut projection_bounds = vec![];
let mut projection_bounds = FxIndexMap::default();
for (pred, span) in bounds.clauses() {
let bound_pred = pred.kind();
match bound_pred.skip_binder() {
Expand All @@ -71,7 +70,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span));
}
ty::ClauseKind::Projection(proj) => {
projection_bounds.push((bound_pred.rebind(proj), span));
let anon = tcx.anonymize_bound_vars(bound_pred.rebind(proj));
projection_bounds.insert(anon, (bound_pred.rebind(proj), span));
}
ty::ClauseKind::TypeOutlives(_) => {
// Do nothing, we deal with regions separately
Expand All @@ -88,8 +88,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

// Expand trait aliases recursively and check that only one regular (non-auto) trait
// is used and no 'maybe' bounds are used.
let expanded_traits =
traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b)));
let mut trait_alias_projection_bounds = FxIndexSet::default();
let expanded_traits = traits::expand_trait_aliases(
tcx,
&mut trait_alias_projection_bounds,
trait_bounds.iter().map(|&(a, b)| (a, b)),
);

let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
Expand Down Expand Up @@ -128,12 +132,14 @@ 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, supertrait_span } in
Expand All @@ -145,17 +151,28 @@ 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)) => {
let pred = bound_predicate.rebind(pred);

let pred_key = tcx.anonymize_bound_vars(pred);
if !trait_alias_projection_bounds.contains(&pred_key) {
projection_bounds.shift_remove(&pred_key);
}

// A `Self` within the original bound will be instantiated with a
// `trait_object_dummy_self`, so check for that.
let references_self = match pred.skip_binder().term.unpack() {
Expand All @@ -182,8 +199,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
// the discussion in #56288 for alternatives.
if !references_self {
// Include projections defined on supertraits.
projection_bounds.push((pred, original_span));
if trait_alias_projection_bounds.contains(&pred_key) {
// Include projections defined on supertraits.
projection_bounds.insert(pred_key, (pred, supertrait_span));
} else {
// Include projections defined on supertraits.
implied_projection_bounds.push(pred);
}
}

self.check_elaborated_projection_mentions_input_lifetimes(
Expand All @@ -201,26 +223,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();
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.values() {
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 Expand Up @@ -302,7 +330,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
})
});

let existential_projections = projection_bounds.iter().map(|(bound, _)| {
let existential_projections = projection_bounds.values().map(|(bound, _)| {
bound.map_bound(|mut b| {
assert_eq!(b.projection_term.self_ty(), dummy_self);

Expand Down
Loading

0 comments on commit 3165a83

Please sign in to comment.