mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-26 06:22:14 +00:00
Result-ify src/parser.rs
(#608)
* Make ConvertToAst trait fallible It's got some panics, and we'll be switching those to errors! * First example of a diagnostic-driven error Add a diagnostic-driven error `#[wasm_bindgen]` being attached to public functions, and add some macros to boot to make it easier to generate errors! * Result-ify `src/parser.rs` This commit converts all of `src/parser.rs` away from panics to using `Diagnostic` instead. Along the way this adds a test case per changed `panic!`, ensuring that we don't regress in these areas!
This commit is contained in:
parent
d90802a40c
commit
bdec2582aa
@ -1,6 +1,20 @@
|
|||||||
use proc_macro2::*;
|
use proc_macro2::*;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! err_span {
|
||||||
|
($span:expr, $($msg:tt)*) => (
|
||||||
|
::backend::Diagnostic::span_error(&$span, format!($($msg)*))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! bail_span {
|
||||||
|
($($t:tt)*) => (
|
||||||
|
return Err(err_span!($($t)*).into())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Diagnostic {
|
pub struct Diagnostic {
|
||||||
inner: Repr,
|
inner: Repr,
|
||||||
}
|
}
|
||||||
|
1
crates/macro-support/src/lib.rs
Executable file → Normal file
1
crates/macro-support/src/lib.rs
Executable file → Normal file
@ -7,6 +7,7 @@ extern crate proc_macro2;
|
|||||||
extern crate quote;
|
extern crate quote;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate syn;
|
extern crate syn;
|
||||||
|
#[macro_use]
|
||||||
extern crate wasm_bindgen_backend as backend;
|
extern crate wasm_bindgen_backend as backend;
|
||||||
extern crate wasm_bindgen_shared as shared;
|
extern crate wasm_bindgen_shared as shared;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use backend::ast;
|
use backend::ast;
|
||||||
use backend::Diagnostic;
|
use backend::Diagnostic;
|
||||||
use backend::util::{ident_ty, ShortHash};
|
use backend::util::{ident_ty, ShortHash};
|
||||||
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
use proc_macro2::{Ident, Span, TokenStream, TokenTree, Delimiter};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use shared;
|
use shared;
|
||||||
use syn;
|
use syn;
|
||||||
@ -16,7 +16,7 @@ pub struct BindgenAttrs {
|
|||||||
|
|
||||||
impl BindgenAttrs {
|
impl BindgenAttrs {
|
||||||
/// Find and parse the wasm_bindgen attributes.
|
/// Find and parse the wasm_bindgen attributes.
|
||||||
fn find(attrs: &mut Vec<syn::Attribute>) -> BindgenAttrs {
|
fn find(attrs: &mut Vec<syn::Attribute>) -> Result<BindgenAttrs, Diagnostic> {
|
||||||
let pos = attrs
|
let pos = attrs
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@ -24,18 +24,22 @@ impl BindgenAttrs {
|
|||||||
.map(|a| a.0);
|
.map(|a| a.0);
|
||||||
let pos = match pos {
|
let pos = match pos {
|
||||||
Some(i) => i,
|
Some(i) => i,
|
||||||
None => return BindgenAttrs::default(),
|
None => return Ok(BindgenAttrs::default()),
|
||||||
};
|
};
|
||||||
let mut tts = attrs.remove(pos).tts.into_iter();
|
let attr = attrs.remove(pos);
|
||||||
let tt = match tts.next() {
|
let mut tts = attr.tts.clone().into_iter();
|
||||||
Some(TokenTree::Group(d)) => d.stream(),
|
let group = match tts.next() {
|
||||||
Some(_) => panic!("malformed #[wasm_bindgen] attribute"),
|
Some(TokenTree::Group(d)) => d,
|
||||||
None => return BindgenAttrs::default(),
|
Some(_) => bail_span!(attr, "malformed #[wasm_bindgen] attribute"),
|
||||||
|
None => return Ok(BindgenAttrs::default()),
|
||||||
};
|
};
|
||||||
if tts.next().is_some() {
|
if tts.next().is_some() {
|
||||||
panic!("malformed #[wasm_bindgen] attribute");
|
bail_span!(attr, "malformed #[wasm_bindgen] attribute");
|
||||||
}
|
}
|
||||||
syn::parse(tt.into()).expect("malformed #[wasm_bindgen] attribute")
|
if group.delimiter() != Delimiter::Parenthesis {
|
||||||
|
bail_span!(attr, "malformed #[wasm_bindgen] attribute");
|
||||||
|
}
|
||||||
|
super::syn_parse(group.stream(), "#[wasm_bindgen] attribute options")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the first module attribute
|
/// Get the first module attribute
|
||||||
@ -304,15 +308,16 @@ trait ConvertToAst<Ctx> {
|
|||||||
/// Convert into our target.
|
/// Convert into our target.
|
||||||
///
|
///
|
||||||
/// Since this is used in a procedural macro, use panic to fail.
|
/// Since this is used in a procedural macro, use panic to fail.
|
||||||
fn convert(self, context: Ctx) -> Self::Target;
|
fn convert(self, context: Ctx) -> Result<Self::Target, Diagnostic>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ConvertToAst<()> for &'a mut syn::ItemStruct {
|
impl<'a> ConvertToAst<()> for &'a mut syn::ItemStruct {
|
||||||
type Target = ast::Struct;
|
type Target = ast::Struct;
|
||||||
|
|
||||||
fn convert(self, (): ()) -> Self::Target {
|
fn convert(self, (): ()) -> Result<Self::Target, Diagnostic> {
|
||||||
if self.generics.params.len() > 0 {
|
if self.generics.params.len() > 0 {
|
||||||
panic!(
|
bail_span!(
|
||||||
|
self.generics,
|
||||||
"structs with #[wasm_bindgen] cannot have lifetime or \
|
"structs with #[wasm_bindgen] cannot have lifetime or \
|
||||||
type parameters currently"
|
type parameters currently"
|
||||||
);
|
);
|
||||||
@ -332,7 +337,7 @@ impl<'a> ConvertToAst<()> for &'a mut syn::ItemStruct {
|
|||||||
let name_str = name.to_string();
|
let name_str = name.to_string();
|
||||||
let getter = shared::struct_field_get(&ident, &name_str);
|
let getter = shared::struct_field_get(&ident, &name_str);
|
||||||
let setter = shared::struct_field_set(&ident, &name_str);
|
let setter = shared::struct_field_set(&ident, &name_str);
|
||||||
let opts = BindgenAttrs::find(&mut field.attrs);
|
let opts = BindgenAttrs::find(&mut field.attrs)?;
|
||||||
let comments = extract_doc_comments(&field.attrs);
|
let comments = extract_doc_comments(&field.attrs);
|
||||||
fields.push(ast::StructField {
|
fields.push(ast::StructField {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
@ -346,20 +351,28 @@ impl<'a> ConvertToAst<()> for &'a mut syn::ItemStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let comments: Vec<String> = extract_doc_comments(&self.attrs);
|
let comments: Vec<String> = extract_doc_comments(&self.attrs);
|
||||||
ast::Struct {
|
Ok(ast::Struct {
|
||||||
name: self.ident.clone(),
|
name: self.ident.clone(),
|
||||||
fields,
|
fields,
|
||||||
comments,
|
comments,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn {
|
impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn {
|
||||||
type Target = ast::ImportKind;
|
type Target = ast::ImportKind;
|
||||||
|
|
||||||
fn convert(self, (opts, module): (BindgenAttrs, &'a Option<String>)) -> Self::Target {
|
fn convert(self, (opts, module): (BindgenAttrs, &'a Option<String>))
|
||||||
|
-> Result<Self::Target, Diagnostic>
|
||||||
|
{
|
||||||
let js_name = opts.js_name().unwrap_or(&self.ident).clone();
|
let js_name = opts.js_name().unwrap_or(&self.ident).clone();
|
||||||
let wasm = function_from_decl(&js_name, self.decl, self.attrs, self.vis, false).0;
|
let wasm = function_from_decl(
|
||||||
|
&js_name,
|
||||||
|
self.decl.clone(),
|
||||||
|
self.attrs.clone(),
|
||||||
|
self.vis.clone(),
|
||||||
|
false,
|
||||||
|
)?.0;
|
||||||
let catch = opts.catch();
|
let catch = opts.catch();
|
||||||
let js_ret = if catch {
|
let js_ret = if catch {
|
||||||
// TODO: this assumes a whole bunch:
|
// TODO: this assumes a whole bunch:
|
||||||
@ -369,8 +382,7 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
|||||||
// * The actual type is the first type parameter
|
// * The actual type is the first type parameter
|
||||||
//
|
//
|
||||||
// should probably fix this one day...
|
// should probably fix this one day...
|
||||||
extract_first_ty_param(wasm.ret.as_ref())
|
extract_first_ty_param(wasm.ret.as_ref())?
|
||||||
.expect("can't `catch` without returning a Result")
|
|
||||||
} else {
|
} else {
|
||||||
wasm.ret.clone()
|
wasm.ret.clone()
|
||||||
};
|
};
|
||||||
@ -387,24 +399,27 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
|||||||
let class = wasm
|
let class = wasm
|
||||||
.arguments
|
.arguments
|
||||||
.get(0)
|
.get(0)
|
||||||
.expect("methods must have at least one argument");
|
.ok_or_else(|| {
|
||||||
|
err_span!(self, "imported methods must have at least one argument")
|
||||||
|
})?;
|
||||||
let class = match class.ty {
|
let class = match class.ty {
|
||||||
syn::Type::Reference(syn::TypeReference {
|
syn::Type::Reference(syn::TypeReference {
|
||||||
mutability: None,
|
mutability: None,
|
||||||
ref elem,
|
ref elem,
|
||||||
..
|
..
|
||||||
}) => &**elem,
|
}) => &**elem,
|
||||||
_ => panic!("first argument of method must be a shared reference"),
|
_ => {
|
||||||
|
bail_span!(class.ty, "first argument of method must be a shared reference")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let class_name = match *class {
|
let class_name = match *class {
|
||||||
syn::Type::Path(syn::TypePath {
|
syn::Type::Path(syn::TypePath {
|
||||||
qself: None,
|
qself: None,
|
||||||
ref path,
|
ref path,
|
||||||
}) => path,
|
}) => path,
|
||||||
_ => panic!("first argument of method must be a path"),
|
_ => bail_span!(class, "first argument of method must be a path"),
|
||||||
};
|
};
|
||||||
let class_name = extract_path_ident(class_name)
|
let class_name = extract_path_ident(class_name)?;
|
||||||
.expect("first argument of method must be a bare type");
|
|
||||||
let class_name = opts
|
let class_name = opts
|
||||||
.js_class()
|
.js_class()
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
@ -433,17 +448,16 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
|||||||
} else if opts.constructor() {
|
} else if opts.constructor() {
|
||||||
let class = match wasm.ret {
|
let class = match wasm.ret {
|
||||||
Some(ref ty) => ty,
|
Some(ref ty) => ty,
|
||||||
_ => panic!("constructor returns must be bare types"),
|
_ => bail_span!(self, "constructor returns must be bare types"),
|
||||||
};
|
};
|
||||||
let class_name = match *class {
|
let class_name = match *class {
|
||||||
syn::Type::Path(syn::TypePath {
|
syn::Type::Path(syn::TypePath {
|
||||||
qself: None,
|
qself: None,
|
||||||
ref path,
|
ref path,
|
||||||
}) => path,
|
}) => path,
|
||||||
_ => panic!("first argument of method must be a path"),
|
_ => bail_span!(self, "return value of constructor must be a bare path"),
|
||||||
};
|
};
|
||||||
let class_name = extract_path_ident(class_name)
|
let class_name = extract_path_ident(class_name)?;
|
||||||
.expect("first argument of method must be a bare type");
|
|
||||||
|
|
||||||
ast::ImportFunctionKind::Method {
|
ast::ImportFunctionKind::Method {
|
||||||
class: class_name.to_string(),
|
class: class_name.to_string(),
|
||||||
@ -462,7 +476,7 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
|||||||
let data = (ns, &self.ident, module);
|
let data = (ns, &self.ident, module);
|
||||||
format!("__wbg_{}_{}", js_name, ShortHash(data))
|
format!("__wbg_{}_{}", js_name, ShortHash(data))
|
||||||
};
|
};
|
||||||
ast::ImportKind::Function(ast::ImportFunction {
|
Ok(ast::ImportKind::Function(ast::ImportFunction {
|
||||||
function: wasm,
|
function: wasm,
|
||||||
kind,
|
kind,
|
||||||
js_ret,
|
js_ret,
|
||||||
@ -471,59 +485,59 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
|||||||
rust_name: self.ident.clone(),
|
rust_name: self.ident.clone(),
|
||||||
shim: Ident::new(&shim, Span::call_site()),
|
shim: Ident::new(&shim, Span::call_site()),
|
||||||
doc_comment: None,
|
doc_comment: None,
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConvertToAst<()> for syn::ForeignItemType {
|
impl ConvertToAst<()> for syn::ForeignItemType {
|
||||||
type Target = ast::ImportKind;
|
type Target = ast::ImportKind;
|
||||||
|
|
||||||
fn convert(self, (): ()) -> Self::Target {
|
fn convert(self, (): ()) -> Result<Self::Target, Diagnostic> {
|
||||||
ast::ImportKind::Type(ast::ImportType {
|
Ok(ast::ImportKind::Type(ast::ImportType {
|
||||||
vis: self.vis,
|
vis: self.vis,
|
||||||
name: self.ident,
|
name: self.ident,
|
||||||
attrs: self.attrs,
|
attrs: self.attrs,
|
||||||
doc_comment: None,
|
doc_comment: None,
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConvertToAst<BindgenAttrs> for syn::ForeignItemStatic {
|
impl ConvertToAst<BindgenAttrs> for syn::ForeignItemStatic {
|
||||||
type Target = ast::ImportKind;
|
type Target = ast::ImportKind;
|
||||||
|
|
||||||
fn convert(self, opts: BindgenAttrs) -> Self::Target {
|
fn convert(self, opts: BindgenAttrs) -> Result<Self::Target, Diagnostic> {
|
||||||
if self.mutability.is_some() {
|
if self.mutability.is_some() {
|
||||||
panic!("cannot import mutable globals yet")
|
bail_span!(self.mutability, "cannot import mutable globals yet")
|
||||||
}
|
}
|
||||||
let js_name = opts.js_name().unwrap_or(&self.ident);
|
let js_name = opts.js_name().unwrap_or(&self.ident);
|
||||||
let shim = format!("__wbg_static_accessor_{}_{}", js_name, self.ident);
|
let shim = format!("__wbg_static_accessor_{}_{}", js_name, self.ident);
|
||||||
ast::ImportKind::Static(ast::ImportStatic {
|
Ok(ast::ImportKind::Static(ast::ImportStatic {
|
||||||
ty: *self.ty,
|
ty: *self.ty,
|
||||||
vis: self.vis,
|
vis: self.vis,
|
||||||
rust_name: self.ident.clone(),
|
rust_name: self.ident.clone(),
|
||||||
js_name: js_name.clone(),
|
js_name: js_name.clone(),
|
||||||
shim: Ident::new(&shim, Span::call_site()),
|
shim: Ident::new(&shim, Span::call_site()),
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConvertToAst<BindgenAttrs> for syn::ItemFn {
|
impl ConvertToAst<BindgenAttrs> for syn::ItemFn {
|
||||||
type Target = ast::Function;
|
type Target = ast::Function;
|
||||||
|
|
||||||
fn convert(self, attrs: BindgenAttrs) -> Self::Target {
|
fn convert(self, attrs: BindgenAttrs) -> Result<Self::Target, Diagnostic> {
|
||||||
match self.vis {
|
match self.vis {
|
||||||
syn::Visibility::Public(_) => {}
|
syn::Visibility::Public(_) => {}
|
||||||
_ => panic!("can only bindgen public functions"),
|
_ => bail_span!(self, "can only #[wasm_bindgen] public functions"),
|
||||||
}
|
}
|
||||||
if self.constness.is_some() {
|
if self.constness.is_some() {
|
||||||
panic!("can only bindgen non-const functions");
|
bail_span!(self.constness, "can only #[wasm_bindgen] non-const functions");
|
||||||
}
|
}
|
||||||
if self.unsafety.is_some() {
|
if self.unsafety.is_some() {
|
||||||
panic!("can only bindgen safe functions");
|
bail_span!(self.unsafety, "can only #[wasm_bindgen] safe functions");
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = attrs.js_name().unwrap_or(&self.ident);
|
let name = attrs.js_name().unwrap_or(&self.ident);
|
||||||
function_from_decl(name, self.decl, self.attrs, self.vis, false).0
|
Ok(function_from_decl(name, self.decl, self.attrs, self.vis, false)?.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,15 +548,18 @@ fn function_from_decl(
|
|||||||
attrs: Vec<syn::Attribute>,
|
attrs: Vec<syn::Attribute>,
|
||||||
vis: syn::Visibility,
|
vis: syn::Visibility,
|
||||||
allow_self: bool,
|
allow_self: bool,
|
||||||
) -> (ast::Function, Option<ast::MethodSelf>) {
|
) -> Result<(ast::Function, Option<ast::MethodSelf>), Diagnostic> {
|
||||||
if decl.variadic.is_some() {
|
if decl.variadic.is_some() {
|
||||||
panic!("can't bindgen variadic functions")
|
bail_span!(decl.variadic, "can't #[wasm_bindgen] variadic functions");
|
||||||
}
|
}
|
||||||
if decl.generics.params.len() > 0 {
|
if decl.generics.params.len() > 0 {
|
||||||
panic!("can't bindgen functions with lifetime or type parameters")
|
bail_span!(
|
||||||
|
decl.generics,
|
||||||
|
"can't #[wasm_bindgen] functions with lifetime or type parameters",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_no_lifetimes(&mut decl);
|
assert_no_lifetimes(&mut decl)?;
|
||||||
|
|
||||||
let syn::FnDecl { inputs, output, .. } = { *decl };
|
let syn::FnDecl { inputs, output, .. } = { *decl };
|
||||||
|
|
||||||
@ -574,7 +591,7 @@ fn function_from_decl(
|
|||||||
syn::ReturnType::Type(_, ty) => Some(*ty),
|
syn::ReturnType::Type(_, ty) => Some(*ty),
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
Ok((
|
||||||
ast::Function {
|
ast::Function {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
arguments,
|
arguments,
|
||||||
@ -583,7 +600,7 @@ fn function_from_decl(
|
|||||||
rust_attrs: attrs,
|
rust_attrs: attrs,
|
||||||
},
|
},
|
||||||
method_self,
|
method_self,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait MacroParse<Ctx> {
|
pub(crate) trait MacroParse<Ctx> {
|
||||||
@ -623,11 +640,11 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
|
|||||||
constructor: None,
|
constructor: None,
|
||||||
comments,
|
comments,
|
||||||
rust_name: f.ident.clone(),
|
rust_name: f.ident.clone(),
|
||||||
function: f.convert(opts.unwrap_or_default()),
|
function: f.convert(opts.unwrap_or_default())?,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
syn::Item::Struct(mut s) => {
|
syn::Item::Struct(mut s) => {
|
||||||
program.structs.push((&mut s).convert(()));
|
program.structs.push((&mut s).convert(())?);
|
||||||
s.to_tokens(tokens);
|
s.to_tokens(tokens);
|
||||||
}
|
}
|
||||||
syn::Item::Impl(mut i) => {
|
syn::Item::Impl(mut i) => {
|
||||||
@ -635,17 +652,23 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
|
|||||||
i.to_tokens(tokens);
|
i.to_tokens(tokens);
|
||||||
}
|
}
|
||||||
syn::Item::ForeignMod(mut f) => {
|
syn::Item::ForeignMod(mut f) => {
|
||||||
let opts = opts.unwrap_or_else(|| BindgenAttrs::find(&mut f.attrs));
|
let opts = match opts {
|
||||||
|
Some(opts) => opts,
|
||||||
|
None => BindgenAttrs::find(&mut f.attrs)?,
|
||||||
|
};
|
||||||
f.macro_parse(program, opts)?;
|
f.macro_parse(program, opts)?;
|
||||||
}
|
}
|
||||||
syn::Item::Enum(e) => {
|
syn::Item::Enum(e) => {
|
||||||
e.to_tokens(tokens);
|
e.to_tokens(tokens);
|
||||||
e.macro_parse(program, ())?;
|
e.macro_parse(program, ())?;
|
||||||
}
|
}
|
||||||
_ => panic!(
|
_ => {
|
||||||
"#[wasm_bindgen] can only be applied to a function, \
|
bail_span!(
|
||||||
struct, enum, impl, or extern block"
|
self,
|
||||||
),
|
"#[wasm_bindgen] can only be applied to a function, \
|
||||||
|
struct, enum, impl, or extern block"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -657,26 +680,23 @@ impl<'a> MacroParse<()> for &'a mut syn::ItemImpl {
|
|||||||
-> Result<(), Diagnostic>
|
-> Result<(), Diagnostic>
|
||||||
{
|
{
|
||||||
if self.defaultness.is_some() {
|
if self.defaultness.is_some() {
|
||||||
panic!("default impls are not supported");
|
bail_span!(self.defaultness, "#[wasm_bindgen] default impls are not supported");
|
||||||
}
|
}
|
||||||
if self.unsafety.is_some() {
|
if self.unsafety.is_some() {
|
||||||
panic!("unsafe impls are not supported");
|
bail_span!(self.unsafety, "#[wasm_bindgen] unsafe impls are not supported");
|
||||||
}
|
}
|
||||||
if self.trait_.is_some() {
|
if let Some((_, path, _)) = &self.trait_ {
|
||||||
panic!("trait impls are not supported");
|
bail_span!(path, "#[wasm_bindgen] trait impls are not supported");
|
||||||
}
|
}
|
||||||
if self.generics.params.len() > 0 {
|
if self.generics.params.len() > 0 {
|
||||||
panic!("generic impls aren't supported");
|
bail_span!(self.generics, "#[wasm_bindgen] generic impls aren't supported");
|
||||||
}
|
}
|
||||||
let name = match *self.self_ty {
|
let name = match *self.self_ty {
|
||||||
syn::Type::Path(syn::TypePath {
|
syn::Type::Path(syn::TypePath {
|
||||||
qself: None,
|
qself: None,
|
||||||
ref path,
|
ref path,
|
||||||
}) => match extract_path_ident(path) {
|
}) => extract_path_ident(path)?,
|
||||||
Some(ident) => ident,
|
_ => bail_span!(self.self_ty, "unsupported self type in #[wasm_bindgen] impl"),
|
||||||
None => panic!("unsupported self type in impl"),
|
|
||||||
},
|
|
||||||
_ => panic!("unsupported self type in impl"),
|
|
||||||
};
|
};
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
for item in self.items.iter_mut() {
|
for item in self.items.iter_mut() {
|
||||||
@ -695,10 +715,16 @@ impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) {
|
|||||||
let (class, item) = self;
|
let (class, item) = self;
|
||||||
replace_self(class, item);
|
replace_self(class, item);
|
||||||
let method = match item {
|
let method = match item {
|
||||||
syn::ImplItem::Const(_) => panic!("const definitions aren't supported"),
|
|
||||||
syn::ImplItem::Type(_) => panic!("type definitions in impls aren't supported"),
|
|
||||||
syn::ImplItem::Method(ref mut m) => m,
|
syn::ImplItem::Method(ref mut m) => m,
|
||||||
syn::ImplItem::Macro(_) => panic!("macros in impls aren't supported"),
|
syn::ImplItem::Const(_) => {
|
||||||
|
bail_span!(&*item, "const definitions aren't supported with #[wasm_bindgen]");
|
||||||
|
}
|
||||||
|
syn::ImplItem::Type(_) => {
|
||||||
|
bail_span!(&*item, "type definitions in impls aren't supported with #[wasm_bindgen]")
|
||||||
|
}
|
||||||
|
syn::ImplItem::Macro(_) => {
|
||||||
|
bail_span!(&*item, "macros in impls aren't supported");
|
||||||
|
}
|
||||||
syn::ImplItem::Verbatim(_) => panic!("unparsed impl item?"),
|
syn::ImplItem::Verbatim(_) => panic!("unparsed impl item?"),
|
||||||
};
|
};
|
||||||
match method.vis {
|
match method.vis {
|
||||||
@ -709,13 +735,19 @@ impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) {
|
|||||||
panic!("default methods are not supported");
|
panic!("default methods are not supported");
|
||||||
}
|
}
|
||||||
if method.sig.constness.is_some() {
|
if method.sig.constness.is_some() {
|
||||||
panic!("can only bindgen non-const functions");
|
bail_span!(
|
||||||
|
method.sig.constness,
|
||||||
|
"can only #[wasm_bindgen] non-const functions",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if method.sig.unsafety.is_some() {
|
if method.sig.unsafety.is_some() {
|
||||||
panic!("can only bindgen safe functions");
|
bail_span!(
|
||||||
|
method.sig.unsafety,
|
||||||
|
"can only bindgen safe functions",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let opts = BindgenAttrs::find(&mut method.attrs);
|
let opts = BindgenAttrs::find(&mut method.attrs)?;
|
||||||
let comments = extract_doc_comments(&method.attrs);
|
let comments = extract_doc_comments(&method.attrs);
|
||||||
let is_constructor = opts.constructor();
|
let is_constructor = opts.constructor();
|
||||||
let constructor = if is_constructor {
|
let constructor = if is_constructor {
|
||||||
@ -730,7 +762,7 @@ impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) {
|
|||||||
method.attrs.clone(),
|
method.attrs.clone(),
|
||||||
method.vis.clone(),
|
method.vis.clone(),
|
||||||
true,
|
true,
|
||||||
);
|
)?;
|
||||||
|
|
||||||
program.exports.push(ast::Export {
|
program.exports.push(ast::Export {
|
||||||
class: Some(class.clone()),
|
class: Some(class.clone()),
|
||||||
@ -750,7 +782,7 @@ impl MacroParse<()> for syn::ItemEnum {
|
|||||||
{
|
{
|
||||||
match self.vis {
|
match self.vis {
|
||||||
syn::Visibility::Public(_) => {}
|
syn::Visibility::Public(_) => {}
|
||||||
_ => panic!("only public enums are allowed"),
|
_ => bail_span!(self, "only public enums are allowed with #[wasm_bindgen]"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let variants = self
|
let variants = self
|
||||||
@ -760,7 +792,7 @@ impl MacroParse<()> for syn::ItemEnum {
|
|||||||
.map(|(i, v)| {
|
.map(|(i, v)| {
|
||||||
match v.fields {
|
match v.fields {
|
||||||
syn::Fields::Unit => (),
|
syn::Fields::Unit => (),
|
||||||
_ => panic!("Only C-Style enums allowed"),
|
_ => bail_span!(v.fields, "only C-Style enums allowed with #[wasm_bindgen]"),
|
||||||
}
|
}
|
||||||
let value = match v.discriminant {
|
let value = match v.discriminant {
|
||||||
Some((
|
Some((
|
||||||
@ -771,20 +803,30 @@ impl MacroParse<()> for syn::ItemEnum {
|
|||||||
}),
|
}),
|
||||||
)) => {
|
)) => {
|
||||||
if int_lit.value() > <u32>::max_value() as u64 {
|
if int_lit.value() > <u32>::max_value() as u64 {
|
||||||
panic!("Enums can only support numbers that can be represented as u32");
|
bail_span!(
|
||||||
|
int_lit,
|
||||||
|
"enums with #[wasm_bindgen] can only support \
|
||||||
|
numbers that can be represented as u32"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
int_lit.value() as u32
|
int_lit.value() as u32
|
||||||
}
|
}
|
||||||
None => i as u32,
|
None => i as u32,
|
||||||
_ => panic!("Enums may only have number literal values"),
|
Some((_, ref expr)) => {
|
||||||
|
bail_span!(
|
||||||
|
expr,
|
||||||
|
"enums with #[wasm_bidngen] may only have \
|
||||||
|
number literal values",
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ast::Variant {
|
Ok(ast::Variant {
|
||||||
name: v.ident.clone(),
|
name: v.ident.clone(),
|
||||||
value,
|
value,
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect::<Result<_, Diagnostic>>()?;
|
||||||
let comments = extract_doc_comments(&self.attrs);
|
let comments = extract_doc_comments(&self.attrs);
|
||||||
program.enums.push(ast::Enum {
|
program.enums.push(ast::Enum {
|
||||||
name: self.ident,
|
name: self.ident,
|
||||||
@ -799,47 +841,62 @@ impl MacroParse<BindgenAttrs> for syn::ItemForeignMod {
|
|||||||
fn macro_parse(self, program: &mut ast::Program, opts: BindgenAttrs)
|
fn macro_parse(self, program: &mut ast::Program, opts: BindgenAttrs)
|
||||||
-> Result<(), Diagnostic>
|
-> Result<(), Diagnostic>
|
||||||
{
|
{
|
||||||
|
let mut errors = Vec::new();
|
||||||
match self.abi.name {
|
match self.abi.name {
|
||||||
Some(ref l) if l.value() == "C" => {}
|
Some(ref l) if l.value() == "C" => {}
|
||||||
None => {}
|
None => {}
|
||||||
_ => panic!("only foreign mods with the `C` ABI are allowed"),
|
Some(ref other) => {
|
||||||
|
errors.push(err_span!(other, "only foreign mods with the `C` ABI are allowed"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for mut item in self.items.into_iter() {
|
for mut item in self.items.into_iter() {
|
||||||
let item_opts = {
|
if let Err(e) = item.macro_parse(program, &opts) {
|
||||||
let attrs = match item {
|
errors.push(e);
|
||||||
syn::ForeignItem::Fn(ref mut f) => &mut f.attrs,
|
}
|
||||||
syn::ForeignItem::Type(ref mut t) => &mut t.attrs,
|
}
|
||||||
syn::ForeignItem::Static(ref mut s) => &mut s.attrs,
|
Diagnostic::from_vec(errors)
|
||||||
_ => panic!("only foreign functions/types allowed for now"),
|
}
|
||||||
};
|
}
|
||||||
BindgenAttrs::find(attrs)
|
|
||||||
};
|
impl<'a> MacroParse<&'a BindgenAttrs> for syn::ForeignItem {
|
||||||
let module = item_opts.module().or(opts.module()).map(|s| s.to_string());
|
fn macro_parse(mut self, program: &mut ast::Program, opts: &'a BindgenAttrs)
|
||||||
let version = item_opts
|
-> Result<(), Diagnostic>
|
||||||
.version()
|
{
|
||||||
.or(opts.version())
|
let item_opts = {
|
||||||
.map(|s| s.to_string());
|
let attrs = match self {
|
||||||
let js_namespace = item_opts.js_namespace().or(opts.js_namespace()).cloned();
|
syn::ForeignItem::Fn(ref mut f) => &mut f.attrs,
|
||||||
let mut kind = match item {
|
syn::ForeignItem::Type(ref mut t) => &mut t.attrs,
|
||||||
syn::ForeignItem::Fn(f) => f.convert((item_opts, &module)),
|
syn::ForeignItem::Static(ref mut s) => &mut s.attrs,
|
||||||
syn::ForeignItem::Type(t) => t.convert(()),
|
|
||||||
syn::ForeignItem::Static(s) => s.convert(item_opts),
|
|
||||||
_ => panic!("only foreign functions/types allowed for now"),
|
_ => panic!("only foreign functions/types allowed for now"),
|
||||||
};
|
};
|
||||||
|
BindgenAttrs::find(attrs)?
|
||||||
|
};
|
||||||
|
let module = item_opts.module().or(opts.module()).map(|s| s.to_string());
|
||||||
|
let version = item_opts
|
||||||
|
.version()
|
||||||
|
.or(opts.version())
|
||||||
|
.map(|s| s.to_string());
|
||||||
|
let js_namespace = item_opts.js_namespace().or(opts.js_namespace()).cloned();
|
||||||
|
let kind = match self {
|
||||||
|
syn::ForeignItem::Fn(f) => f.convert((item_opts, &module))?,
|
||||||
|
syn::ForeignItem::Type(t) => t.convert(())?,
|
||||||
|
syn::ForeignItem::Static(s) => s.convert(item_opts)?,
|
||||||
|
_ => panic!("only foreign functions/types allowed for now"),
|
||||||
|
};
|
||||||
|
|
||||||
|
program.imports.push(ast::Import {
|
||||||
|
module,
|
||||||
|
version,
|
||||||
|
js_namespace,
|
||||||
|
kind,
|
||||||
|
});
|
||||||
|
|
||||||
program.imports.push(ast::Import {
|
|
||||||
module,
|
|
||||||
version,
|
|
||||||
js_namespace,
|
|
||||||
kind,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the first type parameter of a generic type, errors on incorrect input.
|
/// Get the first type parameter of a generic type, errors on incorrect input.
|
||||||
fn extract_first_ty_param(ty: Option<&syn::Type>) -> Result<Option<syn::Type>, ()> {
|
fn extract_first_ty_param(ty: Option<&syn::Type>) -> Result<Option<syn::Type>, Diagnostic> {
|
||||||
let t = match ty {
|
let t = match ty {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
@ -849,16 +906,21 @@ fn extract_first_ty_param(ty: Option<&syn::Type>) -> Result<Option<syn::Type>, (
|
|||||||
qself: None,
|
qself: None,
|
||||||
ref path,
|
ref path,
|
||||||
}) => path,
|
}) => path,
|
||||||
_ => return Err(()),
|
_ => bail_span!(t, "must be Result<...>"),
|
||||||
};
|
};
|
||||||
let seg = path.segments.last().ok_or(())?.into_value();
|
let seg = path.segments.last()
|
||||||
|
.ok_or_else(|| err_span!(t, "must have at least one segment"))?
|
||||||
|
.into_value();
|
||||||
let generics = match seg.arguments {
|
let generics = match seg.arguments {
|
||||||
syn::PathArguments::AngleBracketed(ref t) => t,
|
syn::PathArguments::AngleBracketed(ref t) => t,
|
||||||
_ => return Err(()),
|
_ => bail_span!(t, "must be Result<...>"),
|
||||||
};
|
};
|
||||||
let ty = match *generics.args.first().ok_or(())?.into_value() {
|
let generic = generics.args.first()
|
||||||
syn::GenericArgument::Type(ref t) => t,
|
.ok_or_else(|| err_span!(t, "must have at least one generic parameter"))?
|
||||||
_ => return Err(()),
|
.into_value();
|
||||||
|
let ty = match generic {
|
||||||
|
syn::GenericArgument::Type(t) => t,
|
||||||
|
other => bail_span!(other, "must be a type parameter"),
|
||||||
};
|
};
|
||||||
match *ty {
|
match *ty {
|
||||||
syn::Type::Tuple(ref t) if t.elems.len() == 0 => return Ok(None),
|
syn::Type::Tuple(ref t) if t.elems.len() == 0 => return Ok(None),
|
||||||
@ -910,32 +972,37 @@ fn extract_doc_comments(attrs: &[syn::Attribute]) -> Vec<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check there are no lifetimes on the function.
|
/// Check there are no lifetimes on the function.
|
||||||
fn assert_no_lifetimes(decl: &mut syn::FnDecl) {
|
fn assert_no_lifetimes(decl: &mut syn::FnDecl) -> Result<(), Diagnostic> {
|
||||||
struct Walk;
|
struct Walk {
|
||||||
|
diagnostics: Vec<Diagnostic>,
|
||||||
impl<'ast> syn::visit_mut::VisitMut for Walk {
|
|
||||||
fn visit_lifetime_mut(&mut self, _i: &mut syn::Lifetime) {
|
|
||||||
panic!(
|
|
||||||
"it is currently not sound to use lifetimes in function \
|
|
||||||
signatures"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
syn::visit_mut::VisitMut::visit_fn_decl_mut(&mut Walk, decl);
|
impl<'ast> syn::visit_mut::VisitMut for Walk {
|
||||||
|
fn visit_lifetime_mut(&mut self, i: &mut syn::Lifetime) {
|
||||||
|
self.diagnostics.push(err_span!(
|
||||||
|
&*i,
|
||||||
|
"it is currently not sound to use lifetimes in function \
|
||||||
|
signatures"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut walk = Walk { diagnostics: Vec::new() };
|
||||||
|
syn::visit_mut::VisitMut::visit_fn_decl_mut(&mut walk, decl);
|
||||||
|
Diagnostic::from_vec(walk.diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the path is a single ident, return it.
|
/// If the path is a single ident, return it.
|
||||||
fn extract_path_ident(path: &syn::Path) -> Option<Ident> {
|
fn extract_path_ident(path: &syn::Path) -> Result<Ident, Diagnostic> {
|
||||||
if path.leading_colon.is_some() {
|
if path.leading_colon.is_some() {
|
||||||
return None;
|
bail_span!(path, "global paths are not supported yet");
|
||||||
}
|
}
|
||||||
if path.segments.len() != 1 {
|
if path.segments.len() != 1 {
|
||||||
return None;
|
bail_span!(path, "multi-segment paths are not supported yet");
|
||||||
}
|
}
|
||||||
match path.segments.first().unwrap().value().arguments {
|
let value = &path.segments[0];
|
||||||
|
match value.arguments {
|
||||||
syn::PathArguments::None => {}
|
syn::PathArguments::None => {}
|
||||||
_ => return None,
|
_ => bail_span!(path, "paths with type parameters are not supported yet"),
|
||||||
}
|
}
|
||||||
path.segments.first().map(|v| v.value().ident.clone())
|
Ok(value.ident.clone())
|
||||||
}
|
}
|
||||||
|
23
crates/macro/ui-tests/invalid-attr.rs
Normal file
23
crates/macro/ui-tests/invalid-attr.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#![feature(use_extern_macros)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen(x)]
|
||||||
|
pub fn foo() {}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
#[wasm_bindgen(y)]
|
||||||
|
fn bar();
|
||||||
|
|
||||||
|
#[wasm_bindgen z]
|
||||||
|
fn bar();
|
||||||
|
|
||||||
|
#[wasm_bindgen(z2) x]
|
||||||
|
fn bar();
|
||||||
|
|
||||||
|
#[wasm_bindgen { }]
|
||||||
|
fn bar();
|
||||||
|
}
|
32
crates/macro/ui-tests/invalid-attr.stderr
Normal file
32
crates/macro/ui-tests/invalid-attr.stderr
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
error: error parsing #[wasm_bindgen] attribute options: failed to parse anything
|
||||||
|
--> $DIR/invalid-attr.rs:7:16
|
||||||
|
|
|
||||||
|
7 | #[wasm_bindgen(x)]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: error parsing #[wasm_bindgen] attribute options: failed to parse anything
|
||||||
|
--> $DIR/invalid-attr.rs:12:20
|
||||||
|
|
|
||||||
|
12 | #[wasm_bindgen(y)]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: malformed #[wasm_bindgen] attribute
|
||||||
|
--> $DIR/invalid-attr.rs:15:5
|
||||||
|
|
|
||||||
|
15 | #[wasm_bindgen z]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: malformed #[wasm_bindgen] attribute
|
||||||
|
--> $DIR/invalid-attr.rs:18:5
|
||||||
|
|
|
||||||
|
18 | #[wasm_bindgen(z2) x]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: malformed #[wasm_bindgen] attribute
|
||||||
|
--> $DIR/invalid-attr.rs:21:5
|
||||||
|
|
|
||||||
|
21 | #[wasm_bindgen { }]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
23
crates/macro/ui-tests/invalid-enums.rs
Normal file
23
crates/macro/ui-tests/invalid-enums.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#![feature(use_extern_macros)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
enum A {}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub enum B {
|
||||||
|
D(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub enum C {
|
||||||
|
X = 1 + 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub enum D {
|
||||||
|
X = 4294967296,
|
||||||
|
}
|
26
crates/macro/ui-tests/invalid-enums.stderr
Normal file
26
crates/macro/ui-tests/invalid-enums.stderr
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
error: only public enums are allowed with #[wasm_bindgen]
|
||||||
|
--> $DIR/invalid-enums.rs:8:1
|
||||||
|
|
|
||||||
|
8 | enum A {}
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error: only C-Style enums allowed with #[wasm_bindgen]
|
||||||
|
--> $DIR/invalid-enums.rs:12:6
|
||||||
|
|
|
||||||
|
12 | D(u32),
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: enums with #[wasm_bidngen] may only have number literal values
|
||||||
|
--> $DIR/invalid-enums.rs:17:9
|
||||||
|
|
|
||||||
|
17 | X = 1 + 3,
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: enums with #[wasm_bindgen] can only support numbers that can be represented as u32
|
||||||
|
--> $DIR/invalid-enums.rs:22:9
|
||||||
|
|
|
||||||
|
22 | X = 4294967296,
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
43
crates/macro/ui-tests/invalid-imports.rs
Normal file
43
crates/macro/ui-tests/invalid-imports.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#![feature(use_extern_macros)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
type A;
|
||||||
|
|
||||||
|
fn f() -> &'static u32;
|
||||||
|
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
fn f1();
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
fn f2(x: u32);
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
fn f3(x: &&u32);
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
fn f4(x: &foo::Bar);
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
fn f4(x: &::Bar);
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
fn f4(x: &Bar<T>);
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
fn f4(x: &Fn(T));
|
||||||
|
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
fn f();
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
fn f() -> ::Bar;
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
fn f() -> &Bar;
|
||||||
|
|
||||||
|
#[wasm_bindgen(catch)]
|
||||||
|
fn f() -> u32;
|
||||||
|
#[wasm_bindgen(catch)]
|
||||||
|
fn f() -> &u32;
|
||||||
|
#[wasm_bindgen(catch)]
|
||||||
|
fn f() -> Result<>;
|
||||||
|
#[wasm_bindgen(catch)]
|
||||||
|
fn f() -> Result<'a>;
|
||||||
|
}
|
92
crates/macro/ui-tests/invalid-imports.stderr
Normal file
92
crates/macro/ui-tests/invalid-imports.stderr
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
error: it is currently not sound to use lifetimes in function signatures
|
||||||
|
--> $DIR/invalid-imports.rs:11:16
|
||||||
|
|
|
||||||
|
11 | fn f() -> &'static u32;
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: imported methods must have at least one argument
|
||||||
|
--> $DIR/invalid-imports.rs:14:5
|
||||||
|
|
|
||||||
|
14 | fn f1();
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: first argument of method must be a shared reference
|
||||||
|
--> $DIR/invalid-imports.rs:16:14
|
||||||
|
|
|
||||||
|
16 | fn f2(x: u32);
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: first argument of method must be a path
|
||||||
|
--> $DIR/invalid-imports.rs:18:14
|
||||||
|
|
|
||||||
|
18 | fn f3(x: &&u32);
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: multi-segment paths are not supported yet
|
||||||
|
--> $DIR/invalid-imports.rs:20:15
|
||||||
|
|
|
||||||
|
20 | fn f4(x: &foo::Bar);
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: global paths are not supported yet
|
||||||
|
--> $DIR/invalid-imports.rs:22:15
|
||||||
|
|
|
||||||
|
22 | fn f4(x: &::Bar);
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: paths with type parameters are not supported yet
|
||||||
|
--> $DIR/invalid-imports.rs:24:15
|
||||||
|
|
|
||||||
|
24 | fn f4(x: &Bar<T>);
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: paths with type parameters are not supported yet
|
||||||
|
--> $DIR/invalid-imports.rs:26:15
|
||||||
|
|
|
||||||
|
26 | fn f4(x: &Fn(T));
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: constructor returns must be bare types
|
||||||
|
--> $DIR/invalid-imports.rs:29:5
|
||||||
|
|
|
||||||
|
29 | fn f();
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: global paths are not supported yet
|
||||||
|
--> $DIR/invalid-imports.rs:31:15
|
||||||
|
|
|
||||||
|
31 | fn f() -> ::Bar;
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: return value of constructor must be a bare path
|
||||||
|
--> $DIR/invalid-imports.rs:33:5
|
||||||
|
|
|
||||||
|
33 | fn f() -> &Bar;
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: must be Result<...>
|
||||||
|
--> $DIR/invalid-imports.rs:36:15
|
||||||
|
|
|
||||||
|
36 | fn f() -> u32;
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: must be Result<...>
|
||||||
|
--> $DIR/invalid-imports.rs:38:15
|
||||||
|
|
|
||||||
|
38 | fn f() -> &u32;
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: must have at least one generic parameter
|
||||||
|
--> $DIR/invalid-imports.rs:40:15
|
||||||
|
|
|
||||||
|
40 | fn f() -> Result<>;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: it is currently not sound to use lifetimes in function signatures
|
||||||
|
--> $DIR/invalid-imports.rs:42:22
|
||||||
|
|
|
||||||
|
42 | fn f() -> Result<'a>;
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: aborting due to 15 previous errors
|
||||||
|
|
38
crates/macro/ui-tests/invalid-items.rs
Normal file
38
crates/macro/ui-tests/invalid-items.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#![feature(use_extern_macros)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
fn foo() {}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub unsafe fn foo1() {}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub const fn foo2() {}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
struct Foo<T>(T);
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
static mut FOO: u32;
|
||||||
|
|
||||||
|
pub fn foo3(x: i32, ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "system" {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn foo4<T>() {}
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn foo5<'a>() {}
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn foo6<'a, T>() {}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
trait X {}
|
68
crates/macro/ui-tests/invalid-items.stderr
Normal file
68
crates/macro/ui-tests/invalid-items.stderr
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
error: can only #[wasm_bindgen] public functions
|
||||||
|
--> $DIR/invalid-items.rs:8:1
|
||||||
|
|
|
||||||
|
8 | fn foo() {}
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: can only #[wasm_bindgen] safe functions
|
||||||
|
--> $DIR/invalid-items.rs:11:5
|
||||||
|
|
|
||||||
|
11 | pub unsafe fn foo1() {}
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: can only #[wasm_bindgen] non-const functions
|
||||||
|
--> $DIR/invalid-items.rs:14:5
|
||||||
|
|
|
||||||
|
14 | pub const fn foo2() {}
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: structs with #[wasm_bindgen] cannot have lifetime or type parameters currently
|
||||||
|
--> $DIR/invalid-items.rs:17:11
|
||||||
|
|
|
||||||
|
17 | struct Foo<T>(T);
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: cannot import mutable globals yet
|
||||||
|
--> $DIR/invalid-items.rs:21:12
|
||||||
|
|
|
||||||
|
21 | static mut FOO: u32;
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: can't #[wasm_bindgen] variadic functions
|
||||||
|
--> $DIR/invalid-items.rs:23:25
|
||||||
|
|
|
||||||
|
23 | pub fn foo3(x: i32, ...);
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: only foreign mods with the `C` ABI are allowed
|
||||||
|
--> $DIR/invalid-items.rs:27:8
|
||||||
|
|
|
||||||
|
27 | extern "system" {
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: can't #[wasm_bindgen] functions with lifetime or type parameters
|
||||||
|
--> $DIR/invalid-items.rs:31:12
|
||||||
|
|
|
||||||
|
31 | pub fn foo4<T>() {}
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: can't #[wasm_bindgen] functions with lifetime or type parameters
|
||||||
|
--> $DIR/invalid-items.rs:33:12
|
||||||
|
|
|
||||||
|
33 | pub fn foo5<'a>() {}
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: can't #[wasm_bindgen] functions with lifetime or type parameters
|
||||||
|
--> $DIR/invalid-items.rs:35:12
|
||||||
|
|
|
||||||
|
35 | pub fn foo6<'a, T>() {}
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: #[wasm_bindgen] can only be applied to a function, struct, enum, impl, or extern block
|
||||||
|
--> $DIR/invalid-items.rs:38:1
|
||||||
|
|
|
||||||
|
38 | trait X {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
43
crates/macro/ui-tests/invalid-methods.rs
Normal file
43
crates/macro/ui-tests/invalid-methods.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#![feature(use_extern_macros)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct A;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
default impl A {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
unsafe impl A {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl Clone for A {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl<T> A {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl &'static A {
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! x { () => () }
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl A {
|
||||||
|
const X: u32 = 3;
|
||||||
|
type Y = u32;
|
||||||
|
x!();
|
||||||
|
|
||||||
|
// pub default fn foo() {} // TODO: compiler's pretty printer totally broken
|
||||||
|
|
||||||
|
|
||||||
|
pub const fn foo() {}
|
||||||
|
pub unsafe fn foo() {}
|
||||||
|
}
|
62
crates/macro/ui-tests/invalid-methods.stderr
Normal file
62
crates/macro/ui-tests/invalid-methods.stderr
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
error: #[wasm_bindgen] default impls are not supported
|
||||||
|
--> $DIR/invalid-methods.rs:11:1
|
||||||
|
|
|
||||||
|
11 | default impl A {
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: #[wasm_bindgen] unsafe impls are not supported
|
||||||
|
--> $DIR/invalid-methods.rs:15:1
|
||||||
|
|
|
||||||
|
15 | unsafe impl A {
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: #[wasm_bindgen] trait impls are not supported
|
||||||
|
--> $DIR/invalid-methods.rs:19:6
|
||||||
|
|
|
||||||
|
19 | impl Clone for A {
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: #[wasm_bindgen] generic impls aren't supported
|
||||||
|
--> $DIR/invalid-methods.rs:23:5
|
||||||
|
|
|
||||||
|
23 | impl<T> A {
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: unsupported self type in #[wasm_bindgen] impl
|
||||||
|
--> $DIR/invalid-methods.rs:27:6
|
||||||
|
|
|
||||||
|
27 | impl &'static A {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: const definitions aren't supported with #[wasm_bindgen]
|
||||||
|
--> $DIR/invalid-methods.rs:34:5
|
||||||
|
|
|
||||||
|
34 | const X: u32 = 3;
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: type definitions in impls aren't supported with #[wasm_bindgen]
|
||||||
|
--> $DIR/invalid-methods.rs:35:5
|
||||||
|
|
|
||||||
|
35 | type Y = u32;
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: macros in impls aren't supported
|
||||||
|
--> $DIR/invalid-methods.rs:36:5
|
||||||
|
|
|
||||||
|
36 | x!();
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: can only #[wasm_bindgen] non-const functions
|
||||||
|
--> $DIR/invalid-methods.rs:41:9
|
||||||
|
|
|
||||||
|
41 | pub const fn foo() {}
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: can only bindgen safe functions
|
||||||
|
--> $DIR/invalid-methods.rs:42:9
|
||||||
|
|
|
||||||
|
42 | pub unsafe fn foo() {}
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 10 previous errors
|
||||||
|
|
@ -1,10 +1,8 @@
|
|||||||
error: custom attribute panicked
|
error: can only #[wasm_bindgen] public functions
|
||||||
--> $DIR/non-public-function.rs:7:1
|
--> $DIR/non-public-function.rs:8:1
|
||||||
|
|
|
|
||||||
7 | #[wasm_bindgen]
|
8 | fn foo() {}
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
= help: message: can only bindgen public functions
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user