Description
Describe the Bug
The definitions for WebIDL dictionaries contain information if fields are optional or required by prefixing them with required
or marking the type ?
. However, there's a third option: fields can be neither required
nor ?
, but have a default value after =
.
Currently, code generation for constructor bindings does not set default values in the body of the new
function. Therefore, creating a dictionary with new()
and immediately reading a field that should have a default value is undefined behavior.
Steps to Reproduce
E.g. for the first dictionary declaration I could find going alphabetically in the enabled WebIDLs that uses default values:
wasm-bindgen/crates/web-sys/webidls/enabled/AnalyserNode.webidl
Lines 13 to 18 in e78db23
use web_sys::{AnalyserOptions, AnalyserOptionsGetters as _};
let analyzer_options = AnalyserOptions::new();
let fft_size = analyzer_options.fft_size(); // Uncaught Error: expected a number argument, found undefined
println!("{}", fft_size);
This example is using the getters as implemented in #3933, but the same case can be constructed by many Web APIs that take a dictionary with properties containing default values as argument.
Expected Behavior
2048
Actual Behavior
imported JS function that was not marked as `catch` threw an error: expected a number argument, found undefined
Additional Context
The faulty generated code for AnalyserOptions::new
that does not set default values:
wasm-bindgen/crates/web-sys/src/features/gen_AnalyserOptions.rs
Lines 30 to 38 in e78db23
I discovered this by working on WebIDL dictionary getters in #3933 and thinking about the implications of unsetting dictionary values in #3921 (comment).
Not allowing to safely read properties that are known to exist on a dictionary would require using Option
in return values of property getters and require to be unnecessarily defensive when reading them.