]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_infer/src/infer/canonical/substitute.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / compiler / rustc_infer / src / infer / canonical / substitute.rs
CommitLineData
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 9use crate::infer::canonical::{Canonical, CanonicalVarValues};
064997fb 10use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable};
ba9703b0
XL
11use rustc_middle::ty::subst::GenericArgKind;
12use rustc_middle::ty::{self, TyCtxt};
8faf50e0 13
74b04a01 14pub(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
37impl<'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 63pub(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
68where
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}