Make to_idl_type infallible

This commit makes the `to_idl_type` infallible, returning a new enum
variant, `UnknownInterface`, in the one location that we still return
`None`. By making this infallible we can ensure that expansion of unions
which have unknown types still generate methods for all the variants
which we actually have all the methods for!
This commit is contained in:
Alex Crichton 2018-11-07 10:37:43 -08:00
parent ac6a230d83
commit 176eedc63b
3 changed files with 66 additions and 78 deletions

View File

@ -63,24 +63,26 @@ pub(crate) enum IdlType<'a> {
Any, Any,
Void, Void,
UnknownInterface(&'a str),
} }
pub(crate) trait ToIdlType<'a> { pub(crate) trait ToIdlType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>>; fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a>;
} }
impl<'a> ToIdlType<'a> for UnionType<'a> { impl<'a> ToIdlType<'a> for UnionType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
let mut idl_types = Vec::with_capacity(self.body.list.len()); let mut idl_types = Vec::with_capacity(self.body.list.len());
for t in &self.body.list { for t in &self.body.list {
idl_types.push(t.to_idl_type(record)?); idl_types.push(t.to_idl_type(record));
} }
Some(IdlType::Union(idl_types)) IdlType::Union(idl_types)
} }
} }
impl<'a> ToIdlType<'a> for Type<'a> { impl<'a> ToIdlType<'a> for Type<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
match self { match self {
Type::Single(t) => t.to_idl_type(record), Type::Single(t) => t.to_idl_type(record),
Type::Union(t) => t.to_idl_type(record), Type::Union(t) => t.to_idl_type(record),
@ -89,7 +91,7 @@ impl<'a> ToIdlType<'a> for Type<'a> {
} }
impl<'a> ToIdlType<'a> for SingleType<'a> { impl<'a> ToIdlType<'a> for SingleType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
match self { match self {
SingleType::Any(t) => t.to_idl_type(record), SingleType::Any(t) => t.to_idl_type(record),
SingleType::NonAny(t) => t.to_idl_type(record), SingleType::NonAny(t) => t.to_idl_type(record),
@ -98,7 +100,7 @@ impl<'a> ToIdlType<'a> for SingleType<'a> {
} }
impl<'a> ToIdlType<'a> for NonAnyType<'a> { impl<'a> ToIdlType<'a> for NonAnyType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
match self { match self {
NonAnyType::Promise(t) => t.to_idl_type(record), NonAnyType::Promise(t) => t.to_idl_type(record),
NonAnyType::Integer(t) => t.to_idl_type(record), NonAnyType::Integer(t) => t.to_idl_type(record),
@ -134,42 +136,36 @@ impl<'a> ToIdlType<'a> for NonAnyType<'a> {
} }
impl<'a> ToIdlType<'a> for SequenceType<'a> { impl<'a> ToIdlType<'a> for SequenceType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
Some(IdlType::Sequence(Box::new( IdlType::Sequence(Box::new(self.generics.body.to_idl_type(record)))
self.generics.body.to_idl_type(record)?,
)))
} }
} }
impl<'a> ToIdlType<'a> for FrozenArrayType<'a> { impl<'a> ToIdlType<'a> for FrozenArrayType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
Some(IdlType::FrozenArray(Box::new( IdlType::FrozenArray(Box::new(self.generics.body.to_idl_type(record)))
self.generics.body.to_idl_type(record)?,
)))
} }
} }
impl<'a, T: ToIdlType<'a>> ToIdlType<'a> for MayBeNull<T> { impl<'a, T: ToIdlType<'a>> ToIdlType<'a> for MayBeNull<T> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
let inner_idl_type = self.type_.to_idl_type(record)?; let inner_idl_type = self.type_.to_idl_type(record);
if self.q_mark.is_some() { if self.q_mark.is_some() {
Some(IdlType::Nullable(Box::new(inner_idl_type))) IdlType::Nullable(Box::new(inner_idl_type))
} else { } else {
Some(inner_idl_type) inner_idl_type
} }
} }
} }
impl<'a> ToIdlType<'a> for PromiseType<'a> { impl<'a> ToIdlType<'a> for PromiseType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
Some(IdlType::Promise(Box::new( IdlType::Promise(Box::new(self.generics.body.to_idl_type(record)))
self.generics.body.to_idl_type(record)?,
)))
} }
} }
impl<'a> ToIdlType<'a> for IntegerType { impl<'a> ToIdlType<'a> for IntegerType {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
match self { match self {
IntegerType::LongLong(t) => t.to_idl_type(record), IntegerType::LongLong(t) => t.to_idl_type(record),
IntegerType::Long(t) => t.to_idl_type(record), IntegerType::Long(t) => t.to_idl_type(record),
@ -179,37 +175,37 @@ impl<'a> ToIdlType<'a> for IntegerType {
} }
impl<'a> ToIdlType<'a> for LongLongType { impl<'a> ToIdlType<'a> for LongLongType {
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> {
if self.unsigned.is_some() { if self.unsigned.is_some() {
Some(IdlType::UnsignedLongLong) IdlType::UnsignedLongLong
} else { } else {
Some(IdlType::LongLong) IdlType::LongLong
} }
} }
} }
impl<'a> ToIdlType<'a> for LongType { impl<'a> ToIdlType<'a> for LongType {
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> {
if self.unsigned.is_some() { if self.unsigned.is_some() {
Some(IdlType::UnsignedLong) IdlType::UnsignedLong
} else { } else {
Some(IdlType::Long) IdlType::Long
} }
} }
} }
impl<'a> ToIdlType<'a> for ShortType { impl<'a> ToIdlType<'a> for ShortType {
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> {
if self.unsigned.is_some() { if self.unsigned.is_some() {
Some(IdlType::UnsignedShort) IdlType::UnsignedShort
} else { } else {
Some(IdlType::Short) IdlType::Short
} }
} }
} }
impl<'a> ToIdlType<'a> for FloatingPointType { impl<'a> ToIdlType<'a> for FloatingPointType {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
match self { match self {
FloatingPointType::Float(t) => t.to_idl_type(record), FloatingPointType::Float(t) => t.to_idl_type(record),
FloatingPointType::Double(t) => t.to_idl_type(record), FloatingPointType::Double(t) => t.to_idl_type(record),
@ -218,36 +214,36 @@ impl<'a> ToIdlType<'a> for FloatingPointType {
} }
impl<'a> ToIdlType<'a> for FloatType { impl<'a> ToIdlType<'a> for FloatType {
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> {
if self.unrestricted.is_some() { if self.unrestricted.is_some() {
Some(IdlType::UnrestrictedFloat) IdlType::UnrestrictedFloat
} else { } else {
Some(IdlType::Float) IdlType::Float
} }
} }
} }
impl<'a> ToIdlType<'a> for DoubleType { impl<'a> ToIdlType<'a> for DoubleType {
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> {
if self.unrestricted.is_some() { if self.unrestricted.is_some() {
Some(IdlType::UnrestrictedDouble) IdlType::UnrestrictedDouble
} else { } else {
Some(IdlType::Double) IdlType::Double
} }
} }
} }
impl<'a> ToIdlType<'a> for RecordType<'a> { impl<'a> ToIdlType<'a> for RecordType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
Some(IdlType::Record( IdlType::Record(
Box::new(self.generics.body.0.to_idl_type(record)?), Box::new(self.generics.body.0.to_idl_type(record)),
Box::new(self.generics.body.2.to_idl_type(record)?), Box::new(self.generics.body.2.to_idl_type(record)),
)) )
} }
} }
impl<'a> ToIdlType<'a> for StringType { impl<'a> ToIdlType<'a> for StringType {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
match self { match self {
StringType::Byte(t) => t.to_idl_type(record), StringType::Byte(t) => t.to_idl_type(record),
StringType::DOM(t) => t.to_idl_type(record), StringType::DOM(t) => t.to_idl_type(record),
@ -257,7 +253,7 @@ impl<'a> ToIdlType<'a> for StringType {
} }
impl<'a> ToIdlType<'a> for UnionMemberType<'a> { impl<'a> ToIdlType<'a> for UnionMemberType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
match self { match self {
UnionMemberType::Single(t) => t.to_idl_type(record), UnionMemberType::Single(t) => t.to_idl_type(record),
UnionMemberType::Union(t) => t.to_idl_type(record), UnionMemberType::Union(t) => t.to_idl_type(record),
@ -266,7 +262,7 @@ impl<'a> ToIdlType<'a> for UnionMemberType<'a> {
} }
impl<'a> ToIdlType<'a> for ConstType<'a> { impl<'a> ToIdlType<'a> for ConstType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
match self { match self {
ConstType::Integer(t) => t.to_idl_type(record), ConstType::Integer(t) => t.to_idl_type(record),
ConstType::FloatingPoint(t) => t.to_idl_type(record), ConstType::FloatingPoint(t) => t.to_idl_type(record),
@ -279,7 +275,7 @@ impl<'a> ToIdlType<'a> for ConstType<'a> {
} }
impl<'a> ToIdlType<'a> for ReturnType<'a> { impl<'a> ToIdlType<'a> for ReturnType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
match self { match self {
ReturnType::Void(t) => t.to_idl_type(record), ReturnType::Void(t) => t.to_idl_type(record),
ReturnType::Type(t) => t.to_idl_type(record), ReturnType::Type(t) => t.to_idl_type(record),
@ -288,31 +284,31 @@ impl<'a> ToIdlType<'a> for ReturnType<'a> {
} }
impl<'a> ToIdlType<'a> for AttributedType<'a> { impl<'a> ToIdlType<'a> for AttributedType<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
self.type_.to_idl_type(record) self.type_.to_idl_type(record)
} }
} }
impl<'a> ToIdlType<'a> for Identifier<'a> { impl<'a> ToIdlType<'a> for Identifier<'a> {
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> IdlType<'a> {
if self.0 == "DOMTimeStamp" { if self.0 == "DOMTimeStamp" {
// https://heycam.github.io/webidl/#DOMTimeStamp // https://heycam.github.io/webidl/#DOMTimeStamp
Some(IdlType::UnsignedLongLong) IdlType::UnsignedLongLong
} else if let Some(idl_type) = record.typedefs.get(&self.0) { } else if let Some(idl_type) = record.typedefs.get(&self.0) {
idl_type.to_idl_type(record) idl_type.to_idl_type(record)
} else if record.interfaces.contains_key(self.0) { } else if record.interfaces.contains_key(self.0) {
Some(IdlType::Interface(self.0)) IdlType::Interface(self.0)
} else if record.dictionaries.contains_key(self.0) { } else if record.dictionaries.contains_key(self.0) {
Some(IdlType::Dictionary(self.0)) IdlType::Dictionary(self.0)
} else if record.enums.contains_key(self.0) { } else if record.enums.contains_key(self.0) {
Some(IdlType::Enum(self.0)) IdlType::Enum(self.0)
} else if record.callbacks.contains(self.0) { } else if record.callbacks.contains(self.0) {
Some(IdlType::Callback) IdlType::Callback
} else if let Some(data) = record.callback_interfaces.get(self.0) { } else if let Some(data) = record.callback_interfaces.get(self.0) {
Some(IdlType::CallbackInterface { IdlType::CallbackInterface {
name: self.0, name: self.0,
single_function: data.single_function, single_function: data.single_function,
}) }
} else if self.0 == "WindowProxy" { } else if self.0 == "WindowProxy" {
// See this for more info: // See this for more info:
// //
@ -320,10 +316,10 @@ impl<'a> ToIdlType<'a> for Identifier<'a> {
// //
// namely this seems to be "legalese" for "this is a `Window`", so // namely this seems to be "legalese" for "this is a `Window`", so
// let's translate it as such. // let's translate it as such.
Some(IdlType::Interface("Window")) IdlType::Interface("Window")
} else { } else {
warn!("Unrecognized type: {}", self.0); warn!("Unrecognized type: {}", self.0);
None IdlType::UnknownInterface(self.0)
} }
} }
} }
@ -331,8 +327,8 @@ impl<'a> ToIdlType<'a> for Identifier<'a> {
macro_rules! terms_to_idl_type { macro_rules! terms_to_idl_type {
($($t:tt => $r:tt)*) => ($( ($($t:tt => $r:tt)*) => ($(
impl<'a> ToIdlType<'a> for term::$t { impl<'a> ToIdlType<'a> for term::$t {
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> { fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> {
Some(IdlType::$r) IdlType::$r
} }
} }
)*) )*)
@ -406,6 +402,7 @@ impl<'a> IdlType<'a> {
IdlType::BufferSource => dst.push_str("buffer_source"), IdlType::BufferSource => dst.push_str("buffer_source"),
IdlType::Interface(name) => dst.push_str(&snake_case_ident(name)), IdlType::Interface(name) => dst.push_str(&snake_case_ident(name)),
IdlType::UnknownInterface(name) => dst.push_str(&snake_case_ident(name)),
IdlType::Dictionary(name) => dst.push_str(&snake_case_ident(name)), IdlType::Dictionary(name) => dst.push_str(&snake_case_ident(name)),
IdlType::Enum(name) => dst.push_str(&snake_case_ident(name)), IdlType::Enum(name) => dst.push_str(&snake_case_ident(name)),
IdlType::CallbackInterface { name, .. } => dst.push_str(&snake_case_ident(name)), IdlType::CallbackInterface { name, .. } => dst.push_str(&snake_case_ident(name)),
@ -587,6 +584,7 @@ impl<'a> IdlType<'a> {
} }
IdlType::Void => None, IdlType::Void => None,
IdlType::Callback => js_sys("Function"), IdlType::Callback => js_sys("Function"),
IdlType::UnknownInterface(_) => None,
} }
} }

View File

@ -353,7 +353,7 @@ impl<'src> FirstPassRecord<'src> {
// use argument position now as we're just binding setters // use argument position now as we're just binding setters
let ty = field let ty = field
.type_ .type_
.to_idl_type(self)? .to_idl_type(self)
.to_syn_type(TypePosition::Argument)?; .to_syn_type(TypePosition::Argument)?;
// Slice types aren't supported because they don't implement // Slice types aren't supported because they don't implement
@ -459,11 +459,7 @@ impl<'src> FirstPassRecord<'src> {
self_name: &'src str, self_name: &'src str,
member: &'src weedle::interface::ConstMember<'src>, member: &'src weedle::interface::ConstMember<'src>,
) { ) {
let idl_type = match member.const_type.to_idl_type(self) { let idl_type = member.const_type.to_idl_type(self);
Some(idl_type) => idl_type,
None => return,
};
let ty = match idl_type.to_syn_type(TypePosition::Return) { let ty = match idl_type.to_syn_type(TypePosition::Return) {
Some(ty) => ty, Some(ty) => ty,
None => { None => {

View File

@ -336,7 +336,7 @@ impl<'src> FirstPassRecord<'src> {
) -> Option<backend::ast::ImportFunction> { ) -> Option<backend::ast::ImportFunction> {
let kind = backend::ast::OperationKind::Getter(Some(raw_ident(name))); let kind = backend::ast::OperationKind::Getter(Some(raw_ident(name)));
let kind = self.import_function_kind(self_name, is_static, kind); let kind = self.import_function_kind(self_name, is_static, kind);
let ret = ty.to_idl_type(self)?; let ret = ty.to_idl_type(self);
self.create_one_function( self.create_one_function(
&name, &name,
&snake_case_ident(name), &snake_case_ident(name),
@ -366,7 +366,7 @@ impl<'src> FirstPassRecord<'src> {
) -> Option<backend::ast::ImportFunction> { ) -> Option<backend::ast::ImportFunction> {
let kind = backend::ast::OperationKind::Setter(Some(raw_ident(name))); let kind = backend::ast::OperationKind::Setter(Some(raw_ident(name)));
let kind = self.import_function_kind(self_name, is_static, kind); let kind = self.import_function_kind(self_name, is_static, kind);
let field_ty = field_ty.to_idl_type(self)?; let field_ty = field_ty.to_idl_type(self);
self.create_one_function( self.create_one_function(
&name, &name,
&format!("set_{}", name).to_snake_case(), &format!("set_{}", name).to_snake_case(),
@ -431,10 +431,7 @@ impl<'src> FirstPassRecord<'src> {
); );
signatures.push((signature, idl_args.clone())); signatures.push((signature, idl_args.clone()));
} }
match arg.ty.to_idl_type(self) { idl_args.push(arg.ty.to_idl_type(self));
Some(t) => idl_args.push(t),
None => continue 'outer,
}
} }
signatures.push((signature, idl_args)); signatures.push((signature, idl_args));
} }
@ -517,10 +514,7 @@ impl<'src> FirstPassRecord<'src> {
// TODO: overloads probably never change return types, so we should // TODO: overloads probably never change return types, so we should
// do this much earlier to avoid all the above work if // do this much earlier to avoid all the above work if
// possible. // possible.
let ret_ty = match signature.orig.ret.to_idl_type(self) { let ret_ty = signature.orig.ret.to_idl_type(self);
Some(ty) => ty,
None => continue,
};
let mut rust_name = snake_case_ident(name); let mut rust_name = snake_case_ident(name);
let mut first = true; let mut first = true;