Support unions of objects in overloads

Part of #20513, implementing the parts useful for WebGL.
This commit is contained in:
Anthony Ramine 2018-08-27 12:08:17 +02:00
parent 4cf944eab8
commit 900a19058e
8 changed files with 37 additions and 89 deletions

View file

@ -344,11 +344,16 @@ class CGMethodCall(CGThing):
distinguishingIndex = method.distinguishingIndexForArgCount(argCount) distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
# We can't handle unions at the distinguishing index. # We can't handle unions of non-object values at the distinguishing index.
for (returnType, args) in possibleSignatures: for (returnType, args) in possibleSignatures:
if args[distinguishingIndex].type.isUnion(): type = args[distinguishingIndex].type
raise TypeError("No support for unions as distinguishing " if type.isUnion():
"arguments yet: %s", if type.nullable():
type = type.inner
for type in type.flatMemberTypes:
if not (type.isObject() or type.isNonCallbackInterface()):
raise TypeError("No support for unions with non-object variants "
"as distinguishing arguments yet: %s",
args[distinguishingIndex].location) args[distinguishingIndex].location)
# Convert all our arguments up to the distinguishing index. # Convert all our arguments up to the distinguishing index.
@ -388,6 +393,7 @@ class CGMethodCall(CGThing):
interfacesSigs = [ interfacesSigs = [
s for s in possibleSignatures s for s in possibleSignatures
if (s[1][distinguishingIndex].type.isObject() or if (s[1][distinguishingIndex].type.isObject() or
s[1][distinguishingIndex].type.isUnion() or
s[1][distinguishingIndex].type.isNonCallbackInterface())] s[1][distinguishingIndex].type.isNonCallbackInterface())]
# There might be more than one of these; we need to check # There might be more than one of these; we need to check
# which ones we unwrap to. # which ones we unwrap to.
@ -2366,7 +2372,6 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
'dom::bindings::conversions::ConversionBehavior', 'dom::bindings::conversions::ConversionBehavior',
'dom::bindings::conversions::StringificationBehavior', 'dom::bindings::conversions::StringificationBehavior',
'dom::bindings::conversions::root_from_handlevalue', 'dom::bindings::conversions::root_from_handlevalue',
'dom::bindings::error::throw_not_in_union',
'std::ptr::NonNull', 'std::ptr::NonNull',
'dom::bindings::mozmap::MozMap', 'dom::bindings::mozmap::MozMap',
'dom::bindings::root::DomRoot', 'dom::bindings::root::DomRoot',
@ -4450,8 +4455,8 @@ class CGUnionConversionStruct(CGThing):
other.append(booleanConversion[0]) other.append(booleanConversion[0])
conversions.append(CGList(other, "\n\n")) conversions.append(CGList(other, "\n\n"))
conversions.append(CGGeneric( conversions.append(CGGeneric(
"throw_not_in_union(cx, \"%s\");\n" "Ok(ConversionResult::Failure(\"argument could not be converted to any of: %s\".into()))" % ", ".join(names)
"Err(())" % ", ".join(names))) ))
method = CGWrapper( method = CGWrapper(
CGIndenter(CGList(conversions, "\n\n")), CGIndenter(CGList(conversions, "\n\n")),
pre="unsafe fn from_jsval(cx: *mut JSContext,\n" pre="unsafe fn from_jsval(cx: *mut JSContext,\n"

View file

@ -255,14 +255,6 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool)
} }
} }
/// Throw an exception to signal that a `JSVal` can not be converted to any of
/// the types in an IDL union type.
pub unsafe fn throw_not_in_union(cx: *mut JSContext, names: &'static str) {
assert!(!JS_IsExceptionPending(cx));
let error = format!("argument could not be converted to any of: {}", names);
throw_type_error(cx, &error);
}
/// Throw an exception to signal that a `JSObject` can not be converted to a /// Throw an exception to signal that a `JSObject` can not be converted to a
/// given DOM type. /// given DOM type.
pub unsafe fn throw_invalid_this(cx: *mut JSContext, proto_id: u16) { pub unsafe fn throw_invalid_this(cx: *mut JSContext, proto_id: u16) {

View file

@ -240,14 +240,18 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.GenerateMipmap(target) self.base.GenerateMipmap(target)
} }
#[allow(unsafe_code)]
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
unsafe fn BufferData(&self, cx: *mut JSContext, target: u32, data: *mut JSObject, usage: u32) -> Fallible<()> { fn BufferData(
self.base.BufferData(cx, target, data, usage) &self,
target: u32,
data: Option<ArrayBufferViewOrArrayBuffer>,
usage: u32,
) {
self.base.BufferData(target, data, usage)
} }
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn BufferData_(&self, target: u32, size: i64, usage: u32) -> Fallible<()> { fn BufferData_(&self, target: u32, size: i64, usage: u32) {
self.base.BufferData_(target, size, usage) self.base.BufferData_(target, size, usage)
} }

View file

@ -1326,19 +1326,6 @@ impl Drop for WebGLRenderingContext {
} }
} }
#[allow(unsafe_code)]
unsafe fn fallible_array_buffer_view_to_vec(
cx: *mut JSContext,
abv: *mut JSObject,
) -> Result<Vec<u8>, Error> {
assert!(!abv.is_null());
typedarray!(in(cx) let array_buffer_view: ArrayBufferView = abv);
match array_buffer_view {
Ok(v) => Ok(v.to_vec()),
Err(_) => Err(Error::Type("Not an ArrayBufferView".to_owned())),
}
}
impl WebGLRenderingContextMethods for WebGLRenderingContext { impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1
fn Canvas(&self) -> DomRoot<HTMLCanvasElement> { fn Canvas(&self) -> DomRoot<HTMLCanvasElement> {
@ -1894,52 +1881,44 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
handle_potential_webgl_error!(self, texture.generate_mipmap()); handle_potential_webgl_error!(self, texture.generate_mipmap());
} }
#[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
unsafe fn BufferData( fn BufferData(
&self, &self,
cx: *mut JSContext,
target: u32, target: u32,
data: *mut JSObject, data: Option<ArrayBufferViewOrArrayBuffer>,
usage: u32, usage: u32,
) -> ErrorResult { ) {
if data.is_null() { let data = match data {
return Ok(self.webgl_error(InvalidValue)); Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(data)) => data.to_vec(),
} Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(data)) => data.to_vec(),
None => return self.webgl_error(InvalidValue),
typedarray!(in(cx) let array_buffer: ArrayBuffer = data);
let data_vec = match array_buffer {
Ok(data) => data.to_vec(),
Err(_) => fallible_array_buffer_view_to_vec(cx, data)?,
}; };
let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return Ok(())); let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
let bound_buffer = match bound_buffer { let bound_buffer = match bound_buffer {
Some(bound_buffer) => bound_buffer, Some(bound_buffer) => bound_buffer,
None => return Ok(self.webgl_error(InvalidOperation)), None => return self.webgl_error(InvalidOperation),
}; };
handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, data_vec, usage)); handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, data, usage));
Ok(())
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn BufferData_(&self, target: u32, size: i64, usage: u32) -> ErrorResult { fn BufferData_(&self, target: u32, size: i64, usage: u32) {
let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return Ok(())); let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
let bound_buffer = match bound_buffer { let bound_buffer = match bound_buffer {
Some(bound_buffer) => bound_buffer, Some(bound_buffer) => bound_buffer,
None => return Ok(self.webgl_error(InvalidOperation)), None => return self.webgl_error(InvalidOperation),
}; };
if size < 0 { if size < 0 {
return Ok(self.webgl_error(InvalidValue)); return self.webgl_error(InvalidValue);
} }
// FIXME: Allocating a buffer based on user-requested size is // FIXME: Allocating a buffer based on user-requested size is
// not great, but we don't have a fallible allocation to try. // not great, but we don't have a fallible allocation to try.
let data = vec![0u8; size as usize]; let data = vec![0u8; size as usize];
handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, data, usage)); handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, data, usage));
Ok(())
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5

View file

@ -305,10 +305,7 @@ interface WebGL2RenderingContextBase
/* Buffer objects */ /* Buffer objects */
// WebGL1: // WebGL1:
// BUG: https://github.com/KhronosGroup/WebGL/issues/2216 // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
// FIXME(xanewok): https://github.com/servo/servo/issues/20513 void bufferData(GLenum target, /*[AllowShared]*/ BufferSource? data, GLenum usage);
[Throws]
void bufferData(GLenum target, object? data, GLenum usage);
[Throws]
void bufferData(GLenum target, GLsizeiptr size, GLenum usage); void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
void bufferSubData(GLenum target, GLintptr dstByteOffset, /*[AllowShared]*/ BufferSource srcData); void bufferSubData(GLenum target, GLintptr dstByteOffset, /*[AllowShared]*/ BufferSource srcData);
// WebGL2: // WebGL2:

View file

@ -688,10 +688,7 @@ interface WebGLRenderingContext
{ {
// BUG: https://github.com/KhronosGroup/WebGL/issues/2216 // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
// FIXME(xanewok): https://github.com/servo/servo/issues/20513 void bufferData(GLenum target, /*[AllowShared]*/ BufferSource? data, GLenum usage);
[Throws]
void bufferData(GLenum target, object? data, GLenum usage);
[Throws]
void bufferData(GLenum target, GLsizeiptr size, GLenum usage); void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
void bufferSubData(GLenum target, GLintptr offset, /*[AllowShared]*/ BufferSource data); void bufferSubData(GLenum target, GLintptr offset, /*[AllowShared]*/ BufferSource data);

View file

@ -1,6 +0,0 @@
[buffer-data-and-buffer-sub-data.html]
bug: https://github.com/servo/servo/issues/20513
expected: ERROR
[WebGL test #27: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
expected: FAIL

View file

@ -1,20 +0,0 @@
[type-conversion-test.html]
bug: https://github.com/servo/servo/issues/20513
[WebGL test #340: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView]
expected: FAIL
[WebGL test #407: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView]
expected: FAIL
[WebGL test #474: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView]
expected: FAIL
[WebGL test #541: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView]
expected: FAIL
[WebGL test #608: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView]
expected: FAIL
[WebGL test #675: context.bufferData(context.ARRAY_BUFFER, argument, context.STATIC_DRAW) should be undefined. Threw exception TypeError: Not an ArrayBufferView]
expected: FAIL