Skip to content

Commit 195241b

Browse files
committed
[bindings] Handle type X = Y aliasing in type resolution
For non-generic type aliases which are meant as convinient aliases for more complex types, we need to store the aliased type (with all paths made absolute) and use that in type resolution. The most code by far is just making all the paths in a type absolute but its not too bad either.
1 parent a1b5249 commit 195241b

File tree

2 files changed

+102
-6
lines changed

2 files changed

+102
-6
lines changed

c-bindings-gen/src/main.rs

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,8 +1057,6 @@ struct FullLibraryAST {
10571057
/// `out_path` and fills it with wrapper structs/functions to allow calling the things in the AST
10581058
/// at `module` from C.
10591059
fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &mut CrateTypes<'a>, in_dir: &str, out_dir: &str, path: &str, orig_crate: &str, module: &str, header_file: &mut File, cpp_header_file: &mut File) {
1060-
eprintln!("Converting {}...", path);
1061-
10621060
let syntax = if let Some(ast) = libast.files.get(module) { ast } else { return };
10631061

10641062
assert!(syntax.shebang.is_none()); // Not sure what this is, hope we dont have one
@@ -1096,6 +1094,8 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &mut CrateTypes
10961094
orig_crate, &new_mod, header_file, cpp_header_file);
10971095
}
10981096

1097+
eprintln!("Converting {} entries...", path);
1098+
10991099
let mut type_resolver = TypeResolver::new(orig_crate, module, crate_types);
11001100

11011101
for item in syntax.items.iter() {
@@ -1139,8 +1139,18 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &mut CrateTypes
11391139
ExportStatus::Export => {},
11401140
ExportStatus::NoExport|ExportStatus::TestOnly => continue,
11411141
}
1142-
if t.generics.lt_token.is_none() {
1143-
writeln_opaque(&mut out, &t.ident, &format!("{}", t.ident), &t.generics, &t.attrs, &type_resolver, header_file, cpp_header_file);
1142+
1143+
let mut process_alias = true;
1144+
for tok in t.generics.params.iter() {
1145+
if let syn::GenericParam::Lifetime(_) = tok {}
1146+
else { process_alias = false; }
1147+
}
1148+
if process_alias {
1149+
match &*t.ty {
1150+
syn::Type::Path(_) =>
1151+
writeln_opaque(&mut out, &t.ident, &format!("{}", t.ident), &t.generics, &t.attrs, &type_resolver, header_file, cpp_header_file),
1152+
_ => {}
1153+
}
11441154
}
11451155
}
11461156
},
@@ -1180,6 +1190,52 @@ fn load_ast(in_dir: &str, path: &str, module: String, ast_storage: &mut FullLibr
11801190
ast_storage.files.insert(module, syntax);
11811191
}
11821192

1193+
/// Insert ident -> absolute Path resolutions into imports from the given UseTree and path-prefix.
1194+
fn process_use_intern<'a>(u: &'a syn::UseTree, mut path: syn::punctuated::Punctuated<syn::PathSegment, syn::token::Colon2>, imports: &mut HashMap<&'a syn::Ident, syn::Path>) {
1195+
match u {
1196+
syn::UseTree::Path(p) => {
1197+
path.push(syn::PathSegment { ident: p.ident.clone(), arguments: syn::PathArguments::None });
1198+
process_use_intern(&p.tree, path, imports);
1199+
},
1200+
syn::UseTree::Name(n) => {
1201+
path.push(syn::PathSegment { ident: n.ident.clone(), arguments: syn::PathArguments::None });
1202+
imports.insert(&n.ident, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path });
1203+
},
1204+
syn::UseTree::Group(g) => {
1205+
for i in g.items.iter() {
1206+
process_use_intern(i, path.clone(), imports);
1207+
}
1208+
},
1209+
_ => {}
1210+
}
1211+
}
1212+
1213+
/// Map all the Paths in a Type into absolute paths given a set of imports (generated via process_use_intern)
1214+
fn resolve_imported_refs(imports: &HashMap<&syn::Ident, syn::Path>, mut ty: syn::Type) -> syn::Type {
1215+
match &mut ty {
1216+
syn::Type::Path(p) => {
1217+
if let Some(ident) = p.path.get_ident() {
1218+
if let Some(newpath) = imports.get(ident) {
1219+
p.path = newpath.clone();
1220+
}
1221+
} else { unimplemented!(); }
1222+
},
1223+
syn::Type::Reference(r) => {
1224+
r.elem = Box::new(resolve_imported_refs(imports, (*r.elem).clone()));
1225+
},
1226+
syn::Type::Slice(s) => {
1227+
s.elem = Box::new(resolve_imported_refs(imports, (*s.elem).clone()));
1228+
},
1229+
syn::Type::Tuple(t) => {
1230+
for e in t.elems.iter_mut() {
1231+
*e = resolve_imported_refs(imports, e.clone());
1232+
}
1233+
},
1234+
_ => unimplemented!(),
1235+
}
1236+
ty
1237+
}
1238+
11831239
/// Walk the FullLibraryAST, deciding how things will be mapped and adding tracking to CrateTypes.
11841240
fn walk_ast<'a>(in_dir: &str, path: &str, module: String, ast_storage: &'a FullLibraryAST, crate_types: &mut CrateTypes<'a>) {
11851241
let syntax = if let Some(ast) = ast_storage.files.get(&module) { ast } else { return };
@@ -1189,8 +1245,13 @@ fn walk_ast<'a>(in_dir: &str, path: &str, module: String, ast_storage: &'a FullL
11891245
walk_ast(in_dir, &path, new_mod, ast_storage, crate_types);
11901246
}
11911247

1248+
let mut import_maps = HashMap::new();
1249+
11921250
for item in syntax.items.iter() {
11931251
match item {
1252+
syn::Item::Use(u) => {
1253+
process_use_intern(&u.tree, syn::punctuated::Punctuated::new(), &mut import_maps);
1254+
},
11941255
syn::Item::Struct(s) => {
11951256
if let syn::Visibility::Public(_) = s.vis {
11961257
match export_status(&s.attrs) {
@@ -1211,6 +1272,31 @@ fn walk_ast<'a>(in_dir: &str, path: &str, module: String, ast_storage: &'a FullL
12111272
crate_types.traits.insert(trait_path, &t);
12121273
}
12131274
},
1275+
syn::Item::Type(t) => {
1276+
if let syn::Visibility::Public(_) = t.vis {
1277+
match export_status(&t.attrs) {
1278+
ExportStatus::Export => {},
1279+
ExportStatus::NoExport|ExportStatus::TestOnly => continue,
1280+
}
1281+
let type_path = format!("{}::{}", module, t.ident);
1282+
let mut process_alias = true;
1283+
for tok in t.generics.params.iter() {
1284+
if let syn::GenericParam::Lifetime(_) = tok {}
1285+
else { process_alias = false; }
1286+
}
1287+
if process_alias {
1288+
match &*t.ty {
1289+
syn::Type::Path(_) => {
1290+
// If its a path with no generics, assume we don't map the aliased type and map it opaque
1291+
crate_types.opaques.insert(type_path, &t.ident);
1292+
},
1293+
_ => {
1294+
crate_types.type_aliases.insert(type_path, resolve_imported_refs(&import_maps, (*t.ty).clone()));
1295+
}
1296+
}
1297+
}
1298+
}
1299+
},
12141300
syn::Item::Enum(e) if is_enum_opaque(e) => {
12151301
if let syn::Visibility::Public(_) = e.vis {
12161302
match export_status(&e.attrs) {
@@ -1264,7 +1350,7 @@ fn main() {
12641350
// ...then walk the ASTs tracking what types we will map, and how, so that we can resolve them
12651351
// when parsing other file ASTs...
12661352
let mut libtypes = CrateTypes { traits: HashMap::new(), opaques: HashMap::new(), mirrored_enums: HashMap::new(),
1267-
templates_defined: HashMap::new(), template_file: &mut derived_templates };
1353+
type_aliases: HashMap::new(), templates_defined: HashMap::new(), template_file: &mut derived_templates };
12681354
walk_ast(&args[1], "/lib.rs", "".to_string(), &libast, &mut libtypes);
12691355

12701356
// ... finally, do the actual file conversion/mapping, writing out types as we go.

c-bindings-gen/src/types.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ pub struct CrateTypes<'a> {
234234
pub mirrored_enums: HashMap<String, &'a syn::ItemEnum>,
235235
/// Traits which are mapped as a pointer + jump table
236236
pub traits: HashMap<String, &'a syn::ItemTrait>,
237+
/// Aliases from paths to some other Type
238+
pub type_aliases: HashMap<String, syn::Type>,
237239
/// Template continer types defined, map from mangled type name -> whether a destructor fn
238240
/// exists.
239241
///
@@ -1164,7 +1166,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
11641166
}
11651167

11661168
let resolved_path = self.resolve_path(&p.path, generics);
1167-
if let Some(c_type) = path_lookup(&resolved_path, is_ref, ptr_for_ref) {
1169+
if let Some(aliased_type) = self.crate_types.type_aliases.get(&resolved_path) {
1170+
return self.write_conversion_inline_intern(w, aliased_type, None, is_ref, is_mut, ptr_for_ref, tupleconv, prefix, sliceconv, path_lookup, decl_lookup);
1171+
} else if let Some(c_type) = path_lookup(&resolved_path, is_ref, ptr_for_ref) {
11681172
write!(w, "{}", c_type).unwrap();
11691173
} else if self.crate_types.opaques.get(&resolved_path).is_some() {
11701174
decl_lookup(w, &DeclType::StructImported, &resolved_path, is_ref, is_mut);
@@ -1476,6 +1480,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
14761480
unimplemented!();
14771481
}
14781482
let resolved_path = self.resolve_path(&p.path, generics);
1483+
if let Some(aliased_type) = self.crate_types.type_aliases.get(&resolved_path) {
1484+
return self.write_conversion_new_var_intern(w, ident, var, aliased_type, None, is_ref, ptr_for_ref, to_c, path_lookup, container_lookup, var_prefix, var_suffix);
1485+
}
14791486
if self.is_known_container(&resolved_path, is_ref) || self.is_transparent_container(&resolved_path, is_ref) {
14801487
if let syn::PathArguments::AngleBracketed(args) = &p.path.segments.iter().next().unwrap().arguments {
14811488
convert_container!(resolved_path, args.args.len(), || args.args.iter().map(|arg| {
@@ -1949,6 +1956,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
19491956
if self.is_known_container(&full_path, is_ref) || self.is_transparent_container(&full_path, is_ref) {
19501957
return self.write_c_mangled_container_path(w, Self::path_to_generic_args(&p.path), generics, &full_path, is_ref, is_mut, ptr_for_ref);
19511958
}
1959+
if let Some(aliased_type) = self.crate_types.type_aliases.get(&full_path).cloned() {
1960+
return self.write_c_type_intern(w, &aliased_type, None, is_ref, is_mut, ptr_for_ref);
1961+
}
19521962
}
19531963
self.write_c_path_intern(w, &p.path, generics, is_ref, is_mut, ptr_for_ref)
19541964
},

0 commit comments

Comments
 (0)