mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-17 02:30:50 +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 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 {
|
||||
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;
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
#[macro_use]
|
||||
extern crate wasm_bindgen_backend as backend;
|
||||
extern crate wasm_bindgen_shared as shared;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use backend::ast;
|
||||
use backend::Diagnostic;
|
||||
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 shared;
|
||||
use syn;
|
||||
@ -16,7 +16,7 @@ pub struct BindgenAttrs {
|
||||
|
||||
impl BindgenAttrs {
|
||||
/// 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
|
||||
.iter()
|
||||
.enumerate()
|
||||
@ -24,18 +24,22 @@ impl BindgenAttrs {
|
||||
.map(|a| a.0);
|
||||
let pos = match pos {
|
||||
Some(i) => i,
|
||||
None => return BindgenAttrs::default(),
|
||||
None => return Ok(BindgenAttrs::default()),
|
||||
};
|
||||
let mut tts = attrs.remove(pos).tts.into_iter();
|
||||
let tt = match tts.next() {
|
||||
Some(TokenTree::Group(d)) => d.stream(),
|
||||
Some(_) => panic!("malformed #[wasm_bindgen] attribute"),
|
||||
None => return BindgenAttrs::default(),
|
||||
let attr = attrs.remove(pos);
|
||||
let mut tts = attr.tts.clone().into_iter();
|
||||
let group = match tts.next() {
|
||||
Some(TokenTree::Group(d)) => d,
|
||||
Some(_) => bail_span!(attr, "malformed #[wasm_bindgen] attribute"),
|
||||
None => return Ok(BindgenAttrs::default()),
|
||||
};
|
||||
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
|
||||
@ -304,15 +308,16 @@ trait ConvertToAst<Ctx> {
|
||||
/// Convert into our target.
|
||||
///
|
||||
/// 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 {
|
||||
type Target = ast::Struct;
|
||||
|
||||
fn convert(self, (): ()) -> Self::Target {
|
||||
fn convert(self, (): ()) -> Result<Self::Target, Diagnostic> {
|
||||
if self.generics.params.len() > 0 {
|
||||
panic!(
|
||||
bail_span!(
|
||||
self.generics,
|
||||
"structs with #[wasm_bindgen] cannot have lifetime or \
|
||||
type parameters currently"
|
||||
);
|
||||
@ -332,7 +337,7 @@ impl<'a> ConvertToAst<()> for &'a mut syn::ItemStruct {
|
||||
let name_str = name.to_string();
|
||||
let getter = shared::struct_field_get(&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);
|
||||
fields.push(ast::StructField {
|
||||
name: name.clone(),
|
||||
@ -346,20 +351,28 @@ impl<'a> ConvertToAst<()> for &'a mut syn::ItemStruct {
|
||||
}
|
||||
}
|
||||
let comments: Vec<String> = extract_doc_comments(&self.attrs);
|
||||
ast::Struct {
|
||||
Ok(ast::Struct {
|
||||
name: self.ident.clone(),
|
||||
fields,
|
||||
comments,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn {
|
||||
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 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 js_ret = if catch {
|
||||
// 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
|
||||
//
|
||||
// should probably fix this one day...
|
||||
extract_first_ty_param(wasm.ret.as_ref())
|
||||
.expect("can't `catch` without returning a Result")
|
||||
extract_first_ty_param(wasm.ret.as_ref())?
|
||||
} else {
|
||||
wasm.ret.clone()
|
||||
};
|
||||
@ -387,24 +399,27 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
||||
let class = wasm
|
||||
.arguments
|
||||
.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 {
|
||||
syn::Type::Reference(syn::TypeReference {
|
||||
mutability: None,
|
||||
ref 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 {
|
||||
syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
ref 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)
|
||||
.expect("first argument of method must be a bare type");
|
||||
let class_name = extract_path_ident(class_name)?;
|
||||
let class_name = opts
|
||||
.js_class()
|
||||
.map(Into::into)
|
||||
@ -433,17 +448,16 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
||||
} else if opts.constructor() {
|
||||
let class = match wasm.ret {
|
||||
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 {
|
||||
syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
ref 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)
|
||||
.expect("first argument of method must be a bare type");
|
||||
let class_name = extract_path_ident(class_name)?;
|
||||
|
||||
ast::ImportFunctionKind::Method {
|
||||
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);
|
||||
format!("__wbg_{}_{}", js_name, ShortHash(data))
|
||||
};
|
||||
ast::ImportKind::Function(ast::ImportFunction {
|
||||
Ok(ast::ImportKind::Function(ast::ImportFunction {
|
||||
function: wasm,
|
||||
kind,
|
||||
js_ret,
|
||||
@ -471,59 +485,59 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
||||
rust_name: self.ident.clone(),
|
||||
shim: Ident::new(&shim, Span::call_site()),
|
||||
doc_comment: None,
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl ConvertToAst<()> for syn::ForeignItemType {
|
||||
type Target = ast::ImportKind;
|
||||
|
||||
fn convert(self, (): ()) -> Self::Target {
|
||||
ast::ImportKind::Type(ast::ImportType {
|
||||
fn convert(self, (): ()) -> Result<Self::Target, Diagnostic> {
|
||||
Ok(ast::ImportKind::Type(ast::ImportType {
|
||||
vis: self.vis,
|
||||
name: self.ident,
|
||||
attrs: self.attrs,
|
||||
doc_comment: None,
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl ConvertToAst<BindgenAttrs> for syn::ForeignItemStatic {
|
||||
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() {
|
||||
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 shim = format!("__wbg_static_accessor_{}_{}", js_name, self.ident);
|
||||
ast::ImportKind::Static(ast::ImportStatic {
|
||||
Ok(ast::ImportKind::Static(ast::ImportStatic {
|
||||
ty: *self.ty,
|
||||
vis: self.vis,
|
||||
rust_name: self.ident.clone(),
|
||||
js_name: js_name.clone(),
|
||||
shim: Ident::new(&shim, Span::call_site()),
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl ConvertToAst<BindgenAttrs> for syn::ItemFn {
|
||||
type Target = ast::Function;
|
||||
|
||||
fn convert(self, attrs: BindgenAttrs) -> Self::Target {
|
||||
fn convert(self, attrs: BindgenAttrs) -> Result<Self::Target, Diagnostic> {
|
||||
match self.vis {
|
||||
syn::Visibility::Public(_) => {}
|
||||
_ => panic!("can only bindgen public functions"),
|
||||
_ => bail_span!(self, "can only #[wasm_bindgen] public functions"),
|
||||
}
|
||||
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() {
|
||||
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);
|
||||
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>,
|
||||
vis: syn::Visibility,
|
||||
allow_self: bool,
|
||||
) -> (ast::Function, Option<ast::MethodSelf>) {
|
||||
) -> Result<(ast::Function, Option<ast::MethodSelf>), Diagnostic> {
|
||||
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 {
|
||||
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 };
|
||||
|
||||
@ -574,7 +591,7 @@ fn function_from_decl(
|
||||
syn::ReturnType::Type(_, ty) => Some(*ty),
|
||||
};
|
||||
|
||||
(
|
||||
Ok((
|
||||
ast::Function {
|
||||
name: name.clone(),
|
||||
arguments,
|
||||
@ -583,7 +600,7 @@ fn function_from_decl(
|
||||
rust_attrs: attrs,
|
||||
},
|
||||
method_self,
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) trait MacroParse<Ctx> {
|
||||
@ -623,11 +640,11 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
|
||||
constructor: None,
|
||||
comments,
|
||||
rust_name: f.ident.clone(),
|
||||
function: f.convert(opts.unwrap_or_default()),
|
||||
function: f.convert(opts.unwrap_or_default())?,
|
||||
});
|
||||
}
|
||||
syn::Item::Struct(mut s) => {
|
||||
program.structs.push((&mut s).convert(()));
|
||||
program.structs.push((&mut s).convert(())?);
|
||||
s.to_tokens(tokens);
|
||||
}
|
||||
syn::Item::Impl(mut i) => {
|
||||
@ -635,17 +652,23 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
|
||||
i.to_tokens(tokens);
|
||||
}
|
||||
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)?;
|
||||
}
|
||||
syn::Item::Enum(e) => {
|
||||
e.to_tokens(tokens);
|
||||
e.macro_parse(program, ())?;
|
||||
}
|
||||
_ => panic!(
|
||||
"#[wasm_bindgen] can only be applied to a function, \
|
||||
struct, enum, impl, or extern block"
|
||||
),
|
||||
_ => {
|
||||
bail_span!(
|
||||
self,
|
||||
"#[wasm_bindgen] can only be applied to a function, \
|
||||
struct, enum, impl, or extern block"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -657,26 +680,23 @@ impl<'a> MacroParse<()> for &'a mut syn::ItemImpl {
|
||||
-> Result<(), Diagnostic>
|
||||
{
|
||||
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() {
|
||||
panic!("unsafe impls are not supported");
|
||||
bail_span!(self.unsafety, "#[wasm_bindgen] unsafe impls are not supported");
|
||||
}
|
||||
if self.trait_.is_some() {
|
||||
panic!("trait impls are not supported");
|
||||
if let Some((_, path, _)) = &self.trait_ {
|
||||
bail_span!(path, "#[wasm_bindgen] trait impls are not supported");
|
||||
}
|
||||
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 {
|
||||
syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
ref path,
|
||||
}) => match extract_path_ident(path) {
|
||||
Some(ident) => ident,
|
||||
None => panic!("unsupported self type in impl"),
|
||||
},
|
||||
_ => panic!("unsupported self type in impl"),
|
||||
}) => extract_path_ident(path)?,
|
||||
_ => bail_span!(self.self_ty, "unsupported self type in #[wasm_bindgen] impl"),
|
||||
};
|
||||
let mut errors = Vec::new();
|
||||
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;
|
||||
replace_self(class, 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::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?"),
|
||||
};
|
||||
match method.vis {
|
||||
@ -709,13 +735,19 @@ impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) {
|
||||
panic!("default methods are not supported");
|
||||
}
|
||||
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() {
|
||||
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 is_constructor = opts.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.vis.clone(),
|
||||
true,
|
||||
);
|
||||
)?;
|
||||
|
||||
program.exports.push(ast::Export {
|
||||
class: Some(class.clone()),
|
||||
@ -750,7 +782,7 @@ impl MacroParse<()> for syn::ItemEnum {
|
||||
{
|
||||
match self.vis {
|
||||
syn::Visibility::Public(_) => {}
|
||||
_ => panic!("only public enums are allowed"),
|
||||
_ => bail_span!(self, "only public enums are allowed with #[wasm_bindgen]"),
|
||||
}
|
||||
|
||||
let variants = self
|
||||
@ -760,7 +792,7 @@ impl MacroParse<()> for syn::ItemEnum {
|
||||
.map(|(i, v)| {
|
||||
match v.fields {
|
||||
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 {
|
||||
Some((
|
||||
@ -771,20 +803,30 @@ impl MacroParse<()> for syn::ItemEnum {
|
||||
}),
|
||||
)) => {
|
||||
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
|
||||
}
|
||||
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(),
|
||||
value,
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
.collect::<Result<_, Diagnostic>>()?;
|
||||
let comments = extract_doc_comments(&self.attrs);
|
||||
program.enums.push(ast::Enum {
|
||||
name: self.ident,
|
||||
@ -799,47 +841,62 @@ impl MacroParse<BindgenAttrs> for syn::ItemForeignMod {
|
||||
fn macro_parse(self, program: &mut ast::Program, opts: BindgenAttrs)
|
||||
-> Result<(), Diagnostic>
|
||||
{
|
||||
let mut errors = Vec::new();
|
||||
match self.abi.name {
|
||||
Some(ref l) if l.value() == "C" => {}
|
||||
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() {
|
||||
let item_opts = {
|
||||
let attrs = match item {
|
||||
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,
|
||||
_ => 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 mut kind = match item {
|
||||
syn::ForeignItem::Fn(f) => f.convert((item_opts, &module)),
|
||||
syn::ForeignItem::Type(t) => t.convert(()),
|
||||
syn::ForeignItem::Static(s) => s.convert(item_opts),
|
||||
if let Err(e) = item.macro_parse(program, &opts) {
|
||||
errors.push(e);
|
||||
}
|
||||
}
|
||||
Diagnostic::from_vec(errors)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MacroParse<&'a BindgenAttrs> for syn::ForeignItem {
|
||||
fn macro_parse(mut self, program: &mut ast::Program, opts: &'a BindgenAttrs)
|
||||
-> Result<(), Diagnostic>
|
||||
{
|
||||
let item_opts = {
|
||||
let attrs = match self {
|
||||
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,
|
||||
_ => 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(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Some(t) => t,
|
||||
None => return Ok(None),
|
||||
@ -849,16 +906,21 @@ fn extract_first_ty_param(ty: Option<&syn::Type>) -> Result<Option<syn::Type>, (
|
||||
qself: None,
|
||||
ref 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 {
|
||||
syn::PathArguments::AngleBracketed(ref t) => t,
|
||||
_ => return Err(()),
|
||||
_ => bail_span!(t, "must be Result<...>"),
|
||||
};
|
||||
let ty = match *generics.args.first().ok_or(())?.into_value() {
|
||||
syn::GenericArgument::Type(ref t) => t,
|
||||
_ => return Err(()),
|
||||
let generic = generics.args.first()
|
||||
.ok_or_else(|| err_span!(t, "must have at least one generic parameter"))?
|
||||
.into_value();
|
||||
let ty = match generic {
|
||||
syn::GenericArgument::Type(t) => t,
|
||||
other => bail_span!(other, "must be a type parameter"),
|
||||
};
|
||||
match *ty {
|
||||
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.
|
||||
fn assert_no_lifetimes(decl: &mut syn::FnDecl) {
|
||||
struct Walk;
|
||||
|
||||
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"
|
||||
);
|
||||
}
|
||||
fn assert_no_lifetimes(decl: &mut syn::FnDecl) -> Result<(), Diagnostic> {
|
||||
struct Walk {
|
||||
diagnostics: Vec<Diagnostic>,
|
||||
}
|
||||
|
||||
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.
|
||||
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() {
|
||||
return None;
|
||||
bail_span!(path, "global paths are not supported yet");
|
||||
}
|
||||
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 => {}
|
||||
_ => 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
|
||||
--> $DIR/non-public-function.rs:7:1
|
||||
error: can only #[wasm_bindgen] public functions
|
||||
--> $DIR/non-public-function.rs:8:1
|
||||
|
|
||||
7 | #[wasm_bindgen]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: message: can only bindgen public functions
|
||||
8 | fn foo() {}
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user