1use crate::syntax::improper::ImproperCtype;
2use crate::syntax::instantiate::ImplKey;
3use crate::syntax::map::{OrderedMap, UnorderedMap};
4use crate::syntax::report::Errors;
5use crate::syntax::resolve::Resolution;
6use crate::syntax::set::{OrderedSet, UnorderedSet};
7use crate::syntax::trivial::{self, TrivialReason};
8use crate::syntax::visit::{self, Visit};
9use crate::syntax::{
10 toposort, Api, Atom, Enum, EnumRepr, ExternType, Impl, Lifetimes, Pair, Struct, Type, TypeAlias,
11};
12use proc_macro2::Ident;
13use quote::ToTokens;
14
15pub(crate) struct Types<'a> {
16 pub all: OrderedSet<&'a Type>,
17 pub structs: UnorderedMap<&'a Ident, &'a Struct>,
18 pub enums: UnorderedMap<&'a Ident, &'a Enum>,
19 pub cxx: UnorderedSet<&'a Ident>,
20 pub rust: UnorderedSet<&'a Ident>,
21 pub aliases: UnorderedMap<&'a Ident, &'a TypeAlias>,
22 pub untrusted: UnorderedMap<&'a Ident, &'a ExternType>,
23 pub required_trivial: UnorderedMap<&'a Ident, Vec<TrivialReason<'a>>>,
24 pub impls: OrderedMap<ImplKey<'a>, Option<&'a Impl>>,
25 pub resolutions: UnorderedMap<&'a Ident, Resolution<'a>>,
26 pub struct_improper_ctypes: UnorderedSet<&'a Ident>,
27 pub toposorted_structs: Vec<&'a Struct>,
28}
29
30impl<'a> Types<'a> {
31 pub(crate) fn collect(cx: &mut Errors, apis: &'a [Api]) -> Self {
32 let mut all = OrderedSet::new();
33 let mut structs = UnorderedMap::new();
34 let mut enums = UnorderedMap::new();
35 let mut cxx = UnorderedSet::new();
36 let mut rust = UnorderedSet::new();
37 let mut aliases = UnorderedMap::new();
38 let mut untrusted = UnorderedMap::new();
39 let mut impls = OrderedMap::new();
40 let mut resolutions = UnorderedMap::new();
41 let struct_improper_ctypes = UnorderedSet::new();
42 let toposorted_structs = Vec::new();
43
44 fn visit<'a>(all: &mut OrderedSet<&'a Type>, ty: &'a Type) {
45 struct CollectTypes<'s, 'a>(&'s mut OrderedSet<&'a Type>);
46
47 impl<'s, 'a> Visit<'a> for CollectTypes<'s, 'a> {
48 fn visit_type(&mut self, ty: &'a Type) {
49 self.0.insert(ty);
50 visit::visit_type(self, ty);
51 }
52 }
53
54 CollectTypes(all).visit_type(ty);
55 }
56
57 let mut add_resolution = |name: &'a Pair, generics: &'a Lifetimes| {
58 resolutions.insert(&name.rust, Resolution { name, generics });
59 };
60
61 let mut type_names = UnorderedSet::new();
62 let mut function_names = UnorderedSet::new();
63 for api in apis {
64 match api {
71 Api::Include(_) => {}
72 Api::Struct(strct) => {
73 let ident = &strct.name.rust;
74 if !type_names.insert(ident)
75 && (!cxx.contains(ident)
76 || structs.contains_key(ident)
77 || enums.contains_key(ident))
78 {
79 duplicate_name(cx, strct, ident);
83 }
84 structs.insert(&strct.name.rust, strct);
85 for field in &strct.fields {
86 visit(&mut all, &field.ty);
87 }
88 add_resolution(&strct.name, &strct.generics);
89 }
90 Api::Enum(enm) => {
91 match &enm.repr {
92 EnumRepr::Native { atom: _, repr_type } => {
93 all.insert(repr_type);
94 }
95 #[cfg(feature = "experimental-enum-variants-from-header")]
96 EnumRepr::Foreign { rust_type: _ } => {}
97 }
98 let ident = &enm.name.rust;
99 if !type_names.insert(ident)
100 && (!cxx.contains(ident)
101 || structs.contains_key(ident)
102 || enums.contains_key(ident))
103 {
104 duplicate_name(cx, enm, ident);
108 }
109 enums.insert(ident, enm);
110 if enm.variants_from_header {
111 cxx.insert(&enm.name.rust);
114 }
115 add_resolution(&enm.name, &enm.generics);
116 }
117 Api::CxxType(ety) => {
118 let ident = &ety.name.rust;
119 if !type_names.insert(ident)
120 && (cxx.contains(ident)
121 || !structs.contains_key(ident) && !enums.contains_key(ident))
122 {
123 duplicate_name(cx, ety, ident);
127 }
128 cxx.insert(ident);
129 if !ety.trusted {
130 untrusted.insert(ident, ety);
131 }
132 add_resolution(&ety.name, &ety.generics);
133 }
134 Api::RustType(ety) => {
135 let ident = &ety.name.rust;
136 if !type_names.insert(ident) {
137 duplicate_name(cx, ety, ident);
138 }
139 rust.insert(ident);
140 add_resolution(&ety.name, &ety.generics);
141 }
142 Api::CxxFunction(efn) | Api::RustFunction(efn) => {
143 if !function_names.insert((&efn.receiver, &efn.name.rust)) {
146 duplicate_name(cx, efn, &efn.name.rust);
147 }
148 for arg in &efn.args {
149 visit(&mut all, &arg.ty);
150 }
151 if let Some(ret) = &efn.ret {
152 visit(&mut all, ret);
153 }
154 }
155 Api::TypeAlias(alias) => {
156 let ident = &alias.name.rust;
157 if !type_names.insert(ident) {
158 duplicate_name(cx, alias, ident);
159 }
160 cxx.insert(ident);
161 aliases.insert(ident, alias);
162 add_resolution(&alias.name, &alias.generics);
163 }
164 Api::Impl(imp) => {
165 visit(&mut all, &imp.ty);
166 if let Some(key) = imp.ty.impl_key() {
167 impls.insert(key, Some(imp));
168 }
169 }
170 }
171 }
172
173 for ty in &all {
174 let Some(impl_key) = ty.impl_key() else {
175 continue;
176 };
177 let implicit_impl = match impl_key {
178 ImplKey::RustBox(ident)
179 | ImplKey::RustVec(ident)
180 | ImplKey::UniquePtr(ident)
181 | ImplKey::SharedPtr(ident)
182 | ImplKey::WeakPtr(ident)
183 | ImplKey::CxxVector(ident) => {
184 Atom::from(ident.rust).is_none() && !aliases.contains_key(ident.rust)
185 }
186 };
187 if implicit_impl && !impls.contains_key(&impl_key) {
188 impls.insert(impl_key, None);
189 }
190 }
191
192 let required_trivial =
197 trivial::required_trivial_reasons(apis, &all, &structs, &enums, &cxx);
198
199 let mut types = Types {
200 all,
201 structs,
202 enums,
203 cxx,
204 rust,
205 aliases,
206 untrusted,
207 required_trivial,
208 impls,
209 resolutions,
210 struct_improper_ctypes,
211 toposorted_structs,
212 };
213
214 types.toposorted_structs = toposort::sort(cx, apis, &types);
215
216 let mut unresolved_structs = types.structs.keys();
217 let mut new_information = true;
218 while new_information {
219 new_information = false;
220 unresolved_structs.retain(|ident| {
221 let mut retain = false;
222 for var in &types.structs[ident].fields {
223 if match types.determine_improper_ctype(&var.ty) {
224 ImproperCtype::Depends(inner) => {
225 retain = true;
226 types.struct_improper_ctypes.contains(inner)
227 }
228 ImproperCtype::Definite(improper) => improper,
229 } {
230 types.struct_improper_ctypes.insert(ident);
231 new_information = true;
232 return false;
233 }
234 }
235 retain
237 });
238 }
239
240 types
241 }
242
243 pub(crate) fn needs_indirect_abi(&self, ty: &Type) -> bool {
244 match ty {
245 Type::RustBox(_) | Type::UniquePtr(_) => false,
246 Type::Array(_) => true,
247 _ => !self.is_guaranteed_pod(ty),
248 }
249 }
250
251 #[allow(dead_code)] pub(crate) fn is_considered_improper_ctype(&self, ty: &Type) -> bool {
259 match self.determine_improper_ctype(ty) {
260 ImproperCtype::Definite(improper) => improper,
261 ImproperCtype::Depends(ident) => self.struct_improper_ctypes.contains(ident),
262 }
263 }
264
265 pub(crate) fn is_maybe_trivial(&self, ty: &Ident) -> bool {
268 self.structs.contains_key(ty)
269 || self.enums.contains_key(ty)
270 || self.aliases.contains_key(ty)
271 }
272}
273
274impl<'t, 'a> IntoIterator for &'t Types<'a> {
275 type Item = &'a Type;
276 type IntoIter = crate::syntax::set::Iter<'t, 'a, Type>;
277 fn into_iter(self) -> Self::IntoIter {
278 self.all.into_iter()
279 }
280}
281
282fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
283 let msg = format!("the name `{}` is defined multiple times", ident);
284 cx.error(sp, msg);
285}