]>
Commit | Line | Data |
---|---|---|
8faf50e0 XL |
1 | //! This module contains code to substitute new values into a |
2 | //! `Canonical<'tcx, T>`. | |
3 | //! | |
a1dfa0c6 | 4 | //! For an overview of what canonicalization is and how it fits into |
ba9703b0 | 5 | //! rustc, check out the [chapter in the rustc dev guide][c]. |
8faf50e0 | 6 | //! |
f9f354fc | 7 | //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html |
8faf50e0 | 8 | |
9fa01778 | 9 | use crate::infer::canonical::{Canonical, CanonicalVarValues}; |
064997fb | 10 | use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable}; |
ba9703b0 XL |
11 | use rustc_middle::ty::subst::GenericArgKind; |
12 | use rustc_middle::ty::{self, TyCtxt}; | |
8faf50e0 | 13 | |
74b04a01 | 14 | pub(super) trait CanonicalExt<'tcx, V> { |
8faf50e0 XL |
15 | /// Instantiate the wrapped value, replacing each canonical value |
16 | /// with the value given in `var_values`. | |
74b04a01 | 17 | fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V |
8faf50e0 | 18 | where |
74b04a01 | 19 | V: TypeFoldable<'tcx>; |
8faf50e0 XL |
20 | |
21 | /// Allows one to apply a substitute to some subset of | |
22 | /// `self.value`. Invoke `projection_fn` with `self.value` to get | |
23 | /// a value V that is expressed in terms of the same canonical | |
24 | /// variables bound in `self` (usually this extracts from subset | |
25 | /// of `self`). Apply the substitution `var_values` to this value | |
26 | /// V, replacing each of the canonical variables. | |
74b04a01 XL |
27 | fn substitute_projected<T>( |
28 | &self, | |
29 | tcx: TyCtxt<'tcx>, | |
30 | var_values: &CanonicalVarValues<'tcx>, | |
fc512014 | 31 | projection_fn: impl FnOnce(&V) -> T, |
74b04a01 XL |
32 | ) -> T |
33 | where | |
34 | T: TypeFoldable<'tcx>; | |
35 | } | |
36 | ||
37 | impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { | |
38 | fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V | |
39 | where | |
40 | V: TypeFoldable<'tcx>, | |
41 | { | |
fc512014 | 42 | self.substitute_projected(tcx, var_values, |value| value.clone()) |
74b04a01 XL |
43 | } |
44 | ||
45 | fn substitute_projected<T>( | |
8faf50e0 | 46 | &self, |
dc9dc135 | 47 | tcx: TyCtxt<'tcx>, |
8faf50e0 | 48 | var_values: &CanonicalVarValues<'tcx>, |
fc512014 | 49 | projection_fn: impl FnOnce(&V) -> T, |
8faf50e0 XL |
50 | ) -> T |
51 | where | |
52 | T: TypeFoldable<'tcx>, | |
53 | { | |
54 | assert_eq!(self.variables.len(), var_values.len()); | |
55 | let value = projection_fn(&self.value); | |
56 | substitute_value(tcx, var_values, value) | |
57 | } | |
58 | } | |
59 | ||
60 | /// Substitute the values from `var_values` into `value`. `var_values` | |
61 | /// must be values for the set of canonical variables that appear in | |
62 | /// `value`. | |
fc512014 | 63 | pub(super) fn substitute_value<'tcx, T>( |
dc9dc135 | 64 | tcx: TyCtxt<'tcx>, |
8faf50e0 | 65 | var_values: &CanonicalVarValues<'tcx>, |
fc512014 | 66 | value: T, |
8faf50e0 XL |
67 | ) -> T |
68 | where | |
69 | T: TypeFoldable<'tcx>, | |
70 | { | |
71 | if var_values.var_values.is_empty() { | |
fc512014 | 72 | value |
8faf50e0 | 73 | } else { |
064997fb FG |
74 | let delegate = FnMutDelegate { |
75 | regions: |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() { | |
76 | GenericArgKind::Lifetime(l) => l, | |
77 | r => bug!("{:?} is a region but value is {:?}", br, r), | |
78 | }, | |
79 | types: |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() { | |
80 | GenericArgKind::Type(ty) => ty, | |
81 | r => bug!("{:?} is a type but value is {:?}", bound_ty, r), | |
82 | }, | |
83 | consts: |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack() { | |
84 | GenericArgKind::Const(ct) => ct, | |
85 | c => bug!("{:?} is a const but value is {:?}", bound_ct, c), | |
86 | }, | |
cdc7bbd5 | 87 | }; |
a1dfa0c6 | 88 | |
064997fb | 89 | tcx.replace_escaping_bound_vars_uncached(value, delegate) |
8faf50e0 XL |
90 | } |
91 | } |