diff --git a/crates/cli-support/Cargo.toml b/crates/cli-support/Cargo.toml index c65e2676d50..62a6bb7f88c 100644 --- a/crates/cli-support/Cargo.toml +++ b/crates/cli-support/Cargo.toml @@ -13,7 +13,7 @@ Shared support for the wasm-bindgen-cli package, an internal dependency [dependencies] base64 = "0.9" failure = "0.1.2" -parity-wasm = "0.35" +parity-wasm = "0.36" tempfile = "3.0" wasm-bindgen-gc = { path = '../gc', version = '=0.2.33' } wasm-bindgen-shared = { path = "../shared", version = '=0.2.33' } diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 0ff36301a55..8d86487caa4 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -1546,6 +1546,23 @@ impl<'a> Context<'a> { )); } + fn expose_handle_error(&mut self) { + if !self.should_write_global("handle_error") { + return; + } + self.expose_uint32_memory(); + self.expose_add_heap_object(); + self.global( + " + function handleError(exnptr, e) { + const view = getUint32Memory(); + view[exnptr / 4] = 1; + view[exnptr / 4 + 1] = addHeapObject(e); + } + ", + ); + } + fn wasm_import_needed(&self, name: &str) -> bool { let imports = match self.module.import_section() { Some(s) => s, diff --git a/crates/cli-support/src/js/rust2js.rs b/crates/cli-support/src/js/rust2js.rs index 43cb8e2e602..20c60d3dd22 100644 --- a/crates/cli-support/src/js/rust2js.rs +++ b/crates/cli-support/src/js/rust2js.rs @@ -643,23 +643,16 @@ impl<'a, 'b> Rust2Js<'a, 'b> { }; if self.catch { - self.cx.expose_uint32_memory(); - self.cx.expose_add_heap_object(); - let catch = "\ - const view = getUint32Memory();\n\ - view[exnptr / 4] = 1;\n\ - view[exnptr / 4 + 1] = addHeapObject(e);\n\ - "; - + self.cx.expose_handle_error(); invoc = format!( "\ try {{\n\ {} }} catch (e) {{\n\ - {} + handleError(exnptr, e);\n\ }}\ ", - &invoc, catch + &invoc ); } else if self.catch_and_rethrow { invoc = format!( diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 7d78da07eac..613308b05e8 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -18,7 +18,7 @@ docopt = "1.0" env_logger = "0.6" failure = "0.1.2" log = "0.4" -parity-wasm = "0.35" +parity-wasm = "0.36" rouille = { version = "3.0.0", default-features = false } serde = "1.0" serde_derive = "1.0" diff --git a/crates/cli/src/bin/wasm-bindgen-test-runner/index-headless.html b/crates/cli/src/bin/wasm-bindgen-test-runner/index-headless.html index 11c4d56156e..a65c242fd58 100644 --- a/crates/cli/src/bin/wasm-bindgen-test-runner/index-headless.html +++ b/crates/cli/src/bin/wasm-bindgen-test-runner/index-headless.html @@ -13,7 +13,7 @@ const orig = id => (...args) => { const logs = document.getElementById(id); for (let msg of args) { - logs.innerHTML += `${msg}\n`; + logs.textContent += `${msg}\n`; } }; diff --git a/crates/cli/src/bin/wasm-bindgen-test-runner/server.rs b/crates/cli/src/bin/wasm-bindgen-test-runner/server.rs index 29942b2cff7..f7e9a3d88cc 100644 --- a/crates/cli/src/bin/wasm-bindgen-test-runner/server.rs +++ b/crates/cli/src/bin/wasm-bindgen-test-runner/server.rs @@ -30,7 +30,7 @@ pub fn spawn( // Now that we've gotten to the point where JS is executing, update our // status text as at this point we should be asynchronously fetching the // wasm module. - document.getElementById('output').innerHTML = "Loading wasm module..."; + document.getElementById('output').textContent = "Loading wasm module..."; async function main(test) {{ // this is a facet of using wasm2es6js, a hack until browsers have diff --git a/crates/futures/tests/tests.rs b/crates/futures/tests/tests.rs old mode 100644 new mode 100755 index e8e6bbf4267..d8ea2674e6b --- a/crates/futures/tests/tests.rs +++ b/crates/futures/tests/tests.rs @@ -108,3 +108,10 @@ fn spawn_local_err_no_exception() -> impl Future { }) } +#[wasm_bindgen_test(async)] +fn can_create_multiple_futures_from_same_promise() -> impl Future { + let promise = js_sys::Promise::resolve(&JsValue::null()); + let a = JsFuture::from(promise.clone()); + let b = JsFuture::from(promise); + futures::future::join_all(vec![a, b]).map(|_| ()) +} diff --git a/crates/gc/Cargo.toml b/crates/gc/Cargo.toml index 2bf20eb07d6..b21961e195c 100644 --- a/crates/gc/Cargo.toml +++ b/crates/gc/Cargo.toml @@ -11,7 +11,7 @@ Support for removing unused items from a wasm executable """ [dependencies] -parity-wasm = "0.35.1" +parity-wasm = "0.36" log = "0.4" rustc-demangle = "0.1.9" diff --git a/crates/gc/src/lib.rs b/crates/gc/src/lib.rs index ec4a459cc5a..851380e42a4 100644 --- a/crates/gc/src/lib.rs +++ b/crates/gc/src/lib.rs @@ -99,6 +99,10 @@ fn run(config: &mut Config, module: &mut Module) { info!("skipping reloc section"); continue; } + Section::DataCount(..) => { + info!("skipping data count section"); + continue; + } Section::Type(ref mut s) => cx.remap_type_section(s), Section::Import(ref mut s) => cx.remap_import_section(s), Section::Function(ref mut s) => cx.remap_function_section(s), diff --git a/crates/gc/tests/wat/remove-passive-memory-segment.wat b/crates/gc/tests/wat/remove-passive-memory-segment.wat deleted file mode 100644 index 5c8d92d5e94..00000000000 --- a/crates/gc/tests/wat/remove-passive-memory-segment.wat +++ /dev/null @@ -1,18 +0,0 @@ -(module - (memory 0 10) - - (func $foo - i32.const 0 - i32.const 0 - i32.const 0 - memory.init 0 - ) - - (data passive "wut") - - ) - -;; STDOUT (update this section with `BLESS_TESTS=1` while running tests) -;; (module -;; (memory (;0;) 0 10)) -;; STDOUT diff --git a/crates/gc/tests/wat/renumber-data-segment.wat b/crates/gc/tests/wat/renumber-data-segment.wat deleted file mode 100644 index 199086eaba1..00000000000 --- a/crates/gc/tests/wat/renumber-data-segment.wat +++ /dev/null @@ -1,29 +0,0 @@ -(module - (memory 0 10) - - (func $foo - i32.const 0 - i32.const 0 - i32.const 0 - memory.init 1 - ) - - (data passive "wut") - (data passive "wut2") - (data passive "wut3") - - (start $foo) - ) - -;; STDOUT (update this section with `BLESS_TESTS=1` while running tests) -;; (module -;; (type (;0;) (func)) -;; (func $foo (type 0) -;; i32.const 0 -;; i32.const 0 -;; i32.const 0 -;; memory.init 0) -;; (memory (;0;) 0 10) -;; (start 0) -;; (data (;0;) passive "wut2")) -;; STDOUT diff --git a/crates/gc/tests/wat/renumber-passive-segment.wat b/crates/gc/tests/wat/renumber-passive-segment.wat deleted file mode 100644 index f459ae39c1f..00000000000 --- a/crates/gc/tests/wat/renumber-passive-segment.wat +++ /dev/null @@ -1,32 +0,0 @@ -(module - (import "" "" (table 0 1 anyfunc)) - - (func $foo - i32.const 0 - i32.const 0 - i32.const 0 - table.init 1 - ) - - (func $bar) - (func $bar2) - - (elem passive $bar) - (elem passive $bar2) - - (start $foo) - ) - -;; STDOUT (update this section with `BLESS_TESTS=1` while running tests) -;; (module -;; (type (;0;) (func)) -;; (import "" "" (table (;0;) 0 1 anyfunc)) -;; (func $foo (type 0) -;; i32.const 0 -;; i32.const 0 -;; i32.const 0 -;; table.init 0) -;; (func $bar2 (type 0)) -;; (start 0) -;; (elem (;0;) passive $bar2)) -;; STDOUT diff --git a/crates/test/src/rt/browser.rs b/crates/test/src/rt/browser.rs index a3beecee0bb..d488a0dd512 100644 --- a/crates/test/src/rt/browser.rs +++ b/crates/test/src/rt/browser.rs @@ -22,10 +22,10 @@ extern "C" { fn getElementById(this: &HTMLDocument, id: &str) -> Element; type Element; - #[wasm_bindgen(method, getter = innerHTML, structural)] - fn inner_html(this: &Element) -> String; - #[wasm_bindgen(method, setter = innerHTML, structural)] - fn set_inner_html(this: &Element, html: &str); + #[wasm_bindgen(method, getter = textContent, structural)] + fn text_content(this: &Element) -> String; + #[wasm_bindgen(method, setter = textContent, structural)] + fn set_text_content(this: &Element, text: &str); type BrowserError; #[wasm_bindgen(method, getter, structural)] @@ -37,24 +37,16 @@ impl Browser { /// (requires `Node::new()` to have return `None` first). pub fn new() -> Browser { let pre = document.getElementById("output"); - pre.set_inner_html(""); + pre.set_text_content(""); Browser { pre } } } impl super::Formatter for Browser { fn writeln(&self, line: &str) { - let mut html = self.pre.inner_html(); - for c in line.chars() { - match c { - '<' => html.push_str("<"), - '>' => html.push_str(">"), - '&' => html.push_str("&"), - c => html.push(c), - } - } - html.push_str("\n"); - self.pre.set_inner_html(&html); + let mut html = self.pre.text_content(); + html.extend(line.chars().chain(Some('\n'))); + self.pre.set_text_content(&html); } fn log_test(&self, name: &str, result: &Result<(), JsValue>) { diff --git a/crates/threads-xform/Cargo.toml b/crates/threads-xform/Cargo.toml index 78f786e2fa0..1d6cc40766d 100644 --- a/crates/threads-xform/Cargo.toml +++ b/crates/threads-xform/Cargo.toml @@ -11,5 +11,5 @@ Support for threading-related transformations in wasm-bindgen """ [dependencies] -parity-wasm = "0.35" +parity-wasm = "0.36" failure = "0.1" diff --git a/crates/wasm-interpreter/Cargo.toml b/crates/wasm-interpreter/Cargo.toml index a4bcf74c2e5..8c59b19c01e 100644 --- a/crates/wasm-interpreter/Cargo.toml +++ b/crates/wasm-interpreter/Cargo.toml @@ -11,7 +11,7 @@ Micro-interpreter optimized for wasm-bindgen's use case """ [dependencies] -parity-wasm = "0.35" +parity-wasm = "0.36" [dev-dependencies] tempfile = "3" diff --git a/crates/web-sys/tests/wasm/element.js b/crates/web-sys/tests/wasm/element.js index ed51fbdbe71..3f34bc5f64e 100644 --- a/crates/web-sys/tests/wasm/element.js +++ b/crates/web-sys/tests/wasm/element.js @@ -151,6 +151,11 @@ export function new_title() { return document.createElement("title"); } +export function new_webgl_rendering_context() { + const canvas = document.createElement('canvas'); + return canvas.getContext('webgl'); +} + export function new_xpath_result() { let xmlDoc = new DOMParser().parseFromString("tomato", "application/xml"); let xpathResult = xmlDoc.evaluate("/root//value", xmlDoc, null, XPathResult.ANY_TYPE, null); diff --git a/crates/web-sys/tests/wasm/main.rs b/crates/web-sys/tests/wasm/main.rs index 8f2fd5ffd49..e3d3b48af0e 100644 --- a/crates/web-sys/tests/wasm/main.rs +++ b/crates/web-sys/tests/wasm/main.rs @@ -56,6 +56,7 @@ pub mod style_element; pub mod table_element; pub mod title_element; pub mod xpath_result; +pub mod whitelisted_immutable_slices; #[wasm_bindgen_test] fn deref_works() { diff --git a/crates/web-sys/tests/wasm/whitelisted_immutable_slices.rs b/crates/web-sys/tests/wasm/whitelisted_immutable_slices.rs new file mode 100644 index 00000000000..07804f652af --- /dev/null +++ b/crates/web-sys/tests/wasm/whitelisted_immutable_slices.rs @@ -0,0 +1,57 @@ +//! When generating our web_sys APIs we default to setting slice references that +//! get passed to JS as mutable in case they get mutated in JS. +//! +//! In certain cases we know for sure that the slice will not get mutated - for +//! example when working with the WebGlRenderingContext APIs. +//! +//! These tests ensure that whitelisted methods do indeed accept mutable slices. +//! Especially important since this whitelist is stringly typed and currently +//! maintained by hand. +//! +//! @see https://github.com/rustwasm/wasm-bindgen/issues/1005 + +use wasm_bindgen::prelude::*; +use wasm_bindgen_test::*; +use web_sys::WebGlRenderingContext; + +#[wasm_bindgen(module = "./tests/wasm/element.js")] +extern "C" { + fn new_webgl_rendering_context() -> WebGlRenderingContext; + // TODO: Add a function to create another type to test here. + // These functions come from element.js +} + +// TODO: Uncomment WebGlRenderingContext test. Every now and then we can check if this works +// in the latest geckodriver. +// +// Currently commented out because WebGl isn't working in geckodriver. +// +// It currently works in chromedriver so if you need to run this in the meantime you can +// uncomment this block and run it in using chromedriver. +// +// CHROMEDRIVER=chromedriver cargo test --manifest-path crates/web-sys/Cargo.toml --target wasm32-unknown-unknown --all-features test_webgl_rendering_context_immutable_slices + +// Ensure that our whitelisted WebGlRenderingContext methods work +//#[wasm_bindgen_test] +//fn test_webgl_rendering_context_immutable_slices() { +// let gl = new_webgl_rendering_context(); +// +// gl.vertex_attrib1fv_with_f32_array(0, &[1.]); +// gl.vertex_attrib2fv_with_f32_array(0, &[1.]); +// gl.vertex_attrib3fv_with_f32_array(0, &[1.]); +// gl.vertex_attrib4fv_with_f32_array(0, &[1.]); +// +// gl.uniform1fv_with_f32_array(None, &[1.]); +// gl.uniform2fv_with_f32_array(None, &[1.]); +// gl.uniform3fv_with_f32_array(None, &[1.]); +// gl.uniform4fv_with_f32_array(None, &[1.]); +// +// gl.uniform_matrix2fv_with_f32_array(None, false, &[1.]); +// gl.uniform_matrix3fv_with_f32_array(None, false, &[1.]); +// gl.uniform_matrix4fv_with_f32_array(None, false, &[1.]); +//} + +// TODO: +//#[wasm_bindgen_test] +//fn test_another_types_immutable_slices_here() { +//} diff --git a/crates/webidl-tests/lib.rs b/crates/webidl-tests/lib.rs index 44425d9c15f..ef346239a83 100644 --- a/crates/webidl-tests/lib.rs +++ b/crates/webidl-tests/lib.rs @@ -1 +1 @@ -// intentionally left blank +// Intentionally left blank in order for Cargo to work diff --git a/crates/webidl/src/first_pass.rs b/crates/webidl/src/first_pass.rs index 79b5a2da75c..02ab48e07a1 100644 --- a/crates/webidl/src/first_pass.rs +++ b/crates/webidl/src/first_pass.rs @@ -37,6 +37,7 @@ pub(crate) struct FirstPassRecord<'src> { pub(crate) dictionaries: BTreeMap<&'src str, DictionaryData<'src>>, pub(crate) callbacks: BTreeSet<&'src str>, pub(crate) callback_interfaces: BTreeMap<&'src str, CallbackInterfaceData<'src>>, + pub(crate) immutable_f32_whitelist: BTreeSet<&'static str> } /// We need to collect interface data during the first pass, to be used later. @@ -83,6 +84,9 @@ pub(crate) struct CallbackInterfaceData<'src> { #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] pub(crate) enum OperationId<'src> { Constructor(IgnoreTraits<&'src str>), + /// The name of a function in crates/web-sys/webidls/enabled/*.webidl + /// + /// ex: Operation(Some("vertexAttrib1fv")) Operation(Option<&'src str>), IndexingGetter, IndexingSetter, diff --git a/crates/webidl/src/idl_type.rs b/crates/webidl/src/idl_type.rs index d2dd3e8b234..ca9fcb58223 100644 --- a/crates/webidl/src/idl_type.rs +++ b/crates/webidl/src/idl_type.rs @@ -41,7 +41,10 @@ pub(crate) enum IdlType<'a> { Uint16Array, Int32Array, Uint32Array, - Float32Array, + Float32Array { + /// Whether or not the generated web-sys function should use an immutable slice + immutable: bool + }, Float64Array, ArrayBufferView, BufferSource, @@ -324,6 +327,15 @@ impl<'a> ToIdlType<'a> for Identifier<'a> { } } +// We default to Float32Array's being mutable, but in certain cases where we're certain that +// slices won't get mutated on the JS side (such as the WebGL APIs) we might, later in the flow, +// instead use the immutable version. +impl<'a> ToIdlType<'a> for term::Float32Array { + fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> IdlType<'a> { + IdlType::Float32Array {immutable: false} + } +} + macro_rules! terms_to_idl_type { ($($t:tt => $r:tt)*) => ($( impl<'a> ToIdlType<'a> for term::$t { @@ -331,7 +343,7 @@ macro_rules! terms_to_idl_type { IdlType::$r } } - )*) + )*); } terms_to_idl_type! { @@ -358,7 +370,6 @@ terms_to_idl_type! { Uint16Array => Uint16Array Uint32Array => Uint32Array Uint8ClampedArray => Uint8ClampedArray - Float32Array => Float32Array Float64Array => Float64Array ArrayBufferView => ArrayBufferView BufferSource => BufferSource @@ -396,7 +407,7 @@ impl<'a> IdlType<'a> { IdlType::Uint16Array => dst.push_str("u16_array"), IdlType::Int32Array => dst.push_str("i32_array"), IdlType::Uint32Array => dst.push_str("u32_array"), - IdlType::Float32Array => dst.push_str("f32_array"), + IdlType::Float32Array { .. } => dst.push_str("f32_array"), IdlType::Float64Array => dst.push_str("f64_array"), IdlType::ArrayBufferView => dst.push_str("array_buffer_view"), IdlType::BufferSource => dst.push_str("buffer_source"), @@ -501,16 +512,16 @@ impl<'a> IdlType<'a> { IdlType::ArrayBuffer => js_sys("ArrayBuffer"), IdlType::DataView => None, - IdlType::Int8Array => Some(array("i8", pos)), - IdlType::Uint8Array => Some(array("u8", pos)), - IdlType::Uint8ArrayMut => Some(array("u8", pos)), - IdlType::Uint8ClampedArray => Some(clamped(array("u8", pos))), - IdlType::Int16Array => Some(array("i16", pos)), - IdlType::Uint16Array => Some(array("u16", pos)), - IdlType::Int32Array => Some(array("i32", pos)), - IdlType::Uint32Array => Some(array("u32", pos)), - IdlType::Float32Array => Some(array("f32", pos)), - IdlType::Float64Array => Some(array("f64", pos)), + IdlType::Int8Array => Some(array("i8", pos, false)), + IdlType::Uint8Array => Some(array("u8", pos, false)), + IdlType::Uint8ArrayMut => Some(array("u8", pos, false)), + IdlType::Uint8ClampedArray => Some(clamped(array("u8", pos, false))), + IdlType::Int16Array => Some(array("i16", pos, false)), + IdlType::Uint16Array => Some(array("u16", pos, false)), + IdlType::Int32Array => Some(array("i32", pos, false)), + IdlType::Uint32Array => Some(array("u32", pos, false)), + IdlType::Float32Array {immutable} => Some(array("f32", pos, *immutable)), + IdlType::Float64Array => Some(array("f64", pos, false)), IdlType::ArrayBufferView | IdlType::BufferSource => js_sys("Object"), IdlType::Interface(name) diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index 2e11b1282ef..637070c0ab4 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -82,6 +82,8 @@ fn parse(webidl_source: &str, allowed_types: Option<&[&str]>) -> Result let mut first_pass_record: FirstPassRecord = Default::default(); first_pass_record.builtin_idents = builtin_idents(); + first_pass_record.immutable_f32_whitelist = immutable_f32_whitelist(); + definitions.first_pass(&mut first_pass_record, ())?; let mut program = Default::default(); let mut submodules = Vec::new(); @@ -179,6 +181,26 @@ fn builtin_idents() -> BTreeSet { ) } +fn immutable_f32_whitelist() -> BTreeSet<&'static str> { + BTreeSet::from_iter( + vec![ + // WebGlRenderingContext + "uniform1fv", + "uniform2fv", + "uniform3fv", + "uniform4fv", + "uniformMatrix2fv", + "uniformMatrix3fv", + "uniformMatrix4fv", + "vertexAttrib1fv", + "vertexAttrib2fv", + "vertexAttrib3fv", + "vertexAttrib4fv", + // TODO: Add another type's functions here. Leave a comment header with the type name + ] + ) +} + /// Run codegen on the AST to generate rust code. fn compile_ast(mut ast: Program) -> String { // Iteratively prune all entries from the AST which reference undefined diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs index 412e45d7c66..f0e896247ef 100644 --- a/crates/webidl/src/util.rs +++ b/crates/webidl/src/util.rs @@ -67,13 +67,13 @@ pub fn mdn_doc(class: &str, method: Option<&str>) -> String { format!("[MDN Documentation]({})", link).into() } -// Array type is borrowed for arguments (`&[T]`) and owned for return value (`Vec`). -pub(crate) fn array(base_ty: &str, pos: TypePosition) -> syn::Type { +// Array type is borrowed for arguments (`&mut [T]` or `&[T]`) and owned for return value (`Vec`). +pub(crate) fn array(base_ty: &str, pos: TypePosition, immutable: bool) -> syn::Type { match pos { TypePosition::Argument => { shared_ref( slice_ty(ident_ty(raw_ident(base_ty))), - /*mutable =*/ true, + /*mutable =*/ !immutable, ) } TypePosition::Return => vec_ty(ident_ty(raw_ident(base_ty))), @@ -433,7 +433,10 @@ impl<'src> FirstPassRecord<'src> { ); signatures.push((signature, idl_args.clone())); } - idl_args.push(arg.ty.to_idl_type(self)); + + let mut idl_type = arg.ty.to_idl_type(self); + let idl_type = self.maybe_adjust(idl_type, id); + idl_args.push(idl_type); } signatures.push((signature, idl_args)); } @@ -627,6 +630,34 @@ impl<'src> FirstPassRecord<'src> { } return ret; } + + + /// When generating our web_sys APIs we default to setting slice references that + /// get passed to JS as mutable in case they get mutated in JS. + /// + /// In certain cases we know for sure that the slice will not get mutated - for + /// example when working with the WebGlRenderingContext APIs. + /// + /// Here we implement a whitelist for those cases. This whitelist is currently + /// maintained by hand. + /// + /// When adding to this whitelist add tests to crates/web-sys/tests/wasm/whitelisted_immutable_slices.rs + fn maybe_adjust<'a>(&self, mut idl_type: IdlType<'a>, id: &'a OperationId) -> IdlType<'a> { + let op = match id { + OperationId::Operation(Some(op)) => op, + _ => return idl_type + }; + + if self.immutable_f32_whitelist.contains(op) { + flag_slices_immutable(&mut idl_type) + } + + // TODO: Add other whitelisted slices here, such as F64 or u8.. + + idl_type + } + + } /// Search for an attribute by name in some webidl object's attributes. @@ -707,3 +738,22 @@ pub fn public() -> syn::Visibility { pub_token: Default::default(), }) } + +fn flag_slices_immutable(ty: &mut IdlType) { + match ty { + IdlType::Float32Array { immutable } => *immutable = true, + IdlType::Nullable(item) => flag_slices_immutable(item), + IdlType::FrozenArray(item) => flag_slices_immutable(item), + IdlType::Sequence(item) => flag_slices_immutable(item), + IdlType::Promise(item) => flag_slices_immutable(item), + IdlType::Record(item1, item2) => { + flag_slices_immutable(item1); + flag_slices_immutable(item2); + }, + IdlType::Union(list) => { + for item in list { flag_slices_immutable(item); } + } + // catch-all for everything else like Object + _ => {} + } +} diff --git a/tests/headless.rs b/tests/headless.rs old mode 100644 new mode 100755 index 2fcf66ce9e4..ded767828fd --- a/tests/headless.rs +++ b/tests/headless.rs @@ -26,3 +26,14 @@ impl ConsumeRetString { fn works() { ConsumeRetString.consume(); } + +#[wasm_bindgen] +extern { + #[wasm_bindgen(js_namespace = console)] + pub fn log(s: &str); +} + +#[wasm_bindgen_test] +fn can_log_html_strings() { + log(""); +}