1use crate::ast::*;
2use derive_generic_visitor::{Drive, DriveMut, DriveTwo};
3use macros::EnumIsA;
4use macros::VariantName;
5use serde_state::DeserializeState;
6use serde_state::SerializeState;
7
8#[derive(Debug, Clone)]
10#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
11pub struct FunDecl {
12 pub def_id: FunDeclId,
13 pub item_meta: ItemMeta,
15 pub generics: GenericParams,
16 pub signature: Box<FunSig>,
18 pub src: FunSource,
20 pub body: Body,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
26#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
27pub struct FunSig {
28 pub is_unsafe: bool,
30 pub abi: Abi,
32 pub is_variadic: bool,
34 pub inputs: Vec<Ty>,
35 pub output: Ty,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
39#[derive(VariantName, EnumIsA)]
40#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
41#[serde_state(stateless)]
42#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("Abi"))]
43pub enum Abi {
44 Rust,
45 C,
46 Other(ustr::Ustr),
48}
49
50#[derive(Debug, Clone)]
52#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
53#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Fun"))]
54pub enum FunSource {
55 Normal,
57 AdtConstructor,
59 TraitDefault {
61 trait_ref: TraitDeclRef,
63 item_id: TraitMethodId,
66 },
67 TraitImpl {
69 impl_ref: TraitImplRef,
71 trait_ref: TraitDeclRef,
73 item_id: TraitMethodId,
76 reuses_default: bool,
79 },
80 VTableShim,
84 GlobalInitializer(GlobalDeclRef),
86 TargetDependent { dispatcher: FunDeclRef },
89}
90
91impl FunDecl {
92 pub fn substitute_params(self, subst: Binder<GenericArgs>) -> Self {
94 let FunDecl {
95 def_id,
96 item_meta,
97 generics: _,
98 signature,
99 src,
100 body,
101 } = self;
102 let signature = signature.substitute(&subst.skip_binder);
103 let src = src.substitute(&subst.skip_binder);
104 let body = body.substitute(&subst.skip_binder);
105 FunDecl {
106 def_id,
107 item_meta,
108 generics: subst.params,
109 signature,
110 src,
111 body,
112 }
113 }
114
115 pub fn is_unsafe_to_call(&self, _krate: &TranslatedCrate) -> bool {
119 self.signature.is_unsafe
120 }
121
122 pub fn is_unsafe_to_declare(&self, _krate: &TranslatedCrate) -> bool {
124 !matches!(self.src, FunSource::GlobalInitializer(_))
126 && self.item_meta.is_unsafe_to_declare()
127 }
128
129 pub fn as_fn_ptr(&self) -> RegionBinder<FunSig> {
131 struct RebindLateRegions<'a> {
132 late_regions: &'a IndexVec<RegionId, Option<RegionId>>,
133 }
134
135 impl VarsVisitor for RebindLateRegions<'_> {
136 fn visit_region_var(&mut self, var: RegionDbVar) -> Option<Region> {
137 let DeBruijnVar::Bound(depth, id) = var else {
138 return None;
139 };
140 if depth == DeBruijnId::one() {
141 self.late_regions[id].map(|id| Region::Var(DeBruijnVar::new_at_zero(id)))
142 } else {
143 None
144 }
145 }
146 }
147
148 let mut regions = IndexVec::new();
149 let late_regions = self.generics.regions.map_ref(|param| {
150 if param.late_bound {
151 Some(regions.push_with(|index| RegionParam {
152 index,
153 ..param.clone()
154 }))
155 } else {
156 None
157 }
158 });
159 let mut signature = self.signature.as_ref().clone().move_under_binder();
160 signature.visit_vars(&mut RebindLateRegions {
161 late_regions: &late_regions,
162 });
163 RegionBinder {
164 regions,
165 regions_outlive: Vec::new(),
168 types_outlive: Vec::new(),
169 skip_binder: signature,
170 }
171 }
172}
173
174impl RegionBinder<FunSig> {
175 pub fn infer_region_mapping(&self, target: &Self) -> Option<RegionBinder<RegionArgs>> {
178 struct RegionMapping {
179 regions: IndexVec<RegionId, Option<Region>>,
180 depth: DeBruijnId,
181 }
182
183 impl Visitor for RegionMapping {
184 type Break = ();
185 }
186
187 impl ZipAst for RegionMapping {
188 fn visit_region_param(
189 &mut self,
190 _source: &RegionParam,
191 _target: &RegionParam,
192 ) -> ControlFlow<()> {
193 ControlFlow::Continue(())
195 }
196
197 fn visit_region(&mut self, source: &Region, target: &Region) -> ControlFlow<()> {
198 if let Region::Var(var @ DeBruijnVar::Bound(depth, _)) = source
200 && *depth <= self.depth
201 {
202 if let Some(id) = var.bound_at_depth(self.depth) {
203 let Some(target) = (*target).move_from_under_binders(self.depth) else {
204 return ControlFlow::Break(());
205 };
206 let mapped = &mut self.regions[id];
207 if let Some(previous) = mapped
208 && *previous != target
209 {
210 return ControlFlow::Break(());
211 }
212 *mapped = Some(target);
213 ControlFlow::Continue(())
214 } else if source != target {
215 ControlFlow::Break(())
216 } else {
217 ControlFlow::Continue(())
218 }
219 } else {
220 ControlFlow::Continue(())
221 }
222 }
223
224 fn visit_region_binder<T: AstVisitable>(
225 &mut self,
226 source: &RegionBinder<T>,
227 target: &RegionBinder<T>,
228 ) -> ControlFlow<()> {
229 self.depth = self.depth.incr();
230 let result = self.visit_inner(source, target);
231 self.depth = self.depth.decr();
232 result
233 }
234 }
235
236 let mut mapping = RegionMapping {
237 regions: self.regions.map_ref_indexed(|_, _| None),
238 depth: DeBruijnId::zero(),
239 };
240 if ZipAst::visit(&mut mapping, &self.skip_binder, &target.skip_binder).is_break() {
241 return None;
242 }
243 let regions = RegionArgs::new(mapping.regions.into_iter().collect::<Option<_>>()?);
244 Some(RegionBinder {
245 regions: target.regions.clone(),
246 regions_outlive: target.regions_outlive.clone(),
247 types_outlive: target.types_outlive.clone(),
248 skip_binder: regions,
249 })
250 }
251}
252
253impl Abi {
254 pub fn rust() -> Self {
255 Self::Rust
256 }
257
258 pub fn rust_name(&self) -> &str {
259 match self {
260 Self::Rust => "Rust",
261 Self::C => "C",
262 Self::Other(name) => name.as_str(),
263 }
264 }
265}