2 Clause, Clauses, DomainGoal, Environment, FromEnv, ProgramClause, ProgramClauseCategory,
4 use rustc::ty::{self, Ty, TyCtxt};
5 use rustc_data_structures::fx::FxHashSet;
6 use rustc_hir::def_id::DefId;
8 struct ClauseVisitor<'a, 'tcx> {
10 round: &'a mut FxHashSet<Clause<'tcx>>,
13 impl ClauseVisitor<'a, 'tcx> {
14 fn new(tcx: TyCtxt<'tcx>, round: &'a mut FxHashSet<Clause<'tcx>>) -> Self {
15 ClauseVisitor { tcx, round }
18 fn visit_ty(&mut self, ty: Ty<'tcx>) {
20 ty::Projection(data) => {
23 .program_clauses_for(data.item_def_id)
25 .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
31 // FIXME: trait object rules are not yet implemented
37 .program_clauses_for(def.did)
39 .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
45 | ty::FnDef(def_id, ..)
46 | ty::Closure(def_id, ..)
47 | ty::Generator(def_id, ..)
48 | ty::Opaque(def_id, ..) => {
51 .program_clauses_for(def_id)
53 .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
74 | ty::Bound(..) => (),
76 ty::GeneratorWitness(..) | ty::UnnormalizedProjection(..) | ty::Error => {
77 bug!("unexpected type {:?}", ty);
82 fn visit_from_env(&mut self, from_env: FromEnv<'tcx>) {
84 FromEnv::Trait(predicate) => {
87 .program_clauses_for(predicate.def_id())
89 .filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
94 FromEnv::Ty(ty) => self.visit_ty(ty),
98 fn visit_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>) {
99 // The only domain goals we can find in an environment are:
100 // * `DomainGoal::Holds(..)`
101 // * `DomainGoal::FromEnv(..)`
102 // The former do not lead to any implied bounds. So we only need
103 // to visit the latter.
104 if let DomainGoal::FromEnv(from_env) = domain_goal {
105 self.visit_from_env(from_env);
109 fn visit_program_clause(&mut self, clause: ProgramClause<'tcx>) {
110 self.visit_domain_goal(clause.goal);
111 // No need to visit `clause.hypotheses`: they are always of the form
112 // `FromEnv(...)` and were visited at a previous round.
115 fn visit_clause(&mut self, clause: Clause<'tcx>) {
117 Clause::Implies(clause) => self.visit_program_clause(clause),
118 Clause::ForAll(clause) => self.visit_program_clause(*clause.skip_binder()),
123 crate fn program_clauses_for_env<'tcx>(
125 environment: Environment<'tcx>,
127 debug!("program_clauses_for_env(environment={:?})", environment);
129 let mut last_round = FxHashSet::default();
131 let mut visitor = ClauseVisitor::new(tcx, &mut last_round);
132 for &clause in environment.clauses {
133 visitor.visit_clause(clause);
137 let mut closure = last_round.clone();
138 let mut next_round = FxHashSet::default();
139 while !last_round.is_empty() {
140 let mut visitor = ClauseVisitor::new(tcx, &mut next_round);
141 for clause in last_round.drain() {
142 visitor.visit_clause(clause);
144 last_round.extend(next_round.drain().filter(|&clause| closure.insert(clause)));
147 debug!("program_clauses_for_env: closure = {:#?}", closure);
149 return tcx.mk_clauses(closure.into_iter());
152 crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> {
153 use super::{IntoFromEnvGoal, Lower};
154 use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind};
156 debug!("environment(def_id = {:?})", def_id);
158 // The environment of an impl Trait type is its defining function's environment.
159 if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
160 return environment(tcx, parent);
163 // Compute the bounds on `Self` and the type parameters.
164 let ty::InstantiatedPredicates { predicates, .. } =
165 tcx.predicates_of(def_id).instantiate_identity(tcx);
167 let clauses = predicates
169 .map(|predicate| predicate.lower())
170 .map(|domain_goal| domain_goal.map_bound(|bound| bound.into_from_env_goal()))
171 .map(|domain_goal| domain_goal.map_bound(|bound| bound.into_program_clause()))
172 // `ForAll` because each `domain_goal` is a `PolyDomainGoal` and
173 // could bound lifetimes.
174 .map(Clause::ForAll);
176 let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
177 let node = tcx.hir().get(hir_id);
186 let node_kind = match node {
187 Node::TraitItem(item) => match item.kind {
188 TraitItemKind::Fn(..) => NodeKind::Fn,
189 _ => NodeKind::Other,
192 Node::ImplItem(item) => match item.kind {
193 ImplItemKind::Fn(..) => NodeKind::Fn,
194 _ => NodeKind::Other,
197 Node::Item(item) => match item.kind {
198 ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl,
199 ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl,
200 ItemKind::Fn(..) => NodeKind::Fn,
201 _ => NodeKind::Other,
204 Node::ForeignItem(item) => match item.kind {
205 ForeignItemKind::Fn(..) => NodeKind::Fn,
206 _ => NodeKind::Other,
210 _ => NodeKind::Other,
213 let mut input_tys = FxHashSet::default();
216 // In a trait impl, we assume that the header trait ref and all its
217 // constituents are well-formed.
218 NodeKind::TraitImpl => {
219 let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
221 input_tys.extend(trait_ref.input_types().flat_map(|ty| ty.walk()));
224 // In an inherent impl, we assume that the receiver type and all its
225 // constituents are well-formed.
226 NodeKind::InherentImpl => {
227 let self_ty = tcx.type_of(def_id);
228 input_tys.extend(self_ty.walk());
231 // In an fn, we assume that the arguments and all their constituents are
234 let fn_sig = tcx.fn_sig(def_id);
235 let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig);
237 input_tys.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
240 NodeKind::Other => (),
243 let clauses = clauses.chain(
246 .map(|ty| DomainGoal::FromEnv(FromEnv::Ty(ty)))
247 .map(|domain_goal| domain_goal.into_program_clause())
248 .map(Clause::Implies),
251 debug!("environment: clauses = {:?}", clauses);
253 Environment { clauses: tcx.mk_clauses(clauses) }