1use std::ops::ControlFlow;
2
3use flux_middle::rty::{
4 self,
5 fold::{
6 FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitor,
7 },
8};
9use itertools::Itertools;
10use rustc_data_structures::unord::{UnordMap, UnordSet};
11use rustc_type_ir::{DebruijnIndex, INNERMOST};
12
13pub struct WKVarInstantiator<'a> {
14 args_to_param: &'a UnordMap<rty::Expr, rty::Expr>,
19 self_args: &'a UnordSet<rty::Expr>,
21 any_self_args_used: bool,
23 memo: &'a mut UnordMap<rty::Expr, rty::Expr>,
26 current_index: DebruijnIndex,
27}
28
29impl FallibleTypeFolder for WKVarInstantiator<'_> {
30 type Error = rty::Var;
33
34 fn try_enter_binder(&mut self, _vars: &rty::BoundVariableKinds) {
35 self.current_index.shift_in(1);
36 }
37
38 fn try_exit_binder(&mut self) {
39 self.current_index.shift_out(1);
40 }
41
42 fn try_fold_expr(&mut self, e: &rty::Expr) -> Result<rty::Expr, rty::Var> {
43 if let Some(instantiated_e) = self.memo.get(e) {
44 return Ok(instantiated_e.clone());
45 }
46
47 if let Some(param) = self.args_to_param.get(e) {
53 self.any_self_args_used |= self.self_args.contains(e);
56 let param_expr = param.shift_in_escaping(self.current_index.as_u32());
57 self.memo.insert(e.clone(), param_expr.clone());
58 return Ok(param_expr);
59 }
60
61 if let rty::ExprKind::Var(var) = e.kind() {
62 Err(*var)
64 } else {
65 let instantiated_expr = e.try_super_fold_with(self)?;
66 self.memo.insert(e.clone(), instantiated_expr.clone());
67 Ok(instantiated_expr)
68 }
69 }
70}
71
72impl WKVarInstantiator<'_> {
73 pub fn try_instantiate_wkvar_args(
88 self_args: usize,
89 wkvar_args: &[rty::Expr],
90 expr: &rty::Expr,
91 ) -> Option<rty::Binder<rty::Expr>> {
92 let expr_without_metadata = expr.erase_metadata();
94 let expr_eta_expanded_rel = expr_without_metadata.expand_bin_rels();
95 let mut args_to_param = UnordMap::default();
96 std::iter::zip(
97 wkvar_args
99 .iter()
100 .map(|arg| arg.eta_reduce_projs().erase_metadata()),
101 (0..wkvar_args.len()).map(|var_num| {
104 rty::Expr::bvar(INNERMOST, var_num.into(), rty::BoundReftKind::Anon)
105 }),
106 )
107 .for_each(|(arg, param)| {
108 ProductEtaExpander::eta_expand_products(param, arg, &mut args_to_param);
109 });
110 let self_args = wkvar_args[..self_args].iter().cloned().collect();
111 let mut instantiator = WKVarInstantiator {
112 args_to_param: &args_to_param,
113 self_args: &self_args,
114 any_self_args_used: false,
115 memo: &mut UnordMap::default(),
116 current_index: INNERMOST,
119 };
120 instantiator
122 .try_fold_expr(&expr_eta_expanded_rel)
123 .ok()
125 .and_then(|instantiated_e| {
126 if !instantiator.any_self_args_used && !instantiator.self_args.is_empty() {
127 None
129 } else {
130 Some(rty::Binder::bind_with_sorts(
131 instantiated_e,
132 &std::iter::repeat_n(rty::Sort::Err, wkvar_args.len()).collect_vec(),
133 ))
134 }
135 })
136 }
137}
138
139pub struct WKVarSubst {
140 pub subst_instantiations: UnordMap<rty::WKVid, Vec<rty::Expr>>,
145 pub wkvar_instantiations: UnordMap<rty::WKVid, rty::Binder<rty::Expr>>,
146 pub keep_wkvars: bool,
148}
149
150impl WKVarSubst {
151 pub fn new(
152 wkvar_instantiations: UnordMap<rty::WKVid, rty::Binder<rty::Expr>>,
153 keep_wkvars: bool,
154 ) -> Self {
155 WKVarSubst { subst_instantiations: Default::default(), wkvar_instantiations, keep_wkvars }
156 }
157}
158
159impl TypeFolder for WKVarSubst {
160 fn fold_expr(&mut self, e: &rty::Expr) -> rty::Expr {
161 match e.kind() {
162 rty::ExprKind::WKVar(wkvar @ rty::WKVar { wkvid, .. })
163 if let Some(bound_e) = self.wkvar_instantiations.get(wkvid) =>
164 {
165 let instantiated_e = bound_e.replace_bound_refts(&wkvar.args);
168 self.subst_instantiations
169 .entry(wkvid.clone())
170 .and_modify(|insts| insts.push(instantiated_e.clone()))
171 .or_insert_with(|| vec![instantiated_e.clone()]);
172 if self.keep_wkvars {
173 rty::Expr::and(instantiated_e, e.clone())
174 } else {
175 instantiated_e
176 }
177 }
178 rty::ExprKind::WKVar(_) if !self.keep_wkvars => rty::Expr::tt(),
180 _ => e.super_fold_with(self),
181 }
182 }
183}
184
185struct ProductEtaExpander<'a> {
186 current_path: rty::Expr,
188 expr_to_eta_expansion: &'a mut UnordMap<rty::Expr, rty::Expr>,
190}
191
192impl TypeVisitor for ProductEtaExpander<'_> {
193 fn visit_expr(&mut self, expr: &rty::Expr) -> ControlFlow<Self::BreakTy> {
194 match expr.kind() {
195 rty::ExprKind::Tuple(subexprs) | rty::ExprKind::Ctor(_, subexprs) => {
196 let current_path = self.current_path.clone();
197 let mk_proj = |field| {
198 if let rty::ExprKind::Ctor(ctor, _) = expr.kind() {
199 let def_id = match ctor {
200 rty::Ctor::Struct(def_id) | rty::Ctor::Enum(def_id, _) => *def_id,
201 rty::Ctor::RawPtr => panic!("RawPtr ctor in wkvar path"),
202 };
203 rty::FieldProj::Adt { def_id, field }
204 } else {
205 rty::FieldProj::Tuple { arity: subexprs.len(), field }
206 }
207 };
208 for (i, subexpr) in subexprs.iter().enumerate() {
209 self.current_path = rty::Expr::field_proj(¤t_path, mk_proj(i as u32));
210 subexpr.visit_with(self)?;
211 }
212 ControlFlow::Continue(())
213 }
214 _ => {
215 self.expr_to_eta_expansion
220 .insert(expr.clone(), self.current_path.clone());
221 ControlFlow::Continue(())
222 }
223 }
224 }
225}
226
227impl<'a> ProductEtaExpander<'a> {
242 fn eta_expand_products(
243 current_path: rty::Expr,
244 expr: rty::Expr,
245 expr_to_eta_expansion: &'a mut UnordMap<rty::Expr, rty::Expr>,
246 ) {
247 let mut expander = ProductEtaExpander { current_path, expr_to_eta_expansion };
248 let _ = expr.visit_with(&mut expander);
249 }
250}