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
27 changes: 23 additions & 4 deletions compiler/rustc_privacy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ trait DefIdVisitor<'tcx> {
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> {
self.skeleton().visit_trait(trait_ref)
}
fn visit_projection_ty(
&mut self,
projection: ty::ProjectionTy<'tcx>,
) -> ControlFlow<Self::BreakTy> {
self.skeleton().visit_projection_ty(projection)
}
fn visit_predicates(
&mut self,
predicates: ty::GenericPredicates<'tcx>,
Expand All @@ -101,14 +107,28 @@ where
if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
}

fn visit_projection_ty(
&mut self,
projection: ty::ProjectionTy<'tcx>,
) -> ControlFlow<V::BreakTy> {
let (trait_ref, assoc_substs) =
projection.trait_ref_and_own_substs(self.def_id_visitor.tcx());
self.visit_trait(trait_ref)?;
jackh726 marked this conversation as resolved.
Show resolved Hide resolved
if self.def_id_visitor.shallow() {
ControlFlow::CONTINUE
} else {
assoc_substs.iter().try_for_each(|subst| subst.visit_with(self))
}
}

fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
match predicate.kind().skip_binder() {
ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => {
self.visit_trait(trait_ref)
}
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
ty.visit_with(self)?;
self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
self.visit_projection_ty(projection_ty)
}
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
ty.visit_with(self)
Expand Down Expand Up @@ -197,7 +217,7 @@ where
return ControlFlow::CONTINUE;
}
// This will also visit substs if necessary, so we don't need to recurse.
return self.visit_trait(proj.trait_ref(tcx));
return self.visit_projection_ty(proj);
}
ty::Dynamic(predicates, ..) => {
// All traits in the list are considered the "primary" part of the type
Expand Down Expand Up @@ -1204,10 +1224,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
}

for (poly_predicate, _) in bounds.projection_bounds {
let tcx = self.tcx;
if self.visit(poly_predicate.skip_binder().ty).is_break()
|| self
.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
.visit_projection_ty(poly_predicate.skip_binder().projection_ty)
.is_break()
{
return;
Expand Down
20 changes: 10 additions & 10 deletions compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use rustc_errors::ErrorReported;
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
use std::marker::PhantomData;
Expand Down Expand Up @@ -633,9 +634,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
// only reason we can fail to make progress on
// trait selection is because we don't have enough
// information about the types in the trait.
*stalled_on = trait_ref_infer_vars(
*stalled_on = substs_infer_vars(
self.selcx,
trait_obligation.predicate.map_bound(|pred| pred.trait_ref),
trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
);

debug!(
Expand Down Expand Up @@ -663,9 +664,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
Ok(Ok(None)) => {
*stalled_on = trait_ref_infer_vars(
*stalled_on = substs_infer_vars(
self.selcx,
project_obligation.predicate.to_poly_trait_ref(tcx),
project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
);
ProcessResult::Unchanged
}
Expand All @@ -678,16 +679,15 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
}
}

/// Returns the set of inference variables contained in a trait ref.
fn trait_ref_infer_vars<'a, 'tcx>(
/// Returns the set of inference variables contained in `substs`.
fn substs_infer_vars<'a, 'tcx>(
selcx: &mut SelectionContext<'a, 'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
substs: ty::Binder<SubstsRef<'tcx>>,
) -> Vec<TyOrConstInferVar<'tcx>> {
selcx
.infcx()
.resolve_vars_if_possible(trait_ref)
.skip_binder()
.substs
.resolve_vars_if_possible(substs)
.skip_binder() // ok because this check doesn't care about regions
.iter()
// FIXME(eddyb) try using `skip_current_subtree` to skip everything that
// doesn't contain inference variables, not just the outermost level.
Expand Down
6 changes: 1 addition & 5 deletions compiler/rustc_trait_selection/src/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,7 @@ fn predicate_references_self(
//
// This is ALT2 in issue #56288, see that for discussion of the
// possible alternatives.
if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
Some(sp)
} else {
None
}
if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
}
ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/constrained_generic_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ pub fn setup_constraining_predicates<'tcx>(
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
// Then the projection only applies if `T` is known, but it still
// does not determine `U`.
let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true);
let inputs = parameters_for(&projection.projection_ty, true);
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
if !relies_only_on_inputs {
continue;
Expand Down