diff --git a/crates/backend/src/defined.rs b/crates/backend/src/defined.rs index 20fd8635d..8eef37b7f 100644 --- a/crates/backend/src/defined.rs +++ b/crates/backend/src/defined.rs @@ -289,6 +289,9 @@ impl ImportedTypes for ast::ImportType { F: FnMut(&Ident, ImportedTypeKind), { f(&self.rust_name, ImportedTypeKind::Definition); + for class in self.extends.iter() { + f(class, ImportedTypeKind::Reference); + } } } @@ -344,10 +347,27 @@ impl RemoveUndefinedImports for ast::Program { where F: Fn(&Ident) -> bool, { - let a = self.imports.remove_undefined_imports(is_defined); - let b = self.consts.remove_undefined_imports(is_defined); - let c = self.dictionaries.remove_undefined_imports(is_defined); - a || b || c + let mut changed = self.imports.remove_undefined_imports(is_defined); + changed = self.consts.remove_undefined_imports(is_defined) || changed; + + let mut dictionaries_to_remove = Vec::new(); + for (i, dictionary) in self.dictionaries.iter_mut().enumerate() { + let num_required = |dict: &ast::Dictionary| { + dict.fields.iter().filter(|f| f.required).count() + }; + let before = num_required(dictionary); + changed = dictionary.fields.remove_undefined_imports(is_defined) || changed; + if before != num_required(dictionary) { + warn!("removing {} due to a required field being removed", + dictionary.name); + dictionaries_to_remove.push(i); + } + } + for i in dictionaries_to_remove.iter().rev() { + self.dictionaries.swap_remove(*i); + } + + changed || dictionaries_to_remove.len() > 0 } } diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index 5f971993e..51a3c9c2c 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -29,7 +29,7 @@ mod idl_type; mod util; mod error; -use std::collections::{BTreeSet, HashSet, BTreeMap}; +use std::collections::{BTreeSet, HashSet}; use std::env; use std::fs; use std::iter::FromIterator; @@ -80,49 +80,47 @@ fn parse(webidl_source: &str, allowed_types: Option<&[&str]>) definitions.first_pass(&mut first_pass_record, ())?; let mut program = Default::default(); - // Prune out everything in the `first_pass_record` which isn't allowed, or - // is otherwise gated from not actually being generated. - if let Some(allowed_types) = allowed_types { - let allowed = allowed_types.iter().cloned().collect::>(); - let filter = |name: &&str| { - allowed.contains(&camel_case_ident(name)[..]) - }; - retain(&mut first_pass_record.enums, &filter); - retain(&mut first_pass_record.dictionaries, &filter); - retain(&mut first_pass_record.interfaces, &filter); - } + let allowed_types = allowed_types.map(|list| { + list.iter().cloned().collect::>() + }); + let filter = |name: &str| { + match &allowed_types { + Some(set) => set.contains(&camel_case_ident(name)[..]), + None => true, + } + }; - for e in first_pass_record.enums.values() { - first_pass_record.append_enum(&mut program, e); + for (name, e) in first_pass_record.enums.iter() { + if filter(name) { + first_pass_record.append_enum(&mut program, e); + } } - for d in first_pass_record.dictionaries.values() { - first_pass_record.append_dictionary(&mut program, d); + for (name, d) in first_pass_record.dictionaries.iter() { + if filter(name) { + first_pass_record.append_dictionary(&mut program, d); + } } for (name, n) in first_pass_record.namespaces.iter() { first_pass_record.append_ns(&mut program, name, n); } for (name, d) in first_pass_record.interfaces.iter() { - first_pass_record.append_interface(&mut program, name, d); + if filter(name) { + first_pass_record.append_interface(&mut program, name, d); + } + } + + // Prune out `extends` annotations that aren't defined as these shouldn't + // prevent the type from being usable entirely. They're just there for + // `AsRef` and such implementations. + for import in program.imports.iter_mut() { + if let backend::ast::ImportKind::Type(t) = &mut import.kind { + t.extends.retain(|n| filter(&n.to_string())); + } } Ok(program) } -fn retain( - map: &mut BTreeMap, - mut filter: impl FnMut(&K) -> bool, -) { - let mut to_remove = Vec::new(); - for k in map.keys() { - if !filter(k) { - to_remove.push(*k); - } - } - for k in to_remove { - map.remove(&k); - } -} - /// Compile the given WebIDL source text into Rust source text containing /// `wasm-bindgen` bindings to the things described in the WebIDL. pub fn compile(