]> git.lizzy.rs Git - rust.git/blob - src/librustc_traits/chalk/lowering.rs
Update chalk and add LifetimeOutlives and ObjectSafe lowering
[rust.git] / src / librustc_traits / chalk / lowering.rs
1 //! Contains the logic to lower rustc types into Chalk types
2 //!
3 //! In many cases there is a 1:1 relationship between a rustc type and a Chalk type.
4 //! For example, a `SubstsRef` maps almost directly to a `Substitution`. In some
5 //! other cases, such as `Param`s, there is no Chalk type, so we have to handle
6 //! accordingly.
7 //!
8 //! ## `Ty` lowering
9 //! Much of the `Ty` lowering is 1:1 with Chalk. (Or will be eventually). A
10 //! helpful table for what types lower to what can be found in the
11 //! [Chalk book](http://rust-lang.github.io/chalk/book/types/rust_types.html).
12 //! The most notable difference lies with `Param`s. To convert from rustc to
13 //! Chalk, we eagerly and deeply convert `Param`s to placeholders (in goals) or
14 //! bound variables (for clause generation through functions in `db`).
15 //!
16 //! ## `Region` lowering
17 //! Regions are handled in rustc and Chalk is quite differently. In rustc, there
18 //! is a difference between "early bound" and "late bound" regions, where only
19 //! the late bound regions have a `DebruijnIndex`. Moreover, in Chalk all
20 //! regions (Lifetimes) have an associated index. In rustc, only `BrAnon`s have
21 //! an index, whereas `BrNamed` don't. In order to lower regions to Chalk, we
22 //! convert all regions into `BrAnon` late-bound regions.
23 //!
24 //! ## `Const` lowering
25 //! Chalk doesn't handle consts currently, so consts are currently lowered to
26 //! an empty tuple.
27 //!
28 //! ## Bound variable collection
29 //! Another difference between rustc and Chalk lies in the handling of binders.
30 //! Chalk requires that we store the bound parameter kinds, whereas rustc does
31 //! not. To lower anything wrapped in a `Binder`, we first deeply find any bound
32 //! variables from the current `Binder`.
33
34 use rustc_middle::traits::{
35     ChalkEnvironmentAndGoal, ChalkEnvironmentClause, ChalkRustInterner as RustInterner,
36 };
37 use rustc_middle::ty::fold::TypeFolder;
38 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
39 use rustc_middle::ty::{
40     self, Binder, BoundRegion, Region, RegionKind, Ty, TyCtxt, TyKind, TypeFoldable, TypeVisitor,
41 };
42 use rustc_span::def_id::DefId;
43
44 use std::collections::btree_map::{BTreeMap, Entry};
45
46 /// Essentially an `Into` with a `&RustInterner` parameter
47 crate trait LowerInto<'tcx, T> {
48     /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk type, consuming `self`.
49     fn lower_into(self, interner: &RustInterner<'tcx>) -> T;
50 }
51
52 impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution<RustInterner<'tcx>>> for SubstsRef<'tcx> {
53     fn lower_into(
54         self,
55         interner: &RustInterner<'tcx>,
56     ) -> chalk_ir::Substitution<RustInterner<'tcx>> {
57         chalk_ir::Substitution::from(interner, self.iter().map(|s| s.lower_into(interner)))
58     }
59 }
60
61 impl<'tcx> LowerInto<'tcx, chalk_ir::AliasTy<RustInterner<'tcx>>> for ty::ProjectionTy<'tcx> {
62     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::AliasTy<RustInterner<'tcx>> {
63         chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
64             associated_ty_id: chalk_ir::AssocTypeId(self.item_def_id),
65             substitution: self.substs.lower_into(interner),
66         })
67     }
68 }
69
70 impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>>>
71     for ChalkEnvironmentAndGoal<'tcx>
72 {
73     fn lower_into(
74         self,
75         interner: &RustInterner<'tcx>,
76     ) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> {
77         let clauses = self.environment.into_iter().filter_map(|clause| match clause {
78             ChalkEnvironmentClause::Predicate(predicate) => {
79                 match predicate.kind() {
80                     ty::PredicateKind::Trait(predicate, _) => {
81                         let (predicate, binders, _named_regions) =
82                             collect_bound_vars(interner, interner.tcx, predicate);
83
84                         Some(
85                             chalk_ir::ProgramClauseData::ForAll(chalk_ir::Binders::new(
86                                 binders,
87                                 chalk_ir::ProgramClauseImplication {
88                                     consequence: chalk_ir::DomainGoal::FromEnv(
89                                         chalk_ir::FromEnv::Trait(
90                                             predicate.trait_ref.lower_into(interner),
91                                         ),
92                                     ),
93                                     conditions: chalk_ir::Goals::new(interner),
94                                     priority: chalk_ir::ClausePriority::High,
95                                 },
96                             ))
97                             .intern(interner),
98                         )
99                     }
100                     ty::PredicateKind::RegionOutlives(predicate) => {
101                         let (predicate, binders, _named_regions) =
102                             collect_bound_vars(interner, interner.tcx, predicate);
103         
104                         Some(
105                             chalk_ir::ProgramClauseData::ForAll(chalk_ir::Binders::new(
106                                 binders,
107                                 chalk_ir::ProgramClauseImplication {
108                                     consequence: chalk_ir::DomainGoal::Holds(
109                                         chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
110                                             a: predicate.0.lower_into(interner),
111                                             b: predicate.1.lower_into(interner),
112                                         })
113                                     ),
114                                     conditions: chalk_ir::Goals::new(interner),
115                                     priority: chalk_ir::ClausePriority::High,
116                                 },
117                             ))
118                             .intern(interner),
119                         )
120                     },
121                     // FIXME(chalk): need to add TypeOutlives
122                     ty::PredicateKind::TypeOutlives(_) => None,
123                     ty::PredicateKind::Projection(predicate) => {
124                         let (predicate, binders, _named_regions) =
125                             collect_bound_vars(interner, interner.tcx, predicate);
126
127                         Some(
128                             chalk_ir::ProgramClauseData::ForAll(chalk_ir::Binders::new(
129                                 binders,
130                                 chalk_ir::ProgramClauseImplication {
131                                     consequence: chalk_ir::DomainGoal::Holds(
132                                         chalk_ir::WhereClause::AliasEq(
133                                             predicate.lower_into(interner),
134                                         ),
135                                     ),
136                                     conditions: chalk_ir::Goals::new(interner),
137                                     priority: chalk_ir::ClausePriority::High,
138                                 },
139                             ))
140                             .intern(interner),
141                         )
142                     }
143                     ty::PredicateKind::WellFormed(..)
144                     | ty::PredicateKind::ObjectSafe(..)
145                     | ty::PredicateKind::ClosureKind(..)
146                     | ty::PredicateKind::Subtype(..)
147                     | ty::PredicateKind::ConstEvaluatable(..)
148                     | ty::PredicateKind::ConstEquate(..) => {
149                         bug!("unexpected predicate {}", predicate)
150                     }
151                 }
152             }
153             ChalkEnvironmentClause::TypeFromEnv(ty) => Some(
154                 chalk_ir::ProgramClauseData::Implies(chalk_ir::ProgramClauseImplication {
155                     consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(
156                         ty.lower_into(interner),
157                     )),
158                     conditions: chalk_ir::Goals::new(interner),
159                     priority: chalk_ir::ClausePriority::High,
160                 })
161                 .intern(interner),
162             ),
163         });
164
165         let goal: chalk_ir::GoalData<RustInterner<'tcx>> = self.goal.lower_into(&interner);
166         chalk_ir::InEnvironment {
167             environment: chalk_ir::Environment {
168                 clauses: chalk_ir::ProgramClauses::from(&interner, clauses),
169             },
170             goal: goal.intern(&interner),
171         }
172     }
173 }
174
175 impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predicate<'tcx> {
176     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> {
177         match self.kind() {
178             ty::PredicateKind::Trait(predicate, _) => predicate.lower_into(interner),
179             ty::PredicateKind::RegionOutlives(predicate) => {
180                 let (predicate, binders, _named_regions) =
181                     collect_bound_vars(interner, interner.tcx, predicate);
182
183                 chalk_ir::GoalData::Quantified(
184                     chalk_ir::QuantifierKind::ForAll,
185                     chalk_ir::Binders::new(
186                         binders,
187                         chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
188                             chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
189                                 a: predicate.0.lower_into(interner),
190                                 b: predicate.1.lower_into(interner),
191                             })
192                         )).intern(interner)
193                     )
194                 )
195             }
196             // FIXME(chalk): TypeOutlives
197             ty::PredicateKind::TypeOutlives(_predicate) => {
198                 chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
199             }
200             ty::PredicateKind::Projection(predicate) => predicate.lower_into(interner),
201             ty::PredicateKind::WellFormed(arg) => match arg.unpack() {
202                 GenericArgKind::Type(ty) => match ty.kind {
203                     // FIXME(chalk): In Chalk, a placeholder is WellFormed if it
204                     // `FromEnv`. However, when we "lower" Params, we don't update
205                     // the environment.
206                     ty::Placeholder(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)),
207
208                     _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed(
209                         chalk_ir::WellFormed::Ty(ty.lower_into(interner)),
210                     )),
211                 },
212                 // FIXME(chalk): handle well formed consts
213                 GenericArgKind::Const(..) => {
214                     chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
215                 }
216                 GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt),
217             },
218
219             ty::PredicateKind::ObjectSafe(t) => {
220                 chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(*t)))
221             }
222
223             // FIXME(chalk): other predicates
224             //
225             // We can defer this, but ultimately we'll want to express
226             // some of these in terms of chalk operations.
227             ty::PredicateKind::ClosureKind(..)
228             | ty::PredicateKind::Subtype(..)
229             | ty::PredicateKind::ConstEvaluatable(..)
230             | ty::PredicateKind::ConstEquate(..) => {
231                 chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
232             }
233         }
234     }
235 }
236
237 impl<'tcx> LowerInto<'tcx, chalk_ir::TraitRef<RustInterner<'tcx>>>
238     for rustc_middle::ty::TraitRef<'tcx>
239 {
240     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::TraitRef<RustInterner<'tcx>> {
241         chalk_ir::TraitRef {
242             trait_id: chalk_ir::TraitId(self.def_id),
243             substitution: self.substs.lower_into(interner),
244         }
245     }
246 }
247
248 impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>>
249     for ty::PolyTraitPredicate<'tcx>
250 {
251     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> {
252         let (ty, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self);
253
254         chalk_ir::GoalData::Quantified(
255             chalk_ir::QuantifierKind::ForAll,
256             chalk_ir::Binders::new(
257                 binders,
258                 chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
259                     chalk_ir::WhereClause::Implemented(ty.trait_ref.lower_into(interner)),
260                 ))
261                 .intern(interner),
262             ),
263         )
264     }
265 }
266
267 impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>>
268     for rustc_middle::ty::ProjectionPredicate<'tcx>
269 {
270     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> {
271         chalk_ir::AliasEq {
272             ty: self.ty.lower_into(interner),
273             alias: self.projection_ty.lower_into(interner),
274         }
275     }
276 }
277
278 impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>>
279     for ty::PolyProjectionPredicate<'tcx>
280 {
281     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> {
282         let (ty, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self);
283
284         chalk_ir::GoalData::Quantified(
285             chalk_ir::QuantifierKind::ForAll,
286             chalk_ir::Binders::new(
287                 binders,
288                 chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
289                     chalk_ir::WhereClause::AliasEq(ty.lower_into(interner)),
290                 ))
291                 .intern(interner),
292             ),
293         )
294     }
295 }
296
297 impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
298     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
299         use chalk_ir::TyData;
300         use rustc_ast::ast;
301         use TyKind::*;
302
303         let empty = || chalk_ir::Substitution::empty(interner);
304         let struct_ty = |def_id| chalk_ir::TypeName::Adt(chalk_ir::AdtId(def_id));
305         let apply = |name, substitution| {
306             TyData::Apply(chalk_ir::ApplicationTy { name, substitution }).intern(interner)
307         };
308         let int = |i| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Int(i)), empty());
309         let uint = |i| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Uint(i)), empty());
310         let float = |f| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Float(f)), empty());
311
312         match self.kind {
313             Bool => apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Bool), empty()),
314             Char => apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Char), empty()),
315             Int(ty) => match ty {
316                 ast::IntTy::Isize => int(chalk_ir::IntTy::Isize),
317                 ast::IntTy::I8 => int(chalk_ir::IntTy::I8),
318                 ast::IntTy::I16 => int(chalk_ir::IntTy::I16),
319                 ast::IntTy::I32 => int(chalk_ir::IntTy::I32),
320                 ast::IntTy::I64 => int(chalk_ir::IntTy::I64),
321                 ast::IntTy::I128 => int(chalk_ir::IntTy::I128),
322             },
323             Uint(ty) => match ty {
324                 ast::UintTy::Usize => uint(chalk_ir::UintTy::Usize),
325                 ast::UintTy::U8 => uint(chalk_ir::UintTy::U8),
326                 ast::UintTy::U16 => uint(chalk_ir::UintTy::U16),
327                 ast::UintTy::U32 => uint(chalk_ir::UintTy::U32),
328                 ast::UintTy::U64 => uint(chalk_ir::UintTy::U64),
329                 ast::UintTy::U128 => uint(chalk_ir::UintTy::U128),
330             },
331             Float(ty) => match ty {
332                 ast::FloatTy::F32 => float(chalk_ir::FloatTy::F32),
333                 ast::FloatTy::F64 => float(chalk_ir::FloatTy::F64),
334             },
335             Adt(def, substs) => apply(struct_ty(def.did), substs.lower_into(interner)),
336             Foreign(_def_id) => unimplemented!(),
337             Str => apply(chalk_ir::TypeName::Str, empty()),
338             Array(ty, _) => apply(
339                 chalk_ir::TypeName::Array,
340                 chalk_ir::Substitution::from(
341                     interner,
342                     &[
343                         chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
344                         chalk_ir::GenericArgData::Const(
345                             chalk_ir::ConstData {
346                                 ty: apply(chalk_ir::TypeName::Tuple(0), empty()),
347                                 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
348                                     interned: 0,
349                                 }),
350                             }
351                             .intern(interner),
352                         )
353                         .intern(interner),
354                     ],
355                 ),
356             ),
357             Slice(ty) => apply(
358                 chalk_ir::TypeName::Slice,
359                 chalk_ir::Substitution::from1(
360                     interner,
361                     chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
362                 ),
363             ),
364             RawPtr(ptr) => {
365                 let name = match ptr.mutbl {
366                     ast::Mutability::Mut => chalk_ir::TypeName::Raw(chalk_ir::Mutability::Mut),
367                     ast::Mutability::Not => chalk_ir::TypeName::Raw(chalk_ir::Mutability::Not),
368                 };
369                 apply(name, chalk_ir::Substitution::from1(interner, ptr.ty.lower_into(interner)))
370             }
371             Ref(region, ty, mutability) => {
372                 let name = match mutability {
373                     ast::Mutability::Mut => chalk_ir::TypeName::Ref(chalk_ir::Mutability::Mut),
374                     ast::Mutability::Not => chalk_ir::TypeName::Ref(chalk_ir::Mutability::Not),
375                 };
376                 apply(
377                     name,
378                     chalk_ir::Substitution::from(
379                         interner,
380                         &[
381                             chalk_ir::GenericArgData::Lifetime(region.lower_into(interner))
382                                 .intern(interner),
383                             chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
384                         ],
385                     ),
386                 )
387             }
388             FnDef(def_id, substs) => apply(
389                 chalk_ir::TypeName::FnDef(chalk_ir::FnDefId(def_id)),
390                 substs.lower_into(interner),
391             ),
392             FnPtr(sig) => {
393                 let (inputs_and_outputs, binders, _named_regions) =
394                     collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output());
395                 TyData::Function(chalk_ir::Fn {
396                     num_binders: binders.len(interner),
397                     substitution: chalk_ir::Substitution::from(
398                         interner,
399                         inputs_and_outputs.iter().map(|ty| {
400                             chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner)
401                         }),
402                     ),
403                 })
404                 .intern(interner)
405             }
406             // FIXME(chalk): add region
407             Dynamic(predicates, _region) => {
408                 TyData::Dyn(chalk_ir::DynTy { bounds: predicates.lower_into(interner) })
409                     .intern(interner)
410             }
411             Closure(_def_id, _) => unimplemented!(),
412             Generator(_def_id, _substs, _) => unimplemented!(),
413             GeneratorWitness(_) => unimplemented!(),
414             Never => apply(chalk_ir::TypeName::Never, empty()),
415             Tuple(substs) => {
416                 apply(chalk_ir::TypeName::Tuple(substs.len()), substs.lower_into(interner))
417             }
418             Projection(proj) => TyData::Alias(proj.lower_into(interner)).intern(interner),
419             Opaque(def_id, substs) => {
420                 TyData::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
421                     opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
422                     substitution: substs.lower_into(interner),
423                 }))
424                 .intern(interner)
425             }
426             // This should have been done eagerly prior to this, and all Params
427             // should have been substituted to placeholders
428             Param(_) => panic!("Lowering Param when not expected."),
429             Bound(db, bound) => TyData::BoundVar(chalk_ir::BoundVar::new(
430                 chalk_ir::DebruijnIndex::new(db.as_u32()),
431                 bound.var.index(),
432             ))
433             .intern(interner),
434             Placeholder(_placeholder) => TyData::Placeholder(chalk_ir::PlaceholderIndex {
435                 ui: chalk_ir::UniverseIndex { counter: _placeholder.universe.as_usize() },
436                 idx: _placeholder.name.as_usize(),
437             })
438             .intern(interner),
439             Infer(_infer) => unimplemented!(),
440             Error(_) => apply(chalk_ir::TypeName::Error, empty()),
441         }
442     }
443 }
444
445 impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime<RustInterner<'tcx>>> for Region<'tcx> {
446     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Lifetime<RustInterner<'tcx>> {
447         use rustc_middle::ty::RegionKind::*;
448
449         match self {
450             ReEarlyBound(_) => {
451                 panic!("Should have already been substituted.");
452             }
453             ReLateBound(db, br) => match br {
454                 ty::BoundRegion::BrAnon(var) => {
455                     chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(
456                         chalk_ir::DebruijnIndex::new(db.as_u32()),
457                         *var as usize,
458                     ))
459                     .intern(interner)
460                 }
461                 ty::BoundRegion::BrNamed(_def_id, _name) => unimplemented!(),
462                 ty::BrEnv => unimplemented!(),
463             },
464             ReFree(_) => unimplemented!(),
465             // FIXME(chalk): need to handle ReStatic
466             ReStatic => unimplemented!(),
467             ReVar(_) => unimplemented!(),
468             RePlaceholder(placeholder_region) => {
469                 chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex {
470                     ui: chalk_ir::UniverseIndex { counter: placeholder_region.universe.index() },
471                     idx: 0,
472                 })
473                 .intern(interner)
474             }
475             ReEmpty(_) => unimplemented!(),
476             // FIXME(chalk): need to handle ReErased
477             ReErased => unimplemented!(),
478         }
479     }
480 }
481
482 impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg<RustInterner<'tcx>>> for GenericArg<'tcx> {
483     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GenericArg<RustInterner<'tcx>> {
484         match self.unpack() {
485             ty::subst::GenericArgKind::Type(ty) => {
486                 chalk_ir::GenericArgData::Ty(ty.lower_into(interner))
487             }
488             ty::subst::GenericArgKind::Lifetime(lifetime) => {
489                 chalk_ir::GenericArgData::Lifetime(lifetime.lower_into(interner))
490             }
491             ty::subst::GenericArgKind::Const(_) => chalk_ir::GenericArgData::Ty(
492                 chalk_ir::TyData::Apply(chalk_ir::ApplicationTy {
493                     name: chalk_ir::TypeName::Tuple(0),
494                     substitution: chalk_ir::Substitution::empty(interner),
495                 })
496                 .intern(interner),
497             ),
498         }
499         .intern(interner)
500     }
501 }
502
503 // We lower into an Option here since there are some predicates which Chalk
504 // doesn't have a representation for yet (as a `WhereClause`), but are so common
505 // that we just are accepting the unsoundness for now. The `Option` will
506 // eventually be removed.
507 impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>
508     for ty::Predicate<'tcx>
509 {
510     fn lower_into(
511         self,
512         interner: &RustInterner<'tcx>,
513     ) -> Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
514         match &self.kind() {
515             ty::PredicateKind::Trait(predicate, _) => {
516                 let (predicate, binders, _named_regions) =
517                     collect_bound_vars(interner, interner.tcx, predicate);
518
519                 Some(chalk_ir::Binders::new(
520                     binders,
521                     chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)),
522                 ))
523             }
524             ty::PredicateKind::RegionOutlives(predicate) => {
525                 let (predicate, binders, _named_regions) =
526                     collect_bound_vars(interner, interner.tcx, predicate);
527
528                 Some(chalk_ir::Binders::new(
529                     binders,
530                     chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
531                         a: predicate.0.lower_into(interner),
532                         b: predicate.1.lower_into(interner),
533                     }),
534                 ))
535
536             },
537             ty::PredicateKind::TypeOutlives(_predicate) => None,
538             ty::PredicateKind::Projection(_predicate) => None,
539             ty::PredicateKind::WellFormed(_ty) => None,
540
541             ty::PredicateKind::ObjectSafe(..)
542             | ty::PredicateKind::ClosureKind(..)
543             | ty::PredicateKind::Subtype(..)
544             | ty::PredicateKind::ConstEvaluatable(..)
545             | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", &self),
546         }
547     }
548 }
549
550 impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>>>
551     for Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>
552 {
553     fn lower_into(
554         self,
555         interner: &RustInterner<'tcx>,
556     ) -> chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>> {
557         let (predicates, binders, _named_regions) =
558             collect_bound_vars(interner, interner.tcx, &self);
559         let where_clauses = predicates.into_iter().map(|predicate| match predicate {
560             ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => {
561                 chalk_ir::Binders::new(
562                     chalk_ir::VariableKinds::new(interner),
563                     chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
564                         trait_id: chalk_ir::TraitId(*def_id),
565                         substitution: substs.lower_into(interner),
566                     }),
567                 )
568             }
569             ty::ExistentialPredicate::Projection(_predicate) => unimplemented!(),
570             ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
571                 chalk_ir::VariableKinds::new(interner),
572                 chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
573                     trait_id: chalk_ir::TraitId(*def_id),
574                     substitution: chalk_ir::Substitution::empty(interner),
575                 }),
576             ),
577         });
578         let value = chalk_ir::QuantifiedWhereClauses::from(interner, where_clauses);
579         chalk_ir::Binders::new(binders, value)
580     }
581 }
582
583 /// To collect bound vars, we have to do two passes. In the first pass, we
584 /// collect all `BoundRegion`s and `ty::Bound`s. In the second pass, we then
585 /// replace `BrNamed` into `BrAnon`. The two separate passes are important,
586 /// since we can only replace `BrNamed` with `BrAnon`s with indices *after* all
587 /// "real" `BrAnon`s.
588 ///
589 /// It's important to note that because of prior substitution, we may have
590 /// late-bound regions, even outside of fn contexts, since this is the best way
591 /// to prep types for chalk lowering.
592 crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>(
593     interner: &RustInterner<'tcx>,
594     tcx: TyCtxt<'tcx>,
595     ty: &'a Binder<T>,
596 ) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
597     let mut bound_vars_collector = BoundVarsCollector::new();
598     ty.skip_binder().visit_with(&mut bound_vars_collector);
599     let mut parameters = bound_vars_collector.parameters;
600     let named_parameters: BTreeMap<DefId, u32> = bound_vars_collector
601         .named_parameters
602         .into_iter()
603         .enumerate()
604         .map(|(i, def_id)| (def_id, (i + parameters.len()) as u32))
605         .collect();
606
607     let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters);
608     let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor);
609
610     for var in named_parameters.values() {
611         parameters.insert(*var, chalk_ir::VariableKind::Lifetime);
612     }
613
614     (0..parameters.len()).for_each(|i| {
615         parameters.get(&(i as u32)).expect("Skipped bound var index.");
616     });
617
618     let binders = chalk_ir::VariableKinds::from(interner, parameters.into_iter().map(|(_, v)| v));
619
620     (new_ty, binders, named_parameters)
621 }
622
623 crate struct BoundVarsCollector<'tcx> {
624     binder_index: ty::DebruijnIndex,
625     crate parameters: BTreeMap<u32, chalk_ir::VariableKind<RustInterner<'tcx>>>,
626     crate named_parameters: Vec<DefId>,
627 }
628
629 impl<'tcx> BoundVarsCollector<'tcx> {
630     crate fn new() -> Self {
631         BoundVarsCollector {
632             binder_index: ty::INNERMOST,
633             parameters: BTreeMap::new(),
634             named_parameters: vec![],
635         }
636     }
637 }
638
639 impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
640     fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
641         self.binder_index.shift_in(1);
642         let result = t.super_visit_with(self);
643         self.binder_index.shift_out(1);
644         result
645     }
646
647     fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
648         match t.kind {
649             ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
650                 match self.parameters.entry(bound_ty.var.as_u32()) {
651                     Entry::Vacant(entry) => {
652                         entry.insert(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General));
653                     }
654                     Entry::Occupied(entry) => match entry.get() {
655                         chalk_ir::VariableKind::Ty(_) => {}
656                         _ => panic!(),
657                     },
658                 }
659             }
660
661             _ => (),
662         };
663
664         t.super_visit_with(self)
665     }
666
667     fn visit_region(&mut self, r: Region<'tcx>) -> bool {
668         match r {
669             ty::ReLateBound(index, br) if *index == self.binder_index => match br {
670                 ty::BoundRegion::BrNamed(def_id, _name) => {
671                     if self.named_parameters.iter().find(|d| *d == def_id).is_none() {
672                         self.named_parameters.push(*def_id);
673                     }
674                 }
675
676                 ty::BoundRegion::BrAnon(var) => match self.parameters.entry(*var) {
677                     Entry::Vacant(entry) => {
678                         entry.insert(chalk_ir::VariableKind::Lifetime);
679                     }
680                     Entry::Occupied(entry) => match entry.get() {
681                         chalk_ir::VariableKind::Lifetime => {}
682                         _ => panic!(),
683                     },
684                 },
685
686                 ty::BrEnv => unimplemented!(),
687             },
688
689             ty::ReEarlyBound(_re) => {
690                 // FIXME(chalk): jackh726 - I think we should always have already
691                 // substituted away `ReEarlyBound`s for `ReLateBound`s, but need to confirm.
692                 unimplemented!();
693             }
694
695             _ => (),
696         };
697
698         r.super_visit_with(self)
699     }
700 }
701
702 /// This is used to replace `BoundRegion::BrNamed` with `BoundRegion::BrAnon`.
703 /// Note: we assume that we will always have room for more bound vars. (i.e. we
704 /// won't ever hit the `u32` limit in `BrAnon`s).
705 struct NamedBoundVarSubstitutor<'a, 'tcx> {
706     tcx: TyCtxt<'tcx>,
707     binder_index: ty::DebruijnIndex,
708     named_parameters: &'a BTreeMap<DefId, u32>,
709 }
710
711 impl<'a, 'tcx> NamedBoundVarSubstitutor<'a, 'tcx> {
712     fn new(tcx: TyCtxt<'tcx>, named_parameters: &'a BTreeMap<DefId, u32>) -> Self {
713         NamedBoundVarSubstitutor { tcx, binder_index: ty::INNERMOST, named_parameters }
714     }
715 }
716
717 impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> {
718     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
719         self.tcx
720     }
721
722     fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> Binder<T> {
723         self.binder_index.shift_in(1);
724         let result = t.super_fold_with(self);
725         self.binder_index.shift_out(1);
726         result
727     }
728
729     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
730         t.super_fold_with(self)
731     }
732
733     fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
734         match r {
735             ty::ReLateBound(index, br) if *index == self.binder_index => match br {
736                 ty::BoundRegion::BrNamed(def_id, _name) => {
737                     match self.named_parameters.get(def_id) {
738                         Some(idx) => {
739                             return self.tcx.mk_region(RegionKind::ReLateBound(
740                                 *index,
741                                 BoundRegion::BrAnon(*idx),
742                             ));
743                         }
744                         None => panic!("Missing `BrNamed`."),
745                     }
746                 }
747                 ty::BrEnv => unimplemented!(),
748                 ty::BoundRegion::BrAnon(_) => {}
749             },
750             _ => (),
751         };
752
753         r.super_fold_with(self)
754     }
755 }
756
757 /// Used to substitute `Param`s with placeholders. We do this since Chalk
758 /// have a notion of `Param`s.
759 crate struct ParamsSubstitutor<'tcx> {
760     tcx: TyCtxt<'tcx>,
761     binder_index: ty::DebruijnIndex,
762     list: Vec<rustc_middle::ty::ParamTy>,
763     crate params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
764     crate named_regions: BTreeMap<DefId, u32>,
765 }
766
767 impl<'tcx> ParamsSubstitutor<'tcx> {
768     crate fn new(tcx: TyCtxt<'tcx>) -> Self {
769         ParamsSubstitutor {
770             tcx,
771             binder_index: ty::INNERMOST,
772             list: vec![],
773             params: rustc_data_structures::fx::FxHashMap::default(),
774             named_regions: BTreeMap::default(),
775         }
776     }
777 }
778
779 impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
780     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
781         self.tcx
782     }
783
784     fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> Binder<T> {
785         self.binder_index.shift_in(1);
786         let result = t.super_fold_with(self);
787         self.binder_index.shift_out(1);
788         result
789     }
790
791     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
792         match t.kind {
793             // FIXME(chalk): currently we convert params to placeholders starting at
794             // index `0`. To support placeholders, we'll actually need to do a
795             // first pass to collect placeholders. Then we can insert params after.
796             ty::Placeholder(_) => unimplemented!(),
797             ty::Param(param) => match self.list.iter().position(|r| r == &param) {
798                 Some(_idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
799                     universe: ty::UniverseIndex::from_usize(0),
800                     name: ty::BoundVar::from_usize(_idx),
801                 })),
802                 None => {
803                     self.list.push(param);
804                     let idx = self.list.len() - 1;
805                     self.params.insert(idx, param);
806                     self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
807                         universe: ty::UniverseIndex::from_usize(0),
808                         name: ty::BoundVar::from_usize(idx),
809                     }))
810                 }
811             },
812
813             _ => t.super_fold_with(self),
814         }
815     }
816
817     fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
818         match r {
819             // FIXME(chalk) - jackh726 - this currently isn't hit in any tests.
820             // This covers any region variables in a goal, right?
821             ty::ReEarlyBound(_re) => match self.named_regions.get(&_re.def_id) {
822                 Some(idx) => self.tcx.mk_region(RegionKind::ReLateBound(
823                     self.binder_index,
824                     BoundRegion::BrAnon(*idx),
825                 )),
826                 None => {
827                     let idx = self.named_regions.len() as u32;
828                     self.named_regions.insert(_re.def_id, idx);
829                     self.tcx.mk_region(RegionKind::ReLateBound(
830                         self.binder_index,
831                         BoundRegion::BrAnon(idx),
832                     ))
833                 }
834             },
835
836             _ => r.super_fold_with(self),
837         }
838     }
839 }