Skip to content

Commit 304471b

Browse files
committed
[bindings] Support traits with generic arguments (to support lightningdevkit#681)
Previously we'd ignored generic arguments in traits, leading to bogus code generation after the Persister trait was added in lightningdevkit#681. This adds minimal support for it, fixing code generation on latest upstream.
1 parent 8f10a1d commit 304471b

File tree

2 files changed

+60
-34
lines changed

2 files changed

+60
-34
lines changed

c-bindings-gen/src/main.rs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
148148
}
149149
writeln_docs(w, &t.attrs, "");
150150

151+
let mut gen_types = GenericTypes::new();
152+
assert!(gen_types.learn_generics(&t.generics, types));
153+
151154
writeln!(w, "#[repr(C)]\npub struct {} {{", trait_name).unwrap();
152155
writeln!(w, "\tpub this_arg: *mut c_void,").unwrap();
153156
let associated_types = learn_associated_types(t);
@@ -158,15 +161,17 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
158161
match export_status(&m.attrs) {
159162
ExportStatus::NoExport => {
160163
// NoExport in this context means we'll hit an unimplemented!() at runtime,
161-
// so add a comment noting that this needs to change in the output.
162-
writeln!(w, "\t//XXX: Need to export {}", m.sig.ident).unwrap();
163-
continue;
164+
// so bail out.
165+
unimplemented!();
164166
},
165167
ExportStatus::Export => {},
166168
ExportStatus::TestOnly => continue,
167169
}
168170
if m.default.is_some() { unimplemented!(); }
169171

172+
gen_types.push_ctx();
173+
assert!(gen_types.learn_generics(&m.sig.generics, types));
174+
170175
writeln_docs(w, &m.attrs, "\t");
171176

172177
if let syn::ReturnType::Type(_, rtype) = &m.sig.output {
@@ -183,7 +188,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
183188
// called when the trait method is called which allows updating on the fly.
184189
write!(w, "\tpub {}: ", m.sig.ident).unwrap();
185190
generated_fields.push(format!("{}", m.sig.ident));
186-
types.write_c_type(w, &*r.elem, None, false);
191+
types.write_c_type(w, &*r.elem, Some(&gen_types), false);
187192
writeln!(w, ",").unwrap();
188193
writeln!(w, "\t/// Fill in the {} field as a reference to it will be given to Rust after this returns", m.sig.ident).unwrap();
189194
writeln!(w, "\t/// Note that this takes a pointer to this object, not the this_ptr like other methods do").unwrap();
@@ -195,6 +200,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
195200
// which does not compile since Thing is not defined before it is used.
196201
writeln!(extra_headers, "struct LDK{};", trait_name).unwrap();
197202
writeln!(extra_headers, "typedef struct LDK{} LDK{};", trait_name, trait_name).unwrap();
203+
gen_types.pop_ctx();
198204
continue;
199205
}
200206
// Sadly, this currently doesn't do what we want, but it should be easy to get
@@ -204,8 +210,10 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
204210

205211
write!(w, "\tpub {}: extern \"C\" fn (", m.sig.ident).unwrap();
206212
generated_fields.push(format!("{}", m.sig.ident));
207-
write_method_params(w, &m.sig, &associated_types, "c_void", types, None, true, false);
213+
write_method_params(w, &m.sig, &associated_types, "c_void", types, Some(&gen_types), true, false);
208214
writeln!(w, ",").unwrap();
215+
216+
gen_types.pop_ctx();
209217
},
210218
&syn::TraitItem::Type(_) => {},
211219
_ => unimplemented!(),
@@ -284,8 +292,10 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
284292
m.sig.abi.is_some() || m.sig.variadic.is_some() {
285293
unimplemented!();
286294
}
295+
gen_types.push_ctx();
296+
assert!(gen_types.learn_generics(&m.sig.generics, types));
287297
write!(w, "\tfn {}", m.sig.ident).unwrap();
288-
types.write_rust_generic_param(w, m.sig.generics.params.iter());
298+
types.write_rust_generic_param(w, Some(&gen_types), m.sig.generics.params.iter());
289299
write!(w, "(").unwrap();
290300
for inp in m.sig.inputs.iter() {
291301
match inp {
@@ -309,27 +319,26 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
309319
ident.mutability.is_some() || ident.subpat.is_some() {
310320
unimplemented!();
311321
}
312-
write!(w, ", {}{}: ", if types.skip_arg(&*arg.ty, None) { "_" } else { "" }, ident.ident).unwrap();
322+
write!(w, ", {}{}: ", if types.skip_arg(&*arg.ty, Some(&gen_types)) { "_" } else { "" }, ident.ident).unwrap();
313323
}
314324
_ => unimplemented!(),
315325
}
316-
types.write_rust_type(w, &*arg.ty);
326+
types.write_rust_type(w, Some(&gen_types), &*arg.ty);
317327
}
318328
}
319329
}
320330
write!(w, ")").unwrap();
321331
match &m.sig.output {
322332
syn::ReturnType::Type(_, rtype) => {
323333
write!(w, " -> ").unwrap();
324-
types.write_rust_type(w, &*rtype)
334+
types.write_rust_type(w, Some(&gen_types), &*rtype)
325335
},
326336
_ => {},
327337
}
328338
write!(w, " {{\n\t\t").unwrap();
329339
match export_status(&m.attrs) {
330340
ExportStatus::NoExport => {
331-
writeln!(w, "unimplemented!();\n\t}}").unwrap();
332-
continue;
341+
unimplemented!();
333342
},
334343
_ => {},
335344
}
@@ -339,25 +348,27 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
339348
writeln!(w, "if let Some(f) = self.set_{} {{", m.sig.ident).unwrap();
340349
writeln!(w, "\t\t\t(f)(self);").unwrap();
341350
write!(w, "\t\t}}\n\t\t").unwrap();
342-
types.write_from_c_conversion_to_ref_prefix(w, &*r.elem, None);
351+
types.write_from_c_conversion_to_ref_prefix(w, &*r.elem, Some(&gen_types));
343352
write!(w, "self.{}", m.sig.ident).unwrap();
344-
types.write_from_c_conversion_to_ref_suffix(w, &*r.elem, None);
353+
types.write_from_c_conversion_to_ref_suffix(w, &*r.elem, Some(&gen_types));
345354
writeln!(w, "\n\t}}").unwrap();
355+
gen_types.pop_ctx();
346356
continue;
347357
}
348358
}
349-
write_method_var_decl_body(w, &m.sig, "\t", types, None, true);
359+
write_method_var_decl_body(w, &m.sig, "\t", types, Some(&gen_types), true);
350360
write!(w, "(self.{})(", m.sig.ident).unwrap();
351-
write_method_call_params(w, &m.sig, &associated_types, "\t", types, None, "", true);
361+
write_method_call_params(w, &m.sig, &associated_types, "\t", types, Some(&gen_types), "", true);
352362

353363
writeln!(w, "\n\t}}").unwrap();
364+
gen_types.pop_ctx();
354365
},
355366
&syn::TraitItem::Type(ref t) => {
356367
if t.default.is_some() || t.generics.lt_token.is_some() { unimplemented!(); }
357368
let mut bounds_iter = t.bounds.iter();
358369
match bounds_iter.next().unwrap() {
359370
syn::TypeParamBound::Trait(tr) => {
360-
writeln!(w, "\ttype {} = crate::{};", t.ident, types.resolve_path(&tr.path, None)).unwrap();
371+
writeln!(w, "\ttype {} = crate::{};", t.ident, types.resolve_path(&tr.path, Some(&gen_types))).unwrap();
361372
},
362373
_ => unimplemented!(),
363374
}

c-bindings-gen/src/types.rs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -932,19 +932,34 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
932932
// *** Original Rust Type Printing ***
933933
// ***********************************
934934

935-
fn write_rust_path<W: std::io::Write>(&self, w: &mut W, path: &syn::Path) {
936-
if let Some(resolved) = self.maybe_resolve_path(&path, None) {
935+
fn in_rust_prelude(resolved_path: &str) -> bool {
936+
match resolved_path {
937+
"Vec" => true,
938+
"Result" => true,
939+
"Option" => true,
940+
_ => false,
941+
}
942+
}
943+
944+
fn write_rust_path<W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, path: &syn::Path) {
945+
if let Some(resolved) = self.maybe_resolve_path(&path, generics_resolver) {
937946
if self.is_primitive(&resolved) {
938947
write!(w, "{}", path.get_ident().unwrap()).unwrap();
939948
} else {
940-
if resolved.starts_with("ln::") || resolved.starts_with("chain::") || resolved.starts_with("util::") {
941-
write!(w, "lightning::{}", resolved).unwrap();
949+
// TODO: We should have a generic "is from a dependency" check here instead of
950+
// checking for "bitcoin" explicitly.
951+
if resolved.starts_with("bitcoin::") || Self::in_rust_prelude(&resolved) {
952+
write!(w, "{}", resolved).unwrap();
953+
// If we're printing a generic argument, it needs to reference the crate, otherwise
954+
// the original crate:
955+
} else if self.maybe_resolve_path(&path, None).as_ref() == Some(&resolved) {
956+
write!(w, "{}::{}", self.orig_crate, resolved).unwrap();
942957
} else {
943-
write!(w, "{}", resolved).unwrap(); // XXX: Probably doens't work, get_ident().unwrap()
958+
write!(w, "crate::{}", resolved).unwrap();
944959
}
945960
}
946961
if let syn::PathArguments::AngleBracketed(args) = &path.segments.iter().last().unwrap().arguments {
947-
self.write_rust_generic_arg(w, args.args.iter());
962+
self.write_rust_generic_arg(w, generics_resolver, args.args.iter());
948963
}
949964
} else {
950965
if path.leading_colon.is_some() {
@@ -954,12 +969,12 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
954969
if idx != 0 { write!(w, "::").unwrap(); }
955970
write!(w, "{}", seg.ident).unwrap();
956971
if let syn::PathArguments::AngleBracketed(args) = &seg.arguments {
957-
self.write_rust_generic_arg(w, args.args.iter());
972+
self.write_rust_generic_arg(w, generics_resolver, args.args.iter());
958973
}
959974
}
960975
}
961976
}
962-
pub fn write_rust_generic_param<'b, W: std::io::Write>(&self, w: &mut W, generics: impl Iterator<Item=&'b syn::GenericParam>) {
977+
pub fn write_rust_generic_param<'b, W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, generics: impl Iterator<Item=&'b syn::GenericParam>) {
963978
let mut had_params = false;
964979
for (idx, arg) in generics.enumerate() {
965980
if idx != 0 { write!(w, ", ").unwrap(); } else { write!(w, "<").unwrap(); }
@@ -974,7 +989,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
974989
match bound {
975990
syn::TypeParamBound::Trait(tb) => {
976991
if tb.paren_token.is_some() || tb.lifetimes.is_some() { unimplemented!(); }
977-
self.write_rust_path(w, &tb.path);
992+
self.write_rust_path(w, generics_resolver, &tb.path);
978993
},
979994
_ => unimplemented!(),
980995
}
@@ -987,24 +1002,24 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
9871002
if had_params { write!(w, ">").unwrap(); }
9881003
}
9891004

990-
pub fn write_rust_generic_arg<'b, W: std::io::Write>(&self, w: &mut W, generics: impl Iterator<Item=&'b syn::GenericArgument>) {
1005+
pub fn write_rust_generic_arg<'b, W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, generics: impl Iterator<Item=&'b syn::GenericArgument>) {
9911006
write!(w, "<").unwrap();
9921007
for (idx, arg) in generics.enumerate() {
9931008
if idx != 0 { write!(w, ", ").unwrap(); }
9941009
match arg {
995-
syn::GenericArgument::Type(t) => self.write_rust_type(w, t),
1010+
syn::GenericArgument::Type(t) => self.write_rust_type(w, generics_resolver, t),
9961011
_ => unimplemented!(),
9971012
}
9981013
}
9991014
write!(w, ">").unwrap();
10001015
}
1001-
pub fn write_rust_type<W: std::io::Write>(&self, w: &mut W, t: &syn::Type) {
1016+
pub fn write_rust_type<W: std::io::Write>(&self, w: &mut W, generics: Option<&GenericTypes>, t: &syn::Type) {
10021017
match t {
10031018
syn::Type::Path(p) => {
10041019
if p.qself.is_some() || p.path.leading_colon.is_some() {
10051020
unimplemented!();
10061021
}
1007-
self.write_rust_path(w, &p.path);
1022+
self.write_rust_path(w, generics, &p.path);
10081023
},
10091024
syn::Type::Reference(r) => {
10101025
write!(w, "&").unwrap();
@@ -1014,11 +1029,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
10141029
if r.mutability.is_some() {
10151030
write!(w, "mut ").unwrap();
10161031
}
1017-
self.write_rust_type(w, &*r.elem);
1032+
self.write_rust_type(w, generics, &*r.elem);
10181033
},
10191034
syn::Type::Array(a) => {
10201035
write!(w, "[").unwrap();
1021-
self.write_rust_type(w, &a.elem);
1036+
self.write_rust_type(w, generics, &a.elem);
10221037
if let syn::Expr::Lit(l) = &a.len {
10231038
if let syn::Lit::Int(i) = &l.lit {
10241039
write!(w, "; {}]", i).unwrap();
@@ -1027,14 +1042,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
10271042
}
10281043
syn::Type::Slice(s) => {
10291044
write!(w, "[").unwrap();
1030-
self.write_rust_type(w, &s.elem);
1045+
self.write_rust_type(w, generics, &s.elem);
10311046
write!(w, "]").unwrap();
10321047
},
10331048
syn::Type::Tuple(s) => {
10341049
write!(w, "(").unwrap();
10351050
for (idx, t) in s.elems.iter().enumerate() {
10361051
if idx != 0 { write!(w, ", ").unwrap(); }
1037-
self.write_rust_type(w, &t);
1052+
self.write_rust_type(w, generics, &t);
10381053
}
10391054
write!(w, ")").unwrap();
10401055
},
@@ -1743,7 +1758,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
17431758
} else if in_crate {
17441759
write!(w, "{}", c_type).unwrap();
17451760
} else {
1746-
self.write_rust_type(w, &t);
1761+
self.write_rust_type(w, None, &t);
17471762
}
17481763
} else {
17491764
// If we just write out resolved_generic, it may mostly work, however for

0 commit comments

Comments
 (0)