charon_lib/transform/add_missing_info/
add_implied_outlives.rs1use derive_generic_visitor::*;
3use itertools::Itertools;
4use std::mem;
5
6use crate::ast::*;
7use crate::transform::{TransformCtx, ctx::TransformPass};
8use crate::utils::CycleDetector;
9
10type BoundRegionOutlives = RegionBinder<RegionOutlives>;
11type BoundTypeOutlives = RegionBinder<TypeOutlives>;
12
13#[derive(Visitor)]
15struct OutlivesGatherer<'a> {
16 type_decls: &'a IndexMap<TypeDeclId, TypeDecl>,
17 params: &'a mut GenericParams,
18 regions_outlive: SeqHashSet<BoundRegionOutlives>,
19 types_outlive: SeqHashSet<BoundTypeOutlives>,
20 shorter_regions: Vec<Region>,
22 binder_depth: DeBruijnId,
24}
25
26impl<'a> OutlivesGatherer<'a> {
27 fn new(params: &'a mut GenericParams, type_decls: &'a IndexMap<TypeDeclId, TypeDecl>) -> Self {
28 Self {
29 type_decls,
30 regions_outlive: mem::take(&mut params.regions_outlive).into_iter().collect(),
31 types_outlive: mem::take(&mut params.types_outlive).into_iter().collect(),
32 params,
33 shorter_regions: Vec::new(),
34 binder_depth: DeBruijnId::ZERO,
35 }
36 }
37
38 fn finish(self) {
39 self.params
40 .regions_outlive
41 .extend(self.regions_outlive.into_iter().filter(|pred| {
42 let OutlivesPred(longer, shorter) = pred.skip_binder;
43 longer != shorter && longer != Region::Erased && shorter != Region::Erased
44 }));
45 self.params
46 .types_outlive
47 .extend(self.types_outlive.into_iter().filter(|pred| {
48 let OutlivesPred(_, shorter) = pred.skip_binder;
49 shorter != Region::Erased
50 }));
51 }
52
53 fn with_shorter_region(
54 &mut self,
55 region: Region,
56 f: impl FnOnce(&mut Self) -> ControlFlow<Infallible>,
57 ) -> ControlFlow<Infallible> {
58 if let Some(&shorter) = self.shorter_regions.last() {
59 self.regions_outlive
60 .insert(RegionBinder::empty(OutlivesPred(region, shorter)));
61 }
62 self.shorter_regions.push(region);
63 f(self)?;
64 self.shorter_regions.pop().unwrap();
65 Continue(())
66 }
67}
68
69impl VisitorWithBinderDepth for OutlivesGatherer<'_> {
70 fn binder_depth_mut(&mut self) -> &mut DeBruijnId {
71 &mut self.binder_depth
72 }
73}
74
75impl VisitAst for OutlivesGatherer<'_> {
76 fn visit<T: AstVisitable>(&mut self, value: &T) -> ControlFlow<Self::Break> {
77 VisitWithBinderDepth::new(self).visit(value)
78 }
79
80 fn visit_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break> {
81 match ty.kind() {
82 TyKind::TypeVar(_) | TyKind::TraitType(..)
83 if let Some(ty) = ty.clone().move_from_under_binders(self.binder_depth) =>
84 {
85 if let Some(&shorter) = self.shorter_regions.last() {
86 self.types_outlive
87 .insert(RegionBinder::empty(OutlivesPred(ty.clone(), shorter)));
88 }
89 }
90 TyKind::Adt(type_ref)
91 if let Some(decl) = self.type_decls.get(type_ref.id)
92 && let Some(generics) = type_ref
93 .generics
94 .clone()
95 .move_from_under_binders(self.binder_depth) =>
96 {
97 self.regions_outlive.extend(
98 decl.generics
99 .regions_outlive
100 .iter()
101 .cloned()
102 .map(|pred| pred.substitute(&generics)),
103 );
104 self.types_outlive.extend(
105 decl.generics
106 .types_outlive
107 .iter()
108 .cloned()
109 .map(|pred| pred.substitute(&generics)),
110 );
111 }
112 _ => {}
113 }
114 match ty.kind() {
115 TyKind::Ref(region @ (Region::Static | Region::Var(_)), _, _)
116 if let Some(region) = (*region).move_from_under_binders(self.binder_depth) =>
117 {
118 self.with_shorter_region(region, |this| this.visit_inner(ty))
119 }
120 _ => self.visit_inner(ty),
121 }
122 }
123
124 fn enter_region(&mut self, region: &Region) {
125 if let Some(longer @ Region::Var(_)) = (*region).move_from_under_binders(self.binder_depth)
126 && let Some(&shorter) = self.shorter_regions.last()
127 {
128 self.regions_outlive
129 .insert(RegionBinder::empty(OutlivesPred(longer, shorter)));
130 }
131 }
132}
133
134struct ClosureOutlivesComputer<'a> {
135 type_decls: &'a mut IndexMap<TypeDeclId, TypeDecl>,
136 closure_tys: SeqHashMap<TypeDeclId, CycleDetector<()>>,
138}
139
140impl<'a> ClosureOutlivesComputer<'a> {
141 fn new(type_decls: &'a mut IndexMap<TypeDeclId, TypeDecl>) -> Self {
142 let closure_tys = type_decls
143 .iter()
144 .filter(|decl| matches!(decl.src, TypeSource::Closure { .. }))
145 .map(|decl| (decl.def_id, CycleDetector::Unprocessed))
146 .collect();
147 Self {
148 type_decls,
149 closure_tys,
150 }
151 }
152
153 fn compute_all(mut self) {
154 for type_id in self.closure_tys.keys().cloned().collect_vec() {
155 self.compute(type_id);
156 }
157 }
158
159 fn compute(&mut self, type_id: TypeDeclId) {
160 if self.closure_tys[&type_id].start_processing() {
161 let mut dependencies = Vec::new();
162 self.type_decls[type_id]
163 .kind
164 .dyn_visit(|type_ref: &TypeDeclRef| {
165 if self.closure_tys.get(&type_ref.id).is_some() {
166 dependencies.push(type_ref.id);
167 }
168 });
169 for dependency in dependencies {
170 self.compute(dependency);
171 }
172
173 let mut params = mem::take(&mut self.type_decls[type_id].generics);
174 let mut visitor = OutlivesGatherer::new(&mut params, self.type_decls);
175 visitor.visit(&self.type_decls[type_id].kind);
176 visitor.finish();
177 self.type_decls[type_id].generics = params;
178 self.closure_tys[&type_id].done_processing(());
179 }
180 assert!(
181 matches!(self.closure_tys[&type_id], CycleDetector::Processed(_)),
182 "closure type declarations unexpectedly form a cycle"
183 );
184 }
185}
186
187pub struct Transform;
188
189impl TransformPass for Transform {
190 fn transform_ctx(&self, ctx: &mut TransformCtx) {
191 let type_decls = &mut ctx.translated.type_decls;
192
193 ClosureOutlivesComputer::new(type_decls).compute_all();
197
198 for fun_decl in &mut ctx.translated.fun_decls {
199 let mut visitor = OutlivesGatherer::new(&mut fun_decl.generics, type_decls);
200 visitor.visit(&fun_decl.signature);
201 visitor.finish();
202 }
203
204 for timpl in &mut ctx.translated.trait_impls {
205 let mut visitor = OutlivesGatherer::new(&mut timpl.generics, type_decls);
206 visitor.visit(&timpl.impl_trait);
207 visitor.finish();
208 }
209 }
210}