rustc_infer/infer/canonical/
instantiate.rs1use rustc_macros::extension;
10use rustc_middle::ty::{
11 self, DelayedMap, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
12 TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
13};
14
15use crate::infer::canonical::{Canonical, CanonicalVarValues};
16
17impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
#[doc = " Instantiate the wrapped value, replacing each canonical value"]
#[doc = " with the value given in `var_values`."]
fn instantiate(&self, tcx: TyCtxt<'tcx>,
var_values: &CanonicalVarValues<'tcx>) -> V where
V: TypeFoldable<TyCtxt<'tcx>> {
self.instantiate_projected(tcx, var_values, |value| value.clone())
}
#[doc = " Allows one to apply a instantiation to some subset of"]
#[doc = " `self.value`. Invoke `projection_fn` with `self.value` to get"]
#[doc = " a value V that is expressed in terms of the same canonical"]
#[doc = " variables bound in `self` (usually this extracts from subset"]
#[doc = " of `self`). Apply the instantiation `var_values` to this value"]
#[doc = " V, replacing each of the canonical variables."]
fn instantiate_projected<T>(&self, tcx: TyCtxt<'tcx>,
var_values: &CanonicalVarValues<'tcx>,
projection_fn: impl FnOnce(&V) -> T) -> T where
T: TypeFoldable<TyCtxt<'tcx>> {
match (&self.var_kinds.len(), &var_values.len()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
let value = projection_fn(&self.value);
instantiate_value(tcx, var_values, value)
}
}#[extension(pub trait CanonicalExt<'tcx, V>)]
20impl<'tcx, V> Canonical<'tcx, V> {
21 fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
24 where
25 V: TypeFoldable<TyCtxt<'tcx>>,
26 {
27 self.instantiate_projected(tcx, var_values, |value| value.clone())
28 }
29
30 fn instantiate_projected<T>(
37 &self,
38 tcx: TyCtxt<'tcx>,
39 var_values: &CanonicalVarValues<'tcx>,
40 projection_fn: impl FnOnce(&V) -> T,
41 ) -> T
42 where
43 T: TypeFoldable<TyCtxt<'tcx>>,
44 {
45 assert_eq!(self.var_kinds.len(), var_values.len());
46 let value = projection_fn(&self.value);
47 instantiate_value(tcx, var_values, value)
48 }
49}
50
51pub(super) fn instantiate_value<'tcx, T>(
55 tcx: TyCtxt<'tcx>,
56 var_values: &CanonicalVarValues<'tcx>,
57 value: T,
58) -> T
59where
60 T: TypeFoldable<TyCtxt<'tcx>>,
61{
62 if var_values.var_values.is_empty() {
63 return value;
64 }
65
66 value.fold_with(&mut CanonicalInstantiator {
67 tcx,
68 var_values: var_values.var_values,
69 cache: Default::default(),
70 })
71}
72
73struct CanonicalInstantiator<'tcx> {
75 tcx: TyCtxt<'tcx>,
76
77 var_values: ty::GenericArgsRef<'tcx>,
79
80 cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
83}
84
85impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
86 fn cx(&self) -> TyCtxt<'tcx> {
87 self.tcx
88 }
89
90 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
91 match *t.kind() {
92 ty::Bound(ty::BoundVarIndexKind::Canonical, bound_ty) => {
93 self.var_values[bound_ty.var.as_usize()].expect_ty()
94 }
95 _ => {
96 if !t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
97 t
98 } else if let Some(&t) = self.cache.get(&t) {
99 t
100 } else {
101 let res = t.super_fold_with(self);
102 if !self.cache.insert(t, res) {
::core::panicking::panic("assertion failed: self.cache.insert(t, res)")
};assert!(self.cache.insert(t, res));
103 res
104 }
105 }
106 }
107 }
108
109 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
110 match r.kind() {
111 ty::ReBound(ty::BoundVarIndexKind::Canonical, br) => {
112 self.var_values[br.var.as_usize()].expect_region()
113 }
114 _ => r,
115 }
116 }
117
118 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
119 match ct.kind() {
120 ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound_const) => {
121 self.var_values[bound_const.var.as_usize()].expect_const()
122 }
123 _ => ct.super_fold_with(self),
124 }
125 }
126
127 fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
128 if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p }
129 }
130
131 fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
132 if !c.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
133 return c;
134 }
135
136 let index = *self
145 .tcx
146 .highest_var_in_clauses_cache
147 .lock()
148 .entry(c)
149 .or_insert_with(|| highest_var_in_clauses(c));
150 let c_args = &self.var_values[..=index];
151
152 if let Some(c) = self.tcx.clauses_cache.lock().get(&(c, c_args)) {
153 c
154 } else {
155 let folded = c.super_fold_with(self);
156 self.tcx.clauses_cache.lock().insert((c, c_args), folded);
157 folded
158 }
159 }
160}
161
162fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize {
163 struct HighestVarInClauses {
164 max_var: usize,
165 }
166 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HighestVarInClauses {
167 fn visit_ty(&mut self, t: Ty<'tcx>) {
168 if let ty::Bound(ty::BoundVarIndexKind::Canonical, bound_ty) = *t.kind() {
169 self.max_var = self.max_var.max(bound_ty.var.as_usize());
170 } else if t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
171 t.super_visit_with(self);
172 }
173 }
174 fn visit_region(&mut self, r: ty::Region<'tcx>) {
175 if let ty::ReBound(ty::BoundVarIndexKind::Canonical, bound_region) = r.kind() {
176 self.max_var = self.max_var.max(bound_region.var.as_usize());
177 }
178 }
179 fn visit_const(&mut self, ct: ty::Const<'tcx>) {
180 if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound_const) = ct.kind() {
181 self.max_var = self.max_var.max(bound_const.var.as_usize());
182 } else if ct.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
183 ct.super_visit_with(self);
184 }
185 }
186 }
187 let mut visitor = HighestVarInClauses { max_var: 0 };
188 c.visit_with(&mut visitor);
189 visitor.max_var
190}