Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support dependent qualified types #1975

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1303,23 +1303,30 @@ impl Type {
/// typename T::Associated member;
/// };
/// ```
pub fn is_associated_type(&self) -> bool {
///
/// If so, returns the type name, e.g. 'member'
pub fn get_associated_type_name(&self) -> Option<String> {
// This is terrible :(
fn hacky_parse_associated_type<S: AsRef<str>>(spelling: S) -> bool {
fn hacky_parse_associated_type<S: AsRef<str>>(
spelling: S,
) -> Option<String> {
lazy_static! {
static ref ASSOC_TYPE_RE: regex::Regex = regex::Regex::new(
r"typename type\-parameter\-\d+\-\d+::.+"
r"typename type\-parameter\-\d+\-\d+::(.+)"
)
.unwrap();
}
ASSOC_TYPE_RE.is_match(spelling.as_ref())
ASSOC_TYPE_RE
.captures(spelling.as_ref())
.map(|caps| caps.get(1).unwrap().as_str().to_string())
}

self.kind() == CXType_Unexposed &&
(hacky_parse_associated_type(self.spelling()) ||
hacky_parse_associated_type(
self.canonical_type().spelling(),
))
if self.kind() != CXType_Unexposed {
return None;
}
hacky_parse_associated_type(self.spelling()).or_else(|| {
hacky_parse_associated_type(self.canonical_type().spelling())
})
}
}

Expand Down
1 change: 1 addition & 0 deletions src/codegen/impl_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ impl<'a> ImplDebug<'a> for Item {
TypeKind::ObjCInterface(..) |
TypeKind::ObjCId |
TypeKind::Comp(..) |
TypeKind::DependentQualifiedType(..) |
TypeKind::ObjCSel => debug_print(name, quote! { #name_ident }),

TypeKind::TemplateInstantiation(ref inst) => {
Expand Down
1 change: 1 addition & 0 deletions src/codegen/impl_partialeq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ fn gen_field(
TypeKind::Float(..) |
TypeKind::Enum(..) |
TypeKind::TypeParam |
TypeKind::DependentQualifiedType(..) |
TypeKind::UnresolvedTypeRef(..) |
TypeKind::Reference(..) |
TypeKind::ObjCInterface(..) |
Expand Down
139 changes: 138 additions & 1 deletion src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ struct CodegenResult<'a> {
/// function name to the number of overloads we have already codegen'd for
/// that name. This lets us give each overload a unique suffix.
overload_counters: HashMap<String, u32>,

/// Used to record what traits we have generated for the names
/// of inner types, such that we generate each trait exactly once.
/// (The trait may be implemented by multiple types.)
inner_type_traits_generated: HashSet<Ident>,
}

impl<'a> CodegenResult<'a> {
Expand All @@ -248,6 +253,7 @@ impl<'a> CodegenResult<'a> {
functions_seen: Default::default(),
vars_seen: Default::default(),
overload_counters: Default::default(),
inner_type_traits_generated: Default::default(),
}
}

Expand Down Expand Up @@ -393,6 +399,7 @@ impl AppendImplicitTemplateParams for proc_macro2::TokenStream {
TypeKind::Complex(..) |
TypeKind::Array(..) |
TypeKind::TypeParam |
TypeKind::DependentQualifiedType(..) |
TypeKind::Opaque |
TypeKind::Function(..) |
TypeKind::Enum(..) |
Expand Down Expand Up @@ -758,6 +765,25 @@ impl CodeGenerator for Type {
// it to BindgenContext::compute_allowlisted_and_codegen_items.
return;
}
TypeKind::DependentQualifiedType(_, ref field_name) => {
let shortname = ctx.rust_ident(&field_name);
let traitname = ctx.inner_type_trait_ident(field_name);
if result.inner_type_traits_generated.insert(traitname.clone())
{
let mut type_definition = quote! { #shortname };
let derivable_traits = derives_of_item(item, ctx);
append_associated_type_constraints(
ctx,
&derivable_traits,
&mut type_definition,
);
result.push(quote! {
pub trait #traitname {
type #type_definition;
}
});
}
}
TypeKind::TemplateInstantiation(ref inst) => {
inst.codegen(ctx, result, item)
}
Expand Down Expand Up @@ -1908,10 +1934,48 @@ impl CodeGenerator for CompInfo {

let mut generic_param_names = vec![];

let used_dependent_qualified_types =
item.used_dependent_qualified_types(ctx);
let mut dependent_qualified_types_by_param: HashMap<
crate::ir::context::TypeId,
Vec<&String>,
> = HashMap::default();
for ty_id in used_dependent_qualified_types {
let dependent_qualified_type = ctx.resolve_type(ty_id);
match dependent_qualified_type.kind() {
TypeKind::DependentQualifiedType(
tp_id,
associated_type_name,
) => {
dependent_qualified_types_by_param
.entry(*tp_id)
.or_default()
.push(associated_type_name);
}
_ => panic!(
"unexpected type kind for dependent qualified type type"
),
}
}

let mut where_constraints: std::collections::HashMap<
Ident,
Vec<Ident>,
> = std::collections::HashMap::new();
for (idx, ty) in item.used_template_params(ctx).iter().enumerate() {
let param = ctx.resolve_type(*ty);
let name = param.name().unwrap();
let ident = ctx.rust_ident(name);
if let Some(dependent_qualified_type_field_names) =
dependent_qualified_types_by_param.get(ty)
{
where_constraints.entry(ident.clone()).or_default().extend(
dependent_qualified_type_field_names.into_iter().map(
|field_name| ctx.inner_type_trait_ident(field_name),
),
);
}

generic_param_names.push(ident.clone());

let prefix = ctx.trait_prefix();
Expand Down Expand Up @@ -2013,8 +2077,28 @@ impl CodeGenerator for CompInfo {
}
};

let mut where_constraints_ts = quote! {};
if !where_constraints.is_empty() {
for (i, (k, traits)) in where_constraints.into_iter().enumerate() {
let prefix = if i == 0 {
quote! { where }
} else {
quote! { , }
};
where_constraints_ts.extend(quote! { #prefix #k });
for (j, v) in traits.into_iter().enumerate() {
let sep = if j == 0 {
quote! {:}
} else {
quote! {+}
};
where_constraints_ts.extend(quote! { #sep #v });
}
}
}

tokens.append_all(quote! {
#generics {
#generics #where_constraints_ts {
#( #fields )*
}
});
Expand All @@ -2028,6 +2112,26 @@ impl CodeGenerator for CompInfo {
let child_item = ctx.resolve_item(*ty);
// assert_eq!(child_item.parent_id(), item.id());
child_item.codegen(ctx, result, &());

if let Some(shortname) = child_item.expect_type().name() {
if !ctx.inner_type_used(shortname) {
continue;
}
let child_canonical_name = child_item.canonical_name(ctx);
let child_canonical_name =
ctx.rust_ident(&child_canonical_name);

let traitname = ctx.inner_type_trait_ident(&shortname);
let shortname = ctx.rust_ident(shortname);
let mut template_params = proc_macro2::TokenStream::new();
template_params
.append_implicit_template_params(ctx, child_item);
result.push(quote! {
impl #generics #traitname for #canonical_ident #generics {
type #shortname = #child_canonical_name #template_params;
}
});
}
}

// NOTE: Some unexposed attributes (like alignment attributes) may
Expand Down Expand Up @@ -2278,6 +2382,30 @@ impl CodeGenerator for CompInfo {
}
}

fn append_associated_type_constraints(
ctx: &BindgenContext,
derivable_traits: &DerivableTraits,
ts: &mut proc_macro2::TokenStream,
) {
let trait_bounds: Vec<&'static str> = derivable_traits.clone().into();
let mut done_first = false;
for id in trait_bounds.into_iter() {
let id = match id {
"Debug" => quote! { std::fmt::Debug },
_ => {
let id = ctx.rust_ident(id);
quote! { #id }
}
};
ts.append_all(if done_first {
quote! { + #id }
} else {
quote! { : #id }
});
done_first = true;
}
}

trait MethodCodegen {
fn codegen_method<'a>(
&self,
Expand Down Expand Up @@ -3666,6 +3794,15 @@ impl TryToRustTy for Type {
#ident
})
}
TypeKind::DependentQualifiedType(_, ref field_name) => {
let name = item.canonical_name(ctx);
let ident = ctx.rust_ident(&name);
let dependent_type_ident = ctx.rust_ident(&field_name);
let trait_id = ctx.inner_type_trait_ident(field_name);
Ok(quote! {
< #ident as #trait_id > :: #dependent_type_ident
})
}
TypeKind::ObjCSel => Ok(quote! {
objc::runtime::Sel
}),
Expand Down
3 changes: 3 additions & 0 deletions src/ir/analysis/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ fn consider_edge_default(kind: EdgeKind) -> bool {
EdgeKind::VarType |
EdgeKind::TemplateArgument |
EdgeKind::TemplateDeclaration |
EdgeKind::ContainedDependentQualifiedType |
EdgeKind::DependentQualifiedTypeParam |
EdgeKind::TemplateParameterDefinition => true,

EdgeKind::Constructor |
Expand Down Expand Up @@ -212,6 +214,7 @@ impl<'ctx> CannotDerive<'ctx> {
TypeKind::Float(..) |
TypeKind::Enum(..) |
TypeKind::TypeParam |
TypeKind::DependentQualifiedType(..) |
TypeKind::UnresolvedTypeRef(..) |
TypeKind::Reference(..) |
TypeKind::ObjCInterface(..) |
Expand Down
3 changes: 3 additions & 0 deletions src/ir/analysis/has_float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ impl<'ctx> HasFloat<'ctx> {
EdgeKind::VarType |
EdgeKind::TemplateArgument |
EdgeKind::TemplateDeclaration |
EdgeKind::ContainedDependentQualifiedType |
EdgeKind::DependentQualifiedTypeParam |
EdgeKind::TemplateParameterDefinition => true,

EdgeKind::Constructor |
Expand Down Expand Up @@ -122,6 +124,7 @@ impl<'ctx> MonotoneFramework for HasFloat<'ctx> {
TypeKind::Enum(..) |
TypeKind::Reference(..) |
TypeKind::TypeParam |
TypeKind::DependentQualifiedType(..) |
TypeKind::Opaque |
TypeKind::Pointer(..) |
TypeKind::UnresolvedTypeRef(..) |
Expand Down
3 changes: 3 additions & 0 deletions src/ir/analysis/has_type_param_in_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ impl<'ctx> HasTypeParameterInArray<'ctx> {
EdgeKind::VarType |
EdgeKind::TemplateArgument |
EdgeKind::TemplateDeclaration |
EdgeKind::ContainedDependentQualifiedType |
EdgeKind::DependentQualifiedTypeParam |
EdgeKind::TemplateParameterDefinition => true,

EdgeKind::Constructor |
Expand Down Expand Up @@ -133,6 +135,7 @@ impl<'ctx> MonotoneFramework for HasTypeParameterInArray<'ctx> {
TypeKind::Enum(..) |
TypeKind::Reference(..) |
TypeKind::TypeParam |
TypeKind::DependentQualifiedType(..) |
TypeKind::Opaque |
TypeKind::Pointer(..) |
TypeKind::UnresolvedTypeRef(..) |
Expand Down
2 changes: 1 addition & 1 deletion src/ir/analysis/sizedness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ impl<'ctx> MonotoneFramework for SizednessAnalysis<'ctx> {
self.insert(id, SizednessResult::ZeroSized)
}

TypeKind::TypeParam => {
TypeKind::TypeParam | TypeKind::DependentQualifiedType(..) => {
trace!(
" type params sizedness depends on what they're \
instantiated as"
Expand Down
7 changes: 7 additions & 0 deletions src/ir/analysis/template_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ impl<'ctx> UsedTemplateParameters<'ctx> {
EdgeKind::TemplateDeclaration |
EdgeKind::TemplateParameterDefinition => false,

EdgeKind::DependentQualifiedTypeParam |
EdgeKind::ContainedDependentQualifiedType => true,

// Since we have to be careful about which edges we consider for
// this analysis to be correct, we ignore generic edges. We also
// avoid a `_` wild card to force authors of new edge kinds to
Expand Down Expand Up @@ -534,6 +537,10 @@ impl<'ctx> MonotoneFramework for UsedTemplateParameters<'ctx> {
trace!(" named type, trivially uses itself");
used_by_this_id.insert(id);
}
Some(&TypeKind::DependentQualifiedType(tp_id, ..)) => {
used_by_this_id.insert(id);
used_by_this_id.insert(tp_id.into());
}
// Template instantiations only use their template arguments if the
// template definition uses the corresponding template parameter.
Some(&TypeKind::TemplateInstantiation(ref inst)) => {
Expand Down
Loading