10 use rustc::ty::{self, TyCtxt, Ty};
11 use rustc::hir::def_id::DefId;
12 use rustc_data_structures::fx::FxHashSet;
14 struct ClauseVisitor<'set, 'a, 'tcx: 'a + 'set> {
15 tcx: TyCtxt<'a, 'tcx, 'tcx>,
16 round: &'set mut FxHashSet<Clause<'tcx>>,
19 impl ClauseVisitor<'set, 'a, 'tcx> {
20 fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, round: &'set mut FxHashSet<Clause<'tcx>>) -> Self {
27 fn visit_ty(&mut self, ty: Ty<'tcx>) {
29 ty::Projection(data) => {
31 self.tcx.program_clauses_for(data.item_def_id)
33 .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
39 // FIXME: trait object rules are not yet implemented
44 self.tcx.program_clauses_for(def.did)
46 .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
52 ty::FnDef(def_id, ..) |
53 ty::Closure(def_id, ..) |
54 ty::Generator(def_id, ..) |
55 ty::Opaque(def_id, ..) => {
57 self.tcx.program_clauses_for(def_id)
59 .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
82 ty::GeneratorWitness(..) |
83 ty::UnnormalizedProjection(..) |
85 bug!("unexpected type {:?}", ty);
90 fn visit_from_env(&mut self, from_env: FromEnv<'tcx>) {
92 FromEnv::Trait(predicate) => {
94 self.tcx.program_clauses_for(predicate.def_id())
96 .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
101 FromEnv::Ty(ty) => self.visit_ty(ty),
105 fn visit_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>) {
106 // The only domain goals we can find in an environment are:
107 // * `DomainGoal::Holds(..)`
108 // * `DomainGoal::FromEnv(..)`
109 // The former do not lead to any implied bounds. So we only need
110 // to visit the latter.
111 if let DomainGoal::FromEnv(from_env) = domain_goal {
112 self.visit_from_env(from_env);
116 fn visit_program_clause(&mut self, clause: ProgramClause<'tcx>) {
117 self.visit_domain_goal(clause.goal);
118 // No need to visit `clause.hypotheses`: they are always of the form
119 // `FromEnv(...)` and were visited at a previous round.
122 fn visit_clause(&mut self, clause: Clause<'tcx>) {
124 Clause::Implies(clause) => self.visit_program_clause(clause),
125 Clause::ForAll(clause) => self.visit_program_clause(*clause.skip_binder()),
130 crate fn program_clauses_for_env<'a, 'tcx>(
131 tcx: TyCtxt<'a, 'tcx, 'tcx>,
132 environment: Environment<'tcx>,
134 debug!("program_clauses_for_env(environment={:?})", environment);
136 let mut last_round = FxHashSet::default();
138 let mut visitor = ClauseVisitor::new(tcx, &mut last_round);
139 for &clause in environment.clauses {
140 visitor.visit_clause(clause);
144 let mut closure = last_round.clone();
145 let mut next_round = FxHashSet::default();
146 while !last_round.is_empty() {
147 let mut visitor = ClauseVisitor::new(tcx, &mut next_round);
148 for clause in last_round.drain() {
149 visitor.visit_clause(clause);
152 next_round.drain().filter(|&clause| closure.insert(clause))
156 debug!("program_clauses_for_env: closure = {:#?}", closure);
158 return tcx.mk_clauses(
163 crate fn environment<'a, 'tcx>(
164 tcx: TyCtxt<'a, 'tcx, 'tcx>,
166 ) -> Environment<'tcx> {
167 use super::{Lower, IntoFromEnvGoal};
168 use rustc::hir::{Node, TraitItemKind, ImplItemKind, ItemKind, ForeignItemKind};
170 debug!("environment(def_id = {:?})", def_id);
172 // The environment of an impl Trait type is its defining function's environment.
173 if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
174 return environment(tcx, parent);
177 // Compute the bounds on `Self` and the type parameters.
178 let ty::InstantiatedPredicates { predicates } = tcx.predicates_of(def_id)
179 .instantiate_identity(tcx);
181 let clauses = predicates.into_iter()
182 .map(|predicate| predicate.lower())
183 .map(|domain_goal| domain_goal.map_bound(|bound| bound.into_from_env_goal()))
184 .map(|domain_goal| domain_goal.map_bound(|bound| bound.into_program_clause()))
186 // `ForAll` because each `domain_goal` is a `PolyDomainGoal` and
187 // could bound lifetimes.
188 .map(Clause::ForAll);
190 let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
191 let node = tcx.hir().get_by_hir_id(hir_id);
200 let node_kind = match node {
201 Node::TraitItem(item) => match item.node {
202 TraitItemKind::Method(..) => NodeKind::Fn,
203 _ => NodeKind::Other,
206 Node::ImplItem(item) => match item.node {
207 ImplItemKind::Method(..) => NodeKind::Fn,
208 _ => NodeKind::Other,
211 Node::Item(item) => match item.node {
212 ItemKind::Impl(.., Some(..), _, _) => NodeKind::TraitImpl,
213 ItemKind::Impl(.., None, _, _) => NodeKind::InherentImpl,
214 ItemKind::Fn(..) => NodeKind::Fn,
215 _ => NodeKind::Other,
218 Node::ForeignItem(item) => match item.node {
219 ForeignItemKind::Fn(..) => NodeKind::Fn,
220 _ => NodeKind::Other,
224 _ => NodeKind::Other,
227 let mut input_tys = FxHashSet::default();
230 // In a trait impl, we assume that the header trait ref and all its
231 // constituents are well-formed.
232 NodeKind::TraitImpl => {
233 let trait_ref = tcx.impl_trait_ref(def_id)
234 .expect("not an impl");
237 trait_ref.input_types().flat_map(|ty| ty.walk())
241 // In an inherent impl, we assume that the receiver type and all its
242 // constituents are well-formed.
243 NodeKind::InherentImpl => {
244 let self_ty = tcx.type_of(def_id);
245 input_tys.extend(self_ty.walk());
248 // In an fn, we assume that the arguments and all their constituents are
251 let fn_sig = tcx.fn_sig(def_id);
252 let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig);
255 fn_sig.inputs().iter().flat_map(|ty| ty.walk())
259 NodeKind::Other => (),
262 let clauses = clauses.chain(
263 input_tys.into_iter()
264 .map(|ty| DomainGoal::FromEnv(FromEnv::Ty(ty)))
265 .map(|domain_goal| domain_goal.into_program_clause())
266 .map(Clause::Implies)
269 debug!("environment: clauses = {:?}", clauses);
272 clauses: tcx.mk_clauses(clauses),