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 Dec 4, 2024
2 parents 96e51d9 + 753da78 commit 22a8823
Show file tree
Hide file tree
Showing 73 changed files with 1,324 additions and 936 deletions.
372 changes: 233 additions & 139 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs

Large diffs are not rendered by default.

290 changes: 144 additions & 146 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Large diffs are not rendered by default.

24 changes: 13 additions & 11 deletions compiler/rustc_hir_typeck/src/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_span::def_id::LocalDefId;
use rustc_span::{DUMMY_SP, Span};
use rustc_trait_selection::error_reporting::traits::ArgKind;
use rustc_trait_selection::traits;
use rustc_type_ir::ClosureKind;
use rustc_type_ir::{ClosureKind, Upcast as _};
use tracing::{debug, instrument, trace};

use super::{CoroutineTypes, Expectation, FnCtxt, check_fn};
Expand Down Expand Up @@ -312,16 +312,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter_instantiated_copied(self.tcx, args)
.map(|(c, s)| (c.as_predicate(), s)),
),
ty::Dynamic(object_type, ..) => {
let sig = object_type.projection_bounds().find_map(|pb| {
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
self.deduce_sig_from_projection(None, closure_kind, pb)
});
let kind = object_type
.principal_def_id()
.and_then(|did| self.tcx.fn_trait_kind_from_def_id(did));
(sig, kind)
}
ty::Dynamic(data, ..) => self.deduce_closure_signature_from_predicates(
self.tcx.types.trait_object_dummy_self,
closure_kind,
data.iter().map(|bound| {
(
bound
.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self)
.upcast(self.tcx),
DUMMY_SP,
)
}),
),
ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
Ty::new_var(self.tcx, self.root_var(vid)),
closure_kind,
Expand Down
11 changes: 5 additions & 6 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::cell::{Cell, RefCell};
use std::cmp::max;
use std::iter;
use std::ops::Deref;

use rustc_data_structures::fx::FxHashSet;
Expand Down Expand Up @@ -901,11 +900,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {

if self.tcx.is_trait_alias(trait_def_id) {
// For trait aliases, recursively assume all explicitly named traits are relevant
for expansion in traits::expand_trait_aliases(
self.tcx,
iter::once((ty::Binder::dummy(trait_ref), self.span)),
) {
let bound_trait_ref = expansion.trait_ref();
for (bound_trait_pred, _) in
traits::expand_trait_aliases(self.tcx, [(trait_ref.upcast(self.tcx), self.span)]).0
{
assert_eq!(bound_trait_pred.polarity(), ty::PredicatePolarity::Positive);
let bound_trait_ref = bound_trait_pred.map_bound(|pred| pred.trait_ref);
for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
if !self.has_applicable_self(&item) {
self.record_static_candidate(CandidateSource::Trait(
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ declare_lint_pass! {
DEPRECATED_SAFE_2024,
DEPRECATED_WHERE_CLAUSE_LOCATION,
DUPLICATE_MACRO_ATTRIBUTES,
DYN_ASSOC_REDUNDANT,
DYN_ASSOC_SHADOWED,
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
ELIDED_LIFETIMES_IN_PATHS,
ELIDED_NAMED_LIFETIMES,
Expand Down Expand Up @@ -5112,6 +5114,20 @@ declare_lint! {
crate_level_only
}

declare_lint! {
/// Hi
pub DYN_ASSOC_REDUNDANT,
Warn,
"oops",
}

declare_lint! {
/// Hi
pub DYN_ASSOC_SHADOWED,
Deny,
"oops",
}

declare_lint! {
/// The `abi_unsupported_vector_types` lint detects function definitions and calls
/// whose ABI depends on enabling certain target features, but those features are not enabled.
Expand Down
16 changes: 4 additions & 12 deletions compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,12 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
) -> RelateResult<'tcx, Self> {
let tcx = relation.cx();

// FIXME: this is wasteful, but want to do a perf run to see how slow it is.
// We need to perform this deduplication as we sometimes generate duplicate projections
// in `a`.
let mut a_v: Vec<_> = a.into_iter().collect();
let mut b_v: Vec<_> = b.into_iter().collect();
a_v.dedup();
b_v.dedup();
if a_v.len() != b_v.len() {
if a.len() != b.len() {
return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
}

let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
match (ep_a.skip_binder(), ep_b.skip_binder()) {
let v =
iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) {
(ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => {
Ok(ep_a.rebind(ty::ExistentialPredicate::Trait(
relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
Expand All @@ -109,8 +102,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
ty::ExistentialPredicate::AutoTrait(b),
) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
_ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))),
}
});
});
tcx.mk_poly_existential_predicates_from_iter(v)
}
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
self.async_destructor_ty(interner)
}

fn is_self_param(self) -> bool {
self.is_param(0)
}
}

/// Type utilities
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,15 @@ where
assumption.upcast(cx),
));
}

for assumption in elaborate::implied_supertrait_projections(cx, principal) {
candidates.extend(G::probe_and_consider_object_bound_candidate(
self,
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
goal,
assumption.with_self_ty(cx, self_ty).upcast(cx),
));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use derive_where::derive_where;
use rustc_ast_ir::{Movability, Mutability};
use rustc_type_ir::data_structures::HashMap;
use rustc_type_ir::data_structures::{HashMap, HashSet};
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
Expand Down Expand Up @@ -841,6 +841,14 @@ where
.map(|(pred, _)| pred),
));

// It's sufficient to just keep track of the def ids of the explicitly specified
// associated types since when users write `dyn Trait<Assoc = T>`, that associated
// type must resolve to *one* bound from all of the supertraits. So the fact that
// there is a user-provided projection is enough proof that it's unique and we don't
// need to care about substitutions or anything like that.
let specified_associated_projections: HashSet<_> =
object_bounds.projection_bounds().into_iter().map(|proj| proj.item_def_id()).collect();

// FIXME(associated_const_equality): Also add associated consts to
// the requirements here.
for associated_type_def_id in cx.associated_type_def_ids(trait_ref.def_id) {
Expand All @@ -850,6 +858,11 @@ where
continue;
}

// We don't require these bounds to hold for supertrait implied projection bounds.
if !specified_associated_projections.contains(&associated_type_def_id) {
continue;
}

requirements
.extend(cx.item_bounds(associated_type_def_id).iter_instantiated(cx, trait_ref.args));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,8 @@ pub fn report_dyn_incompatibility<'tcx>(
tcx.dcx(),
span,
E0038,
"the trait `{}` cannot be made into an object",
"the {} `{}` cannot be made into an object",
tcx.def_descr(trait_def_id),
trait_str
);
err.span_label(span, format!("`{trait_str}` cannot be made into an object"));
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ pub use self::specialize::{
};
pub use self::structural_normalize::StructurallyNormalizeExt;
pub use self::util::{
BoundVarReplacer, PlaceholderReplacer, TraitAliasExpander, TraitAliasExpansionInfo, elaborate,
expand_trait_aliases, impl_item_is_final, supertraits,
transitive_bounds_that_define_assoc_item, upcast_choices, with_replaced_escaping_bound_vars,
BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final,
supertraits, transitive_bounds_that_define_assoc_item, upcast_choices,
with_replaced_escaping_bound_vars,
};
use crate::error_reporting::InferCtxtErrorExt;
use crate::infer::outlives::env::OutlivesEnvironment;
Expand Down
26 changes: 21 additions & 5 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::sym;
use rustc_type_ir::elaborate;
use tracing::{debug, instrument};

use super::{
Expand Down Expand Up @@ -59,7 +60,7 @@ enum ProjectionCandidate<'tcx> {
TraitDef(ty::PolyProjectionPredicate<'tcx>),

/// Bounds specified on an object type
Object(ty::PolyProjectionPredicate<'tcx>),
Object(ty::PolyProjectionPredicate<'tcx>, bool),

/// From an "impl" (or a "pseudo-impl" returned by select)
Select(Selection<'tcx>),
Expand Down Expand Up @@ -658,7 +659,7 @@ fn project<'cx, 'tcx>(

assemble_candidates_from_object_ty(selcx, obligation, &mut candidates);

if let ProjectionCandidateSet::Single(ProjectionCandidate::Object(_)) = candidates {
if let ProjectionCandidateSet::Single(ProjectionCandidate::Object(..)) = candidates {
// Avoid normalization cycle from selection (see
// `assemble_candidates_from_object_ty`).
// FIXME(lazy_normalization): Lazy normalization should save us from
Expand Down Expand Up @@ -814,6 +815,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
}
_ => return,
};

let env_predicates = data
.projection_bounds()
.filter(|bound| bound.item_def_id() == obligation.predicate.def_id)
Expand All @@ -823,10 +825,22 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
selcx,
obligation,
candidate_set,
ProjectionCandidate::Object,
|c| ProjectionCandidate::Object(c, false),
env_predicates,
false,
);

if let Some(principal) = data.principal() {
assemble_candidates_from_predicates(
selcx,
obligation,
candidate_set,
|c| ProjectionCandidate::Object(c, true),
elaborate::implied_supertrait_projections(tcx, principal)
.map(|pred| pred.with_self_ty(tcx, object_ty).upcast(tcx)),
true,
);
}
}

#[instrument(
Expand Down Expand Up @@ -1235,10 +1249,12 @@ fn confirm_candidate<'cx, 'tcx>(
) -> Progress<'tcx> {
debug!(?obligation, ?candidate, "confirm_candidate");
let mut progress = match candidate {
ProjectionCandidate::ParamEnv(poly_projection)
| ProjectionCandidate::Object(poly_projection) => {
ProjectionCandidate::ParamEnv(poly_projection) => {
confirm_param_env_candidate(selcx, obligation, poly_projection, false)
}
ProjectionCandidate::Object(poly_projection, from_super) => {
confirm_param_env_candidate(selcx, obligation, poly_projection, from_super)
}

ProjectionCandidate::TraitDef(poly_projection) => {
confirm_param_env_candidate(selcx, obligation, poly_projection, true)
Expand Down
Loading

0 comments on commit 22a8823

Please sign in to comment.