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::common::CycleDetector;
8use crate::transform::{TransformCtx, ctx::TransformPass};
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 TypeId::Adt(type_id) = type_ref.id
92 && let Some(decl) = self.type_decls.get(type_id)
93 && let Some(generics) = type_ref
94 .generics
95 .clone()
96 .move_from_under_binders(self.binder_depth) =>
97 {
98 self.regions_outlive.extend(
99 decl.generics
100 .regions_outlive
101 .iter()
102 .cloned()
103 .map(|pred| pred.substitute(&generics)),
104 );
105 self.types_outlive.extend(
106 decl.generics
107 .types_outlive
108 .iter()
109 .cloned()
110 .map(|pred| pred.substitute(&generics)),
111 );
112 }
113 _ => {}
114 }
115 match ty.kind() {
116 TyKind::Ref(region @ (Region::Static | Region::Var(_)), _, _)
117 if let Some(region) = (*region).move_from_under_binders(self.binder_depth) =>
118 {
119 self.with_shorter_region(region, |this| this.visit_inner(ty))
120 }
121 _ => self.visit_inner(ty),
122 }
123 }
124
125 fn enter_region(&mut self, region: &Region) {
126 if let Some(longer @ Region::Var(_)) = (*region).move_from_under_binders(self.binder_depth)
127 && let Some(&shorter) = self.shorter_regions.last()
128 {
129 self.regions_outlive
130 .insert(RegionBinder::empty(OutlivesPred(longer, shorter)));
131 }
132 }
133}
134
135struct ClosureOutlivesComputer<'a> {
136 type_decls: &'a mut IndexMap<TypeDeclId, TypeDecl>,
137 closure_tys: SeqHashMap<TypeDeclId, CycleDetector<()>>,
139}
140
141impl<'a> ClosureOutlivesComputer<'a> {
142 fn new(type_decls: &'a mut IndexMap<TypeDeclId, TypeDecl>) -> Self {
143 let closure_tys = type_decls
144 .iter()
145 .filter(|decl| matches!(decl.src, ItemSource::Closure { .. }))
146 .map(|decl| (decl.def_id, CycleDetector::Unprocessed))
147 .collect();
148 Self {
149 type_decls,
150 closure_tys,
151 }
152 }
153
154 fn compute_all(mut self) {
155 for type_id in self.closure_tys.keys().cloned().collect_vec() {
156 self.compute(type_id);
157 }
158 }
159
160 fn compute(&mut self, type_id: TypeDeclId) {
161 if self.closure_tys[&type_id].start_processing() {
162 let mut dependencies = Vec::new();
163 self.type_decls[type_id]
164 .kind
165 .dyn_visit(|type_ref: &TypeDeclRef| {
166 if let TypeId::Adt(type_id) = type_ref.id
167 && self.closure_tys.get(&type_id).is_some()
168 {
169 dependencies.push(type_id);
170 }
171 });
172 for dependency in dependencies {
173 self.compute(dependency);
174 }
175
176 let mut params = mem::take(&mut self.type_decls[type_id].generics);
177 let mut visitor = OutlivesGatherer::new(&mut params, self.type_decls);
178 visitor.visit(&self.type_decls[type_id].kind);
179 visitor.finish();
180 self.type_decls[type_id].generics = params;
181 self.closure_tys[&type_id].done_processing(());
182 }
183 assert!(
184 matches!(self.closure_tys[&type_id], CycleDetector::Processed(_)),
185 "closure type declarations unexpectedly form a cycle"
186 );
187 }
188}
189
190pub struct Transform;
191
192impl TransformPass for Transform {
193 fn transform_ctx(&self, ctx: &mut TransformCtx) {
194 let type_decls = &mut ctx.translated.type_decls;
195
196 ClosureOutlivesComputer::new(type_decls).compute_all();
200
201 for fun_decl in &mut ctx.translated.fun_decls {
202 let mut visitor = OutlivesGatherer::new(&mut fun_decl.generics, type_decls);
203 visitor.visit(&fun_decl.signature);
204 visitor.finish();
205 }
206
207 for timpl in &mut ctx.translated.trait_impls {
208 let mut visitor = OutlivesGatherer::new(&mut timpl.generics, type_decls);
209 visitor.visit(&timpl.impl_trait);
210 visitor.finish();
211 }
212 }
213}