Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure valid TraitRefs are created for GATs #82066

Merged
merged 8 commits into from
Feb 18, 2021
23 changes: 18 additions & 5 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1477,12 +1477,11 @@ impl<'tcx> ExistentialProjection<'tcx> {
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
/// then this function would return a `exists T. T: Iterator` existential trait
/// reference.
pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> {
// FIXME(generic_associated_types): substs is the substs of the
// associated type, which should be truncated to get the correct substs
// for the trait.
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
let def_id = tcx.associated_item(self.item_def_id).container.id();
ty::ExistentialTraitRef { def_id, substs: self.substs }
let subst_count = tcx.generics_of(def_id).count() - 1;
let substs = tcx.intern_substs(&self.substs[..subst_count]);
ty::ExistentialTraitRef { def_id, substs }
}

pub fn with_self_ty(
Expand All @@ -1501,6 +1500,20 @@ impl<'tcx> ExistentialProjection<'tcx> {
ty: self.ty,
}
}

pub fn erase_self_ty(
tcx: TyCtxt<'tcx>,
projection_predicate: ty::ProjectionPredicate<'tcx>,
) -> Self {
// Assert there is a Self.
projection_predicate.projection_ty.substs.type_at(0);

Self {
item_def_id: projection_predicate.projection_ty.item_def_id,
substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
ty: projection_predicate.ty,
}
}
}

impl<'tcx> PolyExistentialProjection<'tcx> {
Expand Down
57 changes: 26 additions & 31 deletions compiler/rustc_typeck/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -985,10 +985,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
//
// We want to produce `<B as SuperTrait<i32>>::T == foo`.

debug!(
"add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}",
hir_ref_id, trait_ref, binding, bounds
);
debug!(?hir_ref_id, ?trait_ref, ?binding, ?bounds, "add_predicates_for_ast_type_binding",);
let tcx = self.tcx();

let candidate =
Expand Down Expand Up @@ -1326,37 +1323,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!("regular_traits: {:?}", regular_traits);
debug!("auto_traits: {:?}", auto_traits);

// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
// removing the dummy `Self` type (`trait_object_dummy_self`).
let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| {
if trait_ref.self_ty() != dummy_self {
// FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
// which picks up non-supertraits where clauses - but also, the object safety
// completely ignores trait aliases, which could be object safety hazards. We
// `delay_span_bug` here to avoid an ICE in stable even when the feature is
// disabled. (#66420)
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"trait_ref_to_existential called on {:?} with non-dummy Self",
trait_ref,
),
);
}
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
};

// Erase the `dummy_self` (`trait_object_dummy_self`) used above.
let existential_trait_refs =
regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential));
let existential_trait_refs = regular_traits.iter().map(|i| {
i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
if trait_ref.self_ty() != dummy_self {
// FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
// which picks up non-supertraits where clauses - but also, the object safety
// completely ignores trait aliases, which could be object safety hazards. We
// `delay_span_bug` here to avoid an ICE in stable even when the feature is
// disabled. (#66420)
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"trait_ref_to_existential called on {:?} with non-dummy Self",
trait_ref,
),
);
}
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
})
});
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
bound.map_bound(|b| {
let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
ty::ExistentialProjection {
ty: b.ty,
item_def_id: b.projection_ty.item_def_id,
substs: trait_ref.substs,
if b.projection_ty.self_ty() != dummy_self {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!("trait_ref_to_existential called on {:?} with non-dummy Self", b),
);
}
ty::ExistentialProjection::erase_self_ty(tcx, b)
})
});

Expand Down