mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Replace inheritance_integrity by trait shenanigans
For each derived DomObject impl, we also generate a dummy trait ShouldNotImplDomObject that is implemented for all T: DomObject. We then try to implement it for each field type except the first one. If compilation succeed, this means that field type doesn't implement DomObject itself otherwise it would break coherence rules. error[E0119]: conflicting implementations of trait `dom::xmlhttprequest::_IMPL_DOMOBJECT_FOR_XMLHttpRequest::ShouldNotImplDomObject` for type `((), SomeFieldTypeThatShouldNotImplementDomObject)`: --> /Users/nox/src/servo/components/script/dom/xmlhttprequest.rs:120:1 | 120 | #[dom_struct] | ^^^^^^^^^^^^^ | | | first implementation here | conflicting implementation for `((), SomeFieldTypeThatShouldNotImplementDomObject)`
This commit is contained in:
parent
37dab8f9f2
commit
a6d59d8714
7 changed files with 56 additions and 139 deletions
|
@ -14,17 +14,27 @@ pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenS
|
|||
fn expand_string(input: &str) -> String {
|
||||
let type_ = syn::parse_macro_input(input).unwrap();
|
||||
|
||||
let first_field_name = if let syn::Body::Struct(syn::VariantData::Struct(ref fields)) = type_.body {
|
||||
let first_field = fields.first().expect("#[derive(DomObject)] should not be applied on empty structs");
|
||||
first_field.ident.as_ref().unwrap()
|
||||
let fields = if let syn::Body::Struct(syn::VariantData::Struct(ref fields)) = type_.body {
|
||||
fields
|
||||
} else {
|
||||
panic!("#[derive(DomObject)] should only be applied on proper structs")
|
||||
};
|
||||
|
||||
let (first_field, fields) = fields
|
||||
.split_first()
|
||||
.expect("#[derive(DomObject)] should not be applied on empty structs");
|
||||
let first_field_name = first_field.ident.as_ref().unwrap();
|
||||
let mut field_types = vec![];
|
||||
for field in fields {
|
||||
if !field_types.contains(&&field.ty) {
|
||||
field_types.push(&field.ty);
|
||||
}
|
||||
}
|
||||
|
||||
let name = &type_.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = type_.generics.split_for_impl();
|
||||
|
||||
let tokens = quote! {
|
||||
let mut items = quote! {
|
||||
impl #impl_generics ::js::conversions::ToJSValConvertible for #name #ty_generics #where_clause {
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn to_jsval(&self,
|
||||
|
@ -49,5 +59,46 @@ fn expand_string(input: &str) -> String {
|
|||
}
|
||||
};
|
||||
|
||||
let mut params = quote::Tokens::new();
|
||||
params.append_separated(type_.generics.ty_params.iter().map(|param| ¶m.ident), ", ");
|
||||
|
||||
// For each field in the struct, we implement ShouldNotImplDomObject for a
|
||||
// pair of all the type parameters of the DomObject and and the field type.
|
||||
// This allows us to support parameterized DOM objects
|
||||
// such as IteratorIterable<T>.
|
||||
items.append_all(field_types.iter().map(|ty| {
|
||||
quote! {
|
||||
impl #impl_generics ShouldNotImplDomObject for ((#params), #ty) #where_clause {}
|
||||
}
|
||||
}));
|
||||
|
||||
let bound = syn::TyParamBound::Trait(
|
||||
syn::PolyTraitRef {
|
||||
bound_lifetimes: vec![],
|
||||
trait_ref: syn::parse_path("::dom::bindings::reflector::DomObject").unwrap(),
|
||||
},
|
||||
syn::TraitBoundModifier::None
|
||||
);
|
||||
|
||||
let mut generics = type_.generics.clone();
|
||||
generics.ty_params.push(syn::TyParam {
|
||||
attrs: vec![],
|
||||
ident: "__T".into(),
|
||||
bounds: vec![bound],
|
||||
default: None,
|
||||
});
|
||||
let (impl_generics, _, where_clause) = generics.split_for_impl();
|
||||
|
||||
items.append(quote! {
|
||||
trait ShouldNotImplDomObject {}
|
||||
impl #impl_generics ShouldNotImplDomObject for ((#params), __T) #where_clause {}
|
||||
}.as_str());
|
||||
|
||||
let dummy_const = syn::Ident::new(format!("_IMPL_DOMOBJECT_FOR_{}", name));
|
||||
let tokens = quote! {
|
||||
#[allow(non_upper_case_globals)]
|
||||
const #dummy_const: () = { #items };
|
||||
};
|
||||
|
||||
tokens.to_string()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue