-
Notifications
You must be signed in to change notification settings - Fork 315
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
Add support for transparent typedefs #966
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
use std::borrow::Cow; | ||
use std::collections::HashMap; | ||
use std::io::Write; | ||
use std::ops::Deref; | ||
|
||
|
@@ -8,16 +10,17 @@ use crate::bindgen::config::{Config, Language}; | |
use crate::bindgen::declarationtyperesolver::{DeclarationType, DeclarationTypeResolver}; | ||
use crate::bindgen::ir::{ConstExpr, Path, Type}; | ||
use crate::bindgen::language_backend::LanguageBackend; | ||
use crate::bindgen::library::Library; | ||
use crate::bindgen::utilities::IterHelpers; | ||
use crate::bindgen::writer::SourceWriter; | ||
|
||
#[derive(Debug, Clone)] | ||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
pub enum GenericParamType { | ||
Type, | ||
Const(Type), | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
pub struct GenericParam { | ||
name: Path, | ||
ty: GenericParamType, | ||
|
@@ -103,6 +106,24 @@ impl GenericParams { | |
Ok(GenericParams(params)) | ||
} | ||
|
||
/// If `generics` is empty, create a set of "default" generic arguments, which preserves the | ||
/// existing parameter name. Useful to allow `call` to work when no generics are provided. | ||
pub fn defaulted_generics<'a>( | ||
&self, | ||
generics: &'a [GenericArgument], | ||
) -> Cow<'a, [GenericArgument]> { | ||
if !self.is_empty() && generics.is_empty() { | ||
Cow::Owned( | ||
self.iter() | ||
.map(|param| Type::Path(GenericPath::new(param.name.clone(), vec![]))) | ||
.map(GenericArgument::Type) | ||
.collect(), | ||
) | ||
} else { | ||
Cow::Borrowed(generics) | ||
} | ||
} | ||
|
||
/// Associate each parameter with an argument. | ||
pub fn call<'out>( | ||
&'out self, | ||
|
@@ -234,6 +255,48 @@ impl GenericArgument { | |
} | ||
} | ||
|
||
/// Helper for erasing transparent types, which memoizes already-seen types to avoid repeated work. | ||
#[derive(Default)] | ||
pub struct TransparentTypeEraser { | ||
// Remember paths we've already visited, so we don't repeat unnecessary work. | ||
// TODO: how to handle recursive types such as `struct Foo { next: Box<Foo> }`? | ||
known_types: HashMap<Type, Option<Type>>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really expect extremely long chains of transparent typedefs? Memoizing this seems over-kill without performance numbers, IMHO... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know about long chains, but I do expect frequent use (typedefs exist to eliminate repetition in typing out complex type names). Is frequent use not sufficient reason to memoize? |
||
} | ||
|
||
impl TransparentTypeEraser { | ||
pub fn erase_transparent_types_inplace( | ||
&mut self, | ||
library: &Library, | ||
target: &mut Type, | ||
mappings: &[(&Path, &GenericArgument)], | ||
) { | ||
if let Some(erased_type) = self.erase_transparent_types(library, target, mappings) { | ||
*target = erased_type; | ||
} | ||
} | ||
|
||
#[must_use] | ||
pub fn erase_transparent_types( | ||
&mut self, | ||
library: &Library, | ||
target: &Type, | ||
mappings: &[(&Path, &GenericArgument)], | ||
) -> Option<Type> { | ||
let known_type = self.known_types.get(target); | ||
let unknown_type = known_type.is_none(); | ||
let erased_type = if let Some(ty) = known_type { | ||
ty.clone() | ||
} else { | ||
target.erase_transparent_types(library, mappings, self) | ||
}; | ||
if unknown_type { | ||
debug!("Caching erasure of {:?} as {:?}", target, erased_type); | ||
self.known_types.insert(target.clone(), erased_type.clone()); | ||
} | ||
erased_type | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
pub struct GenericPath { | ||
path: Path, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes seem unrelated? Seems ok, but maybe worth splitting into its own commit / PR? Or is it some sort of autoformatting i'm not aware of?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just fixing broken indentation in the existing .md, so that bullets would render correctly. If you hide whitespace changes the diff disappears:
Happy to split it out if it's too noisy/annoying, tho.