]> git.lizzy.rs Git - rust.git/blob - src/librustc_infer/infer/canonical/substitute.rs
Update const_forget.rs
[rust.git] / src / librustc_infer / infer / canonical / substitute.rs
1 //! This module contains code to substitute new values into a
2 //! `Canonical<'tcx, T>`.
3 //!
4 //! For an overview of what canonicalization is and how it fits into
5 //! rustc, check out the [chapter in the rustc guide][c].
6 //!
7 //! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
8
9 use crate::infer::canonical::{Canonical, CanonicalVarValues};
10 use rustc::ty::fold::TypeFoldable;
11 use rustc::ty::subst::GenericArgKind;
12 use rustc::ty::{self, TyCtxt};
13
14 pub(super) trait CanonicalExt<'tcx, V> {
15     /// Instantiate the wrapped value, replacing each canonical value
16     /// with the value given in `var_values`.
17     fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
18     where
19         V: TypeFoldable<'tcx>;
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.
27     fn substitute_projected<T>(
28         &self,
29         tcx: TyCtxt<'tcx>,
30         var_values: &CanonicalVarValues<'tcx>,
31         projection_fn: impl FnOnce(&V) -> &T,
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     {
42         self.substitute_projected(tcx, var_values, |value| value)
43     }
44
45     fn substitute_projected<T>(
46         &self,
47         tcx: TyCtxt<'tcx>,
48         var_values: &CanonicalVarValues<'tcx>,
49         projection_fn: impl FnOnce(&V) -> &T,
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`.
63 pub(super) fn substitute_value<'a, 'tcx, T>(
64     tcx: TyCtxt<'tcx>,
65     var_values: &CanonicalVarValues<'tcx>,
66     value: &'a T,
67 ) -> T
68 where
69     T: TypeFoldable<'tcx>,
70 {
71     if var_values.var_values.is_empty() {
72         value.clone()
73     } else {
74         let fld_r =
75             |br: ty::BoundRegion| match var_values.var_values[br.assert_bound_var()].unpack() {
76                 GenericArgKind::Lifetime(l) => l,
77                 r => bug!("{:?} is a region but value is {:?}", br, r),
78             };
79
80         let fld_t = |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() {
81             GenericArgKind::Type(ty) => ty,
82             r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
83         };
84
85         let fld_c = |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack() {
86             GenericArgKind::Const(ct) => ct,
87             c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
88         };
89
90         tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c).0
91     }
92 }