1 //! Unification and canonicalization logic.
3 use std::{fmt, mem, sync::Arc};
6 cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
7 IntTy, NoSolution, TyVariableKind, UniverseIndex,
9 use chalk_solve::infer::ParameterEnaVariableExt;
10 use ena::unify::UnifyKey;
14 use super::{InferOk, InferResult, InferenceContext, TypeError};
16 db::HirDatabase, fold_tys, static_lifetime, traits::FnTrait, AliasEq, AliasTy, BoundVar,
17 Canonical, Const, DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment,
18 InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution,
19 Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
22 impl<'a> InferenceContext<'a> {
23 pub(super) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
28 T: HasInterner<Interner = Interner>,
30 self.table.canonicalize(t)
34 #[derive(Debug, Clone)]
35 pub(crate) struct Canonicalized<T>
37 T: HasInterner<Interner = Interner>,
39 pub(crate) value: Canonical<T>,
40 free_vars: Vec<GenericArg>,
43 impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
44 pub(super) fn apply_solution(
46 ctx: &mut InferenceTable<'_>,
47 solution: Canonical<Substitution>,
49 // the solution may contain new variables, which we need to convert to new inference vars
50 let new_vars = Substitution::from_iter(
52 solution.binders.iter(Interner).map(|k| match &k.kind {
53 VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(Interner),
54 VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner),
55 VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(Interner),
56 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
57 VariableKind::Lifetime => static_lifetime().cast(Interner),
58 VariableKind::Const(ty) => ctx.new_const_var(ty.clone()).cast(Interner),
61 for (i, v) in solution.value.iter(Interner).enumerate() {
62 let var = self.free_vars[i].clone();
63 if let Some(ty) = v.ty(Interner) {
64 // eagerly replace projections in the type; we may be getting types
65 // e.g. from where clauses where this hasn't happened yet
66 let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner));
67 ctx.unify(var.assert_ty_ref(Interner), &ty);
69 let _ = ctx.try_unify(&var, &new_vars.apply(v.clone(), Interner));
77 env: Arc<TraitEnvironment>,
78 tys: &Canonical<(Ty, Ty)>,
80 unify(db, env, tys).is_some()
85 env: Arc<TraitEnvironment>,
86 tys: &Canonical<(Ty, Ty)>,
87 ) -> Option<Substitution> {
88 let mut table = InferenceTable::new(db, env);
89 let vars = Substitution::from_iter(
91 tys.binders.iter(Interner).map(|x| match &x.kind {
92 chalk_ir::VariableKind::Ty(_) => {
93 GenericArgData::Ty(table.new_type_var()).intern(Interner)
95 chalk_ir::VariableKind::Lifetime => {
96 GenericArgData::Ty(table.new_type_var()).intern(Interner)
97 } // FIXME: maybe wrong?
98 chalk_ir::VariableKind::Const(ty) => {
99 GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
103 let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
104 let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
105 if !table.unify(&ty1_with_vars, &ty2_with_vars) {
108 // default any type vars that weren't unified back to their original bound vars
110 let find_var = |iv| {
111 vars.iter(Interner).position(|v| match v.interned() {
112 chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
113 chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
114 chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
117 let fallback = |iv, kind, default, binder| match kind {
118 chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
119 .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
120 chalk_ir::VariableKind::Lifetime => find_var(iv)
121 .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)),
122 chalk_ir::VariableKind::Const(ty) => find_var(iv)
123 .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)),
125 Some(Substitution::from_iter(
127 vars.iter(Interner).map(|v| table.resolve_with_fallback(v.clone(), &fallback)),
131 #[derive(Copy, Clone, Debug)]
132 pub(crate) struct TypeVariableData {
136 type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
139 pub(crate) struct InferenceTable<'a> {
140 pub(crate) db: &'a dyn HirDatabase,
141 pub(crate) trait_env: Arc<TraitEnvironment>,
142 var_unification_table: ChalkInferenceTable,
143 type_variable_table: Vec<TypeVariableData>,
144 pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
147 pub(crate) struct InferenceTableSnapshot {
148 var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>,
149 pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
150 type_variable_table_snapshot: Vec<TypeVariableData>,
153 impl<'a> InferenceTable<'a> {
154 pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self {
158 var_unification_table: ChalkInferenceTable::new(),
159 type_variable_table: Vec::new(),
160 pending_obligations: Vec::new(),
164 /// Chalk doesn't know about the `diverging` flag, so when it unifies two
165 /// type variables of which one is diverging, the chosen root might not be
166 /// diverging and we have no way of marking it as such at that time. This
167 /// function goes through all type variables and make sure their root is
168 /// marked as diverging if necessary, so that resolving them gives the right
170 pub(super) fn propagate_diverging_flag(&mut self) {
171 for i in 0..self.type_variable_table.len() {
172 if !self.type_variable_table[i].diverging {
175 let v = InferenceVar::from(i as u32);
176 let root = self.var_unification_table.inference_var_root(v);
177 if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) {
178 data.diverging = true;
183 pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
184 self.type_variable_table[iv.index() as usize].diverging = diverging;
187 fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
191 .get(iv.index() as usize)
192 .map_or(false, |data| data.diverging) =>
196 TyVariableKind::General => TyKind::Error,
197 TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
198 TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
203 pub(crate) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
206 ) -> Canonicalized<T>
208 T: HasInterner<Interner = Interner>,
210 // try to resolve obligations before canonicalizing, since this might
211 // result in new knowledge about variables
212 self.resolve_obligations_as_possible();
213 let result = self.var_unification_table.canonicalize(Interner, t);
214 let free_vars = result
217 .map(|free_var| free_var.to_generic_arg(Interner))
219 Canonicalized { value: result.quantified, free_vars }
222 /// Recurses through the given type, normalizing associated types mentioned
223 /// in it by replacing them by type variables and registering obligations to
224 /// resolve later. This should be done once for every type we get from some
225 /// type annotation (e.g. from a let type annotation, field type or function
226 /// call). `make_ty` handles this already, but e.g. for field types we need
227 /// to do it as well.
228 pub(crate) fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
231 |ty, _| match ty.kind(Interner) {
232 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
233 self.normalize_projection_ty(proj_ty.clone())
237 DebruijnIndex::INNERMOST,
241 pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
242 let var = self.new_type_var();
243 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
244 let obligation = alias_eq.cast(Interner);
245 self.register_obligation(obligation);
249 fn extend_type_variable_table(&mut self, to_index: usize) {
250 self.type_variable_table.extend(
251 (0..1 + to_index - self.type_variable_table.len())
252 .map(|_| TypeVariableData { diverging: false }),
256 fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
257 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
258 // Chalk might have created some type variables for its own purposes that we don't know about...
259 self.extend_type_variable_table(var.index() as usize);
260 assert_eq!(var.index() as usize, self.type_variable_table.len() - 1);
261 self.type_variable_table[var.index() as usize].diverging = diverging;
262 var.to_ty_with_kind(Interner, kind)
265 pub(crate) fn new_type_var(&mut self) -> Ty {
266 self.new_var(TyVariableKind::General, false)
269 pub(crate) fn new_integer_var(&mut self) -> Ty {
270 self.new_var(TyVariableKind::Integer, false)
273 pub(crate) fn new_float_var(&mut self) -> Ty {
274 self.new_var(TyVariableKind::Float, false)
277 pub(crate) fn new_maybe_never_var(&mut self) -> Ty {
278 self.new_var(TyVariableKind::General, true)
281 pub(crate) fn new_const_var(&mut self, ty: Ty) -> Const {
282 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
283 var.to_const(Interner, ty)
286 pub(crate) fn new_lifetime_var(&mut self) -> Lifetime {
287 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
288 var.to_lifetime(Interner)
291 pub(crate) fn resolve_with_fallback<T>(
294 fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
297 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
299 self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
302 pub(crate) fn fresh_subst(&mut self, binders: &[CanonicalVarKind<Interner>]) -> Substitution {
303 Substitution::from_iter(
305 binders.iter().map(|kind| {
306 let param_infer_var =
307 kind.map_ref(|&ui| self.var_unification_table.new_variable(ui));
308 param_infer_var.to_generic_arg(Interner)
313 pub(crate) fn instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T
315 T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + std::fmt::Debug,
317 let subst = self.fresh_subst(canonical.binders.as_slice(Interner));
318 subst.apply(canonical.value, Interner)
321 fn resolve_with_fallback_inner<T>(
323 var_stack: &mut Vec<InferenceVar>,
325 fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
328 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
331 &mut resolve::Resolver { table: self, var_stack, fallback },
332 DebruijnIndex::INNERMOST,
334 .expect("fold failed unexpectedly")
337 pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
339 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
341 self.resolve_with_fallback(t, &|_, _, d, _| d)
344 /// Unify two types and register new trait goals that arise from that.
345 pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
346 let result = match self.try_unify(ty1, ty2) {
348 Err(_) => return false,
350 self.register_infer_ok(result);
354 /// Unify two types and return new trait goals arising from it, so the
355 /// caller needs to deal with them.
356 pub(crate) fn try_unify<T: Zip<Interner>>(&mut self, t1: &T, t2: &T) -> InferResult<()> {
357 match self.var_unification_table.relate(
361 chalk_ir::Variance::Invariant,
365 Ok(result) => Ok(InferOk { goals: result.goals, value: () }),
366 Err(chalk_ir::NoSolution) => Err(TypeError),
370 /// If `ty` is a type variable with known type, returns that type;
371 /// otherwise, return ty.
372 pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
373 self.resolve_obligations_as_possible();
374 self.var_unification_table.normalize_ty_shallow(Interner, ty).unwrap_or_else(|| ty.clone())
377 pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot {
378 let var_table_snapshot = self.var_unification_table.snapshot();
379 let type_variable_table_snapshot = self.type_variable_table.clone();
380 let pending_obligations = self.pending_obligations.clone();
381 InferenceTableSnapshot {
384 type_variable_table_snapshot,
388 pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) {
389 self.var_unification_table.rollback_to(snapshot.var_table_snapshot);
390 self.type_variable_table = snapshot.type_variable_table_snapshot;
391 self.pending_obligations = snapshot.pending_obligations;
394 pub(crate) fn run_in_snapshot<T>(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> T) -> T {
395 let snapshot = self.snapshot();
396 let result = f(self);
397 self.rollback_to(snapshot);
401 /// Checks an obligation without registering it. Useful mostly to check
402 /// whether a trait *might* be implemented before deciding to 'lock in' the
403 /// choice (during e.g. method resolution or deref).
404 pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option<Solution> {
405 let in_env = InEnvironment::new(&self.trait_env.env, goal);
406 let canonicalized = self.canonicalize(in_env);
407 let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value);
411 pub(crate) fn register_obligation(&mut self, goal: Goal) {
412 let in_env = InEnvironment::new(&self.trait_env.env, goal);
413 self.register_obligation_in_env(in_env)
416 fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) {
417 let canonicalized = self.canonicalize(goal);
418 if !self.try_resolve_obligation(&canonicalized) {
419 self.pending_obligations.push(canonicalized);
423 pub(crate) fn register_infer_ok<T>(&mut self, infer_ok: InferOk<T>) {
424 infer_ok.goals.into_iter().for_each(|goal| self.register_obligation_in_env(goal));
427 pub(crate) fn resolve_obligations_as_possible(&mut self) {
428 let _span = profile::span("resolve_obligations_as_possible");
429 let mut changed = true;
430 let mut obligations = Vec::new();
433 mem::swap(&mut self.pending_obligations, &mut obligations);
434 for canonicalized in obligations.drain(..) {
435 if !self.check_changed(&canonicalized) {
436 self.pending_obligations.push(canonicalized);
440 let uncanonical = chalk_ir::Substitute::apply(
441 &canonicalized.free_vars,
442 canonicalized.value.value,
445 self.register_obligation_in_env(uncanonical);
450 pub(crate) fn fudge_inference<T: TypeFoldable<Interner>>(
452 f: impl FnOnce(&mut Self) -> T,
454 use chalk_ir::fold::TypeFolder;
455 struct VarFudger<'a, 'b> {
456 table: &'a mut InferenceTable<'b>,
457 highest_known_var: InferenceVar,
459 impl<'a, 'b> TypeFolder<Interner> for VarFudger<'a, 'b> {
460 type Error = NoSolution;
462 fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
466 fn interner(&self) -> Interner {
470 fn fold_inference_ty(
472 var: chalk_ir::InferenceVar,
473 kind: TyVariableKind,
474 _outer_binder: chalk_ir::DebruijnIndex,
475 ) -> chalk_ir::Fallible<chalk_ir::Ty<Interner>> {
476 Ok(if var < self.highest_known_var {
477 var.to_ty(Interner, kind)
479 self.table.new_type_var()
483 fn fold_inference_lifetime(
485 var: chalk_ir::InferenceVar,
486 _outer_binder: chalk_ir::DebruijnIndex,
487 ) -> chalk_ir::Fallible<chalk_ir::Lifetime<Interner>> {
488 Ok(if var < self.highest_known_var {
489 var.to_lifetime(Interner)
491 self.table.new_lifetime_var()
495 fn fold_inference_const(
497 ty: chalk_ir::Ty<Interner>,
498 var: chalk_ir::InferenceVar,
499 _outer_binder: chalk_ir::DebruijnIndex,
500 ) -> chalk_ir::Fallible<chalk_ir::Const<Interner>> {
501 Ok(if var < self.highest_known_var {
502 var.to_const(Interner, ty)
504 self.table.new_const_var(ty)
509 let snapshot = self.snapshot();
510 let highest_known_var = self.new_type_var().inference_var(Interner).expect("inference_var");
511 let result = f(self);
512 self.rollback_to(snapshot);
514 .fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
515 .expect("fold_with with VarFudger")
518 /// This checks whether any of the free variables in the `canonicalized`
519 /// have changed (either been unified with another variable, or with a
520 /// value). If this is not the case, we don't need to try to solve the goal
521 /// again -- it'll give the same result as last time.
522 fn check_changed(&mut self, canonicalized: &Canonicalized<InEnvironment<Goal>>) -> bool {
523 canonicalized.free_vars.iter().any(|var| {
524 let iv = match var.data(Interner) {
525 chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
526 chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
527 chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
529 .expect("free var is not inference var");
530 if self.var_unification_table.probe_var(iv).is_some() {
533 let root = self.var_unification_table.inference_var_root(iv);
538 fn try_resolve_obligation(
540 canonicalized: &Canonicalized<InEnvironment<Goal>>,
542 let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value.clone());
545 Some(Solution::Unique(canonical_subst)) => {
546 canonicalized.apply_solution(
549 binders: canonical_subst.binders,
550 // FIXME: handle constraints
551 value: canonical_subst.value.subst,
556 Some(Solution::Ambig(Guidance::Definite(substs))) => {
557 canonicalized.apply_solution(self, substs);
561 // FIXME use this when trying to resolve everything at the end
565 // FIXME obligation cannot be fulfilled => diagnostic
571 pub(crate) fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
572 match ty.callable_sig(self.db) {
573 Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())),
574 None => self.callable_sig_from_fn_trait(ty, num_args),
578 fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
579 let krate = self.trait_env.krate;
580 let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?;
581 let output_assoc_type =
582 self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
584 let mut arg_tys = vec![];
585 let arg_ty = TyBuilder::tuple(num_args)
588 ParamKind::Type => self.new_type_var(),
589 ParamKind::Const(ty) => {
590 never!("Tuple with const parameter");
591 return GenericArgData::Const(self.new_const_var(ty.clone()))
595 arg_tys.push(arg.clone());
596 GenericArgData::Ty(arg).intern(Interner)
601 let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
602 if b.remaining() != 2 {
605 b.push(ty.clone()).push(arg_ty).build()
608 let trait_env = self.trait_env.env.clone();
609 let obligation = InEnvironment {
610 goal: projection.trait_ref(self.db).cast(Interner),
611 environment: trait_env,
613 let canonical = self.canonicalize(obligation.clone());
614 if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
615 self.register_obligation(obligation.goal);
616 let return_ty = self.normalize_projection_ty(projection);
617 Some((arg_tys, return_ty))
624 impl<'a> fmt::Debug for InferenceTable<'a> {
625 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
626 f.debug_struct("InferenceTable").field("num_vars", &self.type_variable_table.len()).finish()
631 use super::InferenceTable;
633 ConcreteConst, Const, ConstData, ConstValue, DebruijnIndex, GenericArg, InferenceVar,
634 Interner, Lifetime, Ty, TyVariableKind, VariableKind,
638 fold::{TypeFoldable, TypeFolder},
639 Fallible, NoSolution,
641 use hir_def::type_ref::ConstScalar;
643 pub(super) struct Resolver<'a, 'b, F> {
644 pub(super) table: &'a mut InferenceTable<'b>,
645 pub(super) var_stack: &'a mut Vec<InferenceVar>,
646 pub(super) fallback: F,
648 impl<'a, 'b, 'i, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
650 F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg + 'i,
652 type Error = NoSolution;
654 fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
658 fn interner(&self) -> Interner {
662 fn fold_inference_ty(
665 kind: TyVariableKind,
666 outer_binder: DebruijnIndex,
668 let var = self.table.var_unification_table.inference_var_root(var);
669 if self.var_stack.contains(&var) {
671 let default = self.table.fallback_value(var, kind).cast(Interner);
672 return Ok((self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
673 .assert_ty_ref(Interner)
676 let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
677 // known_ty may contain other variables that are known by now
678 self.var_stack.push(var);
680 known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
681 self.var_stack.pop();
682 result.assert_ty_ref(Interner).clone()
684 let default = self.table.fallback_value(var, kind).cast(Interner);
685 (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
686 .assert_ty_ref(Interner)
692 fn fold_inference_const(
696 outer_binder: DebruijnIndex,
697 ) -> Fallible<Const> {
698 let var = self.table.var_unification_table.inference_var_root(var);
699 let default = ConstData {
701 value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }),
705 if self.var_stack.contains(&var) {
707 return Ok((self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
708 .assert_const_ref(Interner)
711 let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
712 // known_ty may contain other variables that are known by now
713 self.var_stack.push(var);
715 known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
716 self.var_stack.pop();
717 result.assert_const_ref(Interner).clone()
719 (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
720 .assert_const_ref(Interner)
726 fn fold_inference_lifetime(
729 _outer_binder: DebruijnIndex,
730 ) -> Fallible<Lifetime> {
731 // fall back all lifetimes to 'static -- currently we don't deal
732 // with any lifetimes, but we can sometimes get some lifetime
733 // variables through Chalk's unification, and this at least makes
734 // sure we don't leak them outside of inference
735 Ok(crate::static_lifetime())