Fix codegen of consuming setters/getters (#2172)

Make sure they reset their internal pointer to null after we call Rust
since it invalidates the Rust pointer after being called!

Closes #2168
This commit is contained in:
Alex Crichton 2020-05-29 15:28:52 -05:00 committed by GitHub
parent b5e377da78
commit cc36bdc00d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 60 additions and 10 deletions

View File

@ -2190,10 +2190,9 @@ impl<'a> Context<'a> {
AuxExportKind::Function(_) => {}
AuxExportKind::StaticFunction { .. } => {}
AuxExportKind::Constructor(class) => builder.constructor(class),
AuxExportKind::Getter { .. } | AuxExportKind::Setter { .. } => {
builder.method(false)
}
AuxExportKind::Method { consumed, .. } => builder.method(*consumed),
AuxExportKind::Getter { consumed, .. }
| AuxExportKind::Setter { consumed, .. }
| AuxExportKind::Method { consumed, .. } => builder.method(*consumed),
}
}
Kind::Import(_) => {}
@ -2257,7 +2256,7 @@ impl<'a> Context<'a> {
exported.has_constructor = true;
exported.push(&docs, "constructor", "", &code, ts_sig);
}
AuxExportKind::Getter { class, field } => {
AuxExportKind::Getter { class, field, .. } => {
let ret_ty = match export.generate_typescript {
true => match &ts_ret_ty {
Some(s) => Some(s.as_str()),
@ -2268,7 +2267,7 @@ impl<'a> Context<'a> {
let exported = require_class(&mut self.exported_classes, class);
exported.push_getter(&docs, field, &code, ret_ty);
}
AuxExportKind::Setter { class, field } => {
AuxExportKind::Setter { class, field, .. } => {
let arg_ty = match export.generate_typescript {
true => Some(ts_arg_tys[0].as_str()),
false => None,
@ -3247,20 +3246,24 @@ fn check_duplicated_getter_and_setter_names(
AuxExportKind::Getter {
class: first_class,
field: first_field,
consumed: _,
},
AuxExportKind::Getter {
class: second_class,
field: second_field,
consumed: _,
},
) => verify_exports(first_class, first_field, second_class, second_field)?,
(
AuxExportKind::Setter {
class: first_class,
field: first_field,
consumed: _,
},
AuxExportKind::Setter {
class: second_class,
field: second_field,
consumed: _,
},
) => verify_exports(first_class, first_field, second_class, second_field)?,
_ => {}

View File

@ -419,6 +419,7 @@ impl<'a> Context<'a> {
AuxExportKind::Getter {
class,
field: f.to_string(),
consumed: export.consumed,
}
}
decode::OperationKind::Setter(f) => {
@ -426,6 +427,7 @@ impl<'a> Context<'a> {
AuxExportKind::Setter {
class,
field: f.to_string(),
consumed: export.consumed,
}
}
_ if op.is_static => AuxExportKind::StaticFunction {
@ -806,6 +808,7 @@ impl<'a> Context<'a> {
kind: AuxExportKind::Getter {
class: struct_.name.to_string(),
field: field.name.to_string(),
consumed: false,
},
generate_typescript: field.generate_typescript,
},
@ -832,6 +835,7 @@ impl<'a> Context<'a> {
kind: AuxExportKind::Setter {
class: struct_.name.to_string(),
field: field.name.to_string(),
consumed: false,
},
generate_typescript: field.generate_typescript,
},

View File

@ -105,12 +105,22 @@ pub enum AuxExportKind {
/// This function is intended to be a getter for a field on a class. The
/// first argument is the internal pointer and the returned value is
/// expected to be the field.
Getter { class: String, field: String },
Getter {
class: String,
field: String,
// same as `consumed` in `Method`
consumed: bool,
},
/// This function is intended to be a setter for a field on a class. The
/// first argument is the internal pointer and the second argument is
/// expected to be the field's new value.
Setter { class: String, field: String },
Setter {
class: String,
field: String,
// same as `consumed` in `Method`
consumed: bool,
},
/// This is a free function (ish) but scoped inside of a class name.
StaticFunction { class: String, name: String },

View File

@ -369,7 +369,7 @@ fn check_standard_export(export: &AuxExport) -> Result<(), Error> {
name,
);
}
AuxExportKind::Getter { class, field } => {
AuxExportKind::Getter { class, field, .. } => {
bail!(
"cannot export `{}::{}` getter function when generating \
a standalone WebAssembly module with no JS glue",
@ -377,7 +377,7 @@ fn check_standard_export(export: &AuxExport) -> Result<(), Error> {
field,
);
}
AuxExportKind::Setter { class, field } => {
AuxExportKind::Setter { class, field, .. } => {
bail!(
"cannot export `{}::{}` setter function when generating \
a standalone WebAssembly module with no JS glue",

View File

@ -4,3 +4,21 @@ use wasm_bindgen::prelude::*;
pub fn add(a: u32, b: u32) -> u32 {
a + b
}
#[wasm_bindgen]
#[derive(Copy, Clone)]
pub struct Answer(u32);
#[wasm_bindgen]
impl Answer {
pub fn new() -> Answer {
Answer(41)
}
#[wasm_bindgen(getter)]
pub fn the_answer(self) -> u32 {
self.0 + 1
}
pub fn foo(self) -> u32 {
self.0 + 1
}
}

View File

@ -33,4 +33,11 @@ exports.js_works = () => {
useMoved();
moveMoved();
methodMoved();
const a = new wasm.Fruit('a');
a.prop;
assertMovedPtrThrows(() => a.prop);
const b = new wasm.Fruit('a');
b.prop = 3;
assertMovedPtrThrows(() => { b.prop = 4; });
};

View File

@ -25,6 +25,14 @@ impl Fruit {
pub fn rot(self) {
drop(self);
}
#[wasm_bindgen(getter)]
pub fn prop(self) -> u32 {
0
}
#[wasm_bindgen(setter)]
pub fn set_prop(self, _val: u32) {}
}
#[wasm_bindgen]