ty::FnPtr(..) |
ty::Tuple(..) |
ty::Never |
- ty::Param(..) => (),
+ ty::Infer(..) |
+ ty::Bound(..) => (),
ty::GeneratorWitness(..) |
ty::UnnormalizedProjection(..) |
- ty::Infer(..) |
- ty::Bound(..) |
+ ty::Param(..) |
ty::Error => {
bug!("unexpected type {:?}", ty);
}
);
}
-crate fn environment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Environment<'tcx> {
+crate fn environment<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId
+) -> ty::Binder<Environment<'tcx>> {
use super::{Lower, IntoFromEnvGoal};
use rustc::hir::{Node, TraitItemKind, ImplItemKind, ItemKind, ForeignItemKind};
+ use rustc::ty::subst::{Subst, Substs};
// The environment of an impl Trait type is its defining function's environment.
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
return environment(tcx, parent);
}
+ let bound_vars = Substs::bound_vars_for_item(tcx, def_id);
+
// Compute the bounds on `Self` and the type parameters.
- let ty::InstantiatedPredicates { predicates } =
- tcx.predicates_of(def_id).instantiate_identity(tcx);
+ let ty::InstantiatedPredicates { predicates } = tcx.predicates_of(def_id)
+ .instantiate_identity(tcx);
let clauses = predicates.into_iter()
.map(|predicate| predicate.lower())
+ .map(|predicate| predicate.subst(tcx, bound_vars))
.map(|domain_goal| domain_goal.map_bound(|bound| bound.into_from_env_goal()))
.map(|domain_goal| domain_goal.map_bound(|bound| bound.into_program_clause()))
let mut input_tys = FxHashSet::default();
- // In an impl, we assume that the receiver type and all its constituents
+ // In an impl, we assume that the header trait ref and all its constituents
// are well-formed.
if is_impl {
- let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
- input_tys.extend(trait_ref.self_ty().walk());
+ let trait_ref = tcx.impl_trait_ref(def_id)
+ .expect("not an impl")
+ .subst(tcx, bound_vars);
+
+ input_tys.extend(
+ trait_ref.substs.types().flat_map(|ty| ty.walk())
+ );
}
// In an fn, we assume that the arguments and all their constituents are
// well-formed.
if is_fn {
- let fn_sig = tcx.fn_sig(def_id);
+ // `skip_binder` because we move late bound regions to the root binder,
+ // restored in the return type
+ let fn_sig = tcx.fn_sig(def_id).skip_binder().subst(tcx, bound_vars);
+
input_tys.extend(
- // FIXME: `skip_binder` seems ok for now? In a real setting,
- // the late bound regions would next be instantiated with things
- // in the inference table.
- fn_sig.skip_binder().inputs().iter().flat_map(|ty| ty.walk())
+ fn_sig.inputs().iter().flat_map(|ty| ty.walk())
);
}
let clauses = clauses.chain(
input_tys.into_iter()
+ // Filter out type parameters
+ .filter(|ty| match ty.sty {
+ ty::Bound(..) => false,
+ _ => true,
+ })
.map(|ty| DomainGoal::FromEnv(FromEnv::Ty(ty)))
.map(|domain_goal| domain_goal.into_program_clause())
.map(Clause::Implies)
);
- Environment {
+ ty::Binder::bind(Environment {
clauses: tcx.mk_clauses(clauses),
- }
+ })
}
};
use rustc::ty::query::Providers;
use rustc::ty::{self, List, TyCtxt};
+use rustc::ty::subst::{Subst, Substs};
use syntax::ast;
use std::iter;
// }
// ```
+ let bound_vars = Substs::bound_vars_for_item(tcx, def_id);
+
// `Self: Trait<P1..Pn>`
let trait_pred = ty::TraitPredicate {
- trait_ref: ty::TraitRef::identity(tcx, def_id),
+ trait_ref: ty::TraitRef {
+ def_id,
+ substs: bound_vars,
+ },
};
// `Implemented(Self: Trait<P1..Pn>)`
category: ProgramClauseCategory::ImpliedBound,
};
- let clauses = iter::once(Clause::ForAll(ty::Binder::dummy(implemented_from_env)));
+ let implemented_from_env = Clause::ForAll(ty::Binder::bind(implemented_from_env));
let where_clauses = &tcx.predicates_defined_on(def_id).predicates
.into_iter()
.map(|(wc, _)| wc.lower())
+ .map(|wc| wc.subst(tcx, bound_vars))
.collect::<Vec<_>>();
// Rule Implied-Bound-From-Trait
.cloned()
// `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
- .map(|wc| wc.map_bound(|goal| ProgramClause {
- goal: goal.into_from_env_goal(),
- hypotheses,
- category: ProgramClauseCategory::ImpliedBound,
- }))
+ .map(|wc| {
+ // we move binders to the left
+ wc.map_bound(|goal| ProgramClause {
+ goal: goal.into_from_env_goal(),
+
+ // FIXME: As where clauses can only bind lifetimes for now,
+ // and that named bound regions have a def-id, it is safe
+ // to just inject `hypotheses` (which contains named vars bound at index `0`)
+ // into this binding level. This may change if we ever allow where clauses
+ // to bind types (e.g. for GATs things).
+ hypotheses,
+
+ category: ProgramClauseCategory::ImpliedBound,
+ })
+ })
.map(Clause::ForAll);
// Rule WellFormed-TraitRef
// }
// ```
- // `Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
- let wf_conditions = iter::once(ty::Binder::dummy(trait_pred.lower()))
- .chain(
- where_clauses
- .into_iter()
- .map(|wc| wc.map_bound(|goal| goal.into_well_formed_goal()))
- );
+ // `WellFormed(WC)`
+ let wf_conditions = where_clauses
+ .into_iter()
+ .map(|wc| wc.map_bound(|goal| goal.into_well_formed_goal()));
// `WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
let wf_clause = ProgramClause {
goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)),
hypotheses: tcx.mk_goals(
- wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
+ iter::once(tcx.mk_goal(GoalKind::DomainGoal(impl_trait))).chain(
+ wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx)))
+ )
),
category: ProgramClauseCategory::WellFormed,
};
- let wf_clause = iter::once(Clause::ForAll(ty::Binder::dummy(wf_clause)));
+ let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
tcx.mk_clauses(
- clauses
+ iter::once(implemented_from_env)
.chain(implied_bound_clauses)
- .chain(wf_clause)
+ .chain(iter::once(wf_clause))
)
}
// }
// ```
- let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
+ let bound_vars = Substs::bound_vars_for_item(tcx, def_id);
+
+ let trait_ref = tcx.impl_trait_ref(def_id)
+ .expect("not an impl")
+ .subst(tcx, bound_vars);
// `Implemented(A0: Trait<A1..An>)`
let trait_pred = ty::TraitPredicate { trait_ref }.lower();
// `WC`
let where_clauses = tcx.predicates_of(def_id).predicates
.into_iter()
- .map(|(wc, _)| wc.lower());
+ .map(|(wc, _)| wc.lower())
+ .map(|wc| wc.subst(tcx, bound_vars));
// `Implemented(A0: Trait<A1..An>) :- WC`
let clause = ProgramClause {
),
category: ProgramClauseCategory::Other,
};
- tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
+ tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::bind(clause))))
}
pub fn program_clauses_for_type_def<'a, 'tcx>(
// }
// ```
+ let bound_vars = Substs::bound_vars_for_item(tcx, def_id);
+
// `Ty<...>`
- let ty = tcx.type_of(def_id);
+ let ty = tcx.type_of(def_id).subst(tcx, bound_vars);
// `WC`
let where_clauses = tcx.predicates_of(def_id).predicates
.into_iter()
.map(|(wc, _)| wc.lower())
+ .map(|wc| wc.subst(tcx, bound_vars))
.collect::<Vec<_>>();
// `WellFormed(Ty<...>) :- WC1, ..., WCm`
- let well_formed = ProgramClause {
+ let well_formed_clause = ProgramClause {
goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
hypotheses: tcx.mk_goals(
where_clauses
),
category: ProgramClauseCategory::WellFormed,
};
-
- let well_formed_clause = iter::once(Clause::ForAll(ty::Binder::dummy(well_formed)));
+ let well_formed_clause = Clause::ForAll(ty::Binder::bind(well_formed_clause));
// Rule FromEnv-Type
//
.into_iter()
// `FromEnv(WC) :- FromEnv(Ty<...>)`
- .map(|wc| wc.map_bound(|goal| ProgramClause {
- goal: goal.into_from_env_goal(),
- hypotheses,
- category: ProgramClauseCategory::ImpliedBound,
- }))
+ .map(|wc| {
+ // move the binders to the left
+ wc.map_bound(|goal| ProgramClause {
+ goal: goal.into_from_env_goal(),
+
+ // FIXME: we inject `hypotheses` into this binding level,
+ // which may be incorrect in the future: see the FIXME in
+ // `program_clauses_for_trait`
+ hypotheses,
+
+ category: ProgramClauseCategory::ImpliedBound,
+ })
+ })
.map(Clause::ForAll);
- tcx.mk_clauses(well_formed_clause.chain(from_env_clauses))
+ tcx.mk_clauses(iter::once(well_formed_clause).chain(from_env_clauses))
}
pub fn program_clauses_for_associated_type_def<'a, 'tcx>(
ty::AssociatedItemContainer::TraitContainer(trait_id) => trait_id,
_ => bug!("not an trait container"),
};
- let trait_ref = ty::TraitRef::identity(tcx, trait_id);
+
+ let trait_bound_vars = Substs::bound_vars_for_item(tcx, trait_id);
+ let trait_ref = ty::TraitRef {
+ def_id: trait_id,
+ substs: trait_bound_vars,
+ };
let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
let placeholder_ty = tcx.mk_ty(ty::UnnormalizedProjection(projection_ty));
hypotheses: ty::List::empty(),
category: ProgramClauseCategory::Other,
};
+ let projection_eq_clause = Clause::ForAll(ty::Binder::bind(projection_eq_clause));
// Rule WellFormed-AssocTy
// ```
let hypothesis = tcx.mk_goal(
DomainGoal::Holds(WhereClause::Implemented(trait_predicate)).into_goal()
);
+
let wf_clause = ProgramClause {
goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)),
hypotheses: tcx.mk_goals(iter::once(hypothesis)),
category: ProgramClauseCategory::WellFormed,
};
+ let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
// Rule Implied-Trait-From-AssocTy
// ```
let hypothesis = tcx.mk_goal(
DomainGoal::FromEnv(FromEnv::Ty(placeholder_ty)).into_goal()
);
+
let from_env_clause = ProgramClause {
goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)),
hypotheses: tcx.mk_goals(iter::once(hypothesis)),
category: ProgramClauseCategory::ImpliedBound,
};
+ let from_env_clause = Clause::ForAll(ty::Binder::bind(from_env_clause));
let clauses = iter::once(projection_eq_clause)
.chain(iter::once(wf_clause))
.chain(iter::once(from_env_clause));
- let clauses = clauses.map(|clause| Clause::ForAll(ty::Binder::dummy(clause)));
tcx.mk_clauses(clauses)
}
_ => bug!("not an impl container"),
};
+ let impl_bound_vars = Substs::bound_vars_for_item(tcx, impl_id);
+
// `A0 as Trait<A1..An>`
- let trait_ref = tcx.impl_trait_ref(impl_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_id)
+ .unwrap()
+ .subst(tcx, impl_bound_vars);
// `T`
let ty = tcx.type_of(item_id);
// `Implemented(A0: Trait<A1..An>)`
- let trait_implemented = ty::Binder::dummy(ty::TraitPredicate { trait_ref }.lower());
-
- // `Implemented(A0: Trait<A1..An>)`
- let hypotheses = vec![trait_implemented];
+ let trait_implemented: DomainGoal = ty::TraitPredicate { trait_ref }.lower();
// `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
// `Normalize(... -> T) :- ...`
- let clause = ProgramClause {
+ let normalize_clause = ProgramClause {
goal: normalize_goal,
hypotheses: tcx.mk_goals(
- hypotheses
- .into_iter()
- .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
+ iter::once(tcx.mk_goal(GoalKind::DomainGoal(trait_implemented)))
),
category: ProgramClauseCategory::Other,
};
- tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
+ let normalize_clause = Clause::ForAll(ty::Binder::bind(normalize_clause));
+
+ tcx.mk_clauses(iter::once(normalize_clause))
}
pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
if attr.check_name("rustc_dump_env_program_clauses") {
let environment = self.tcx.environment(def_id);
- clauses = Some(self.tcx.program_clauses_for_env(environment));
+ clauses = Some(self.tcx.program_clauses_for_env(*environment.skip_binder()));
}
if let Some(clauses) = clauses {