From 6e701bfe83a8e36e5ab6a1719f2c9c89903f61c8 Mon Sep 17 00:00:00 2001 From: J Henry Waugh Date: Wed, 9 Sep 2020 16:24:37 -0500 Subject: [PATCH 1/9] Catch getter, setter, indexer errors --- codegen/src/attrs.rs | 4 +- codegen/src/function.rs | 43 +++++++++++++------ codegen/src/module.rs | 2 +- .../rhai_fn_rename_to_index_getter.rs | 28 ++++++++++++ .../rhai_fn_rename_to_index_getter.stderr | 11 +++++ .../rhai_fn_rename_to_index_setter.rs | 28 ++++++++++++ .../rhai_fn_rename_to_index_setter.stderr | 11 +++++ .../ui_tests/rhai_fn_rename_to_prop_getter.rs | 28 ++++++++++++ .../rhai_fn_rename_to_prop_getter.stderr | 11 +++++ .../ui_tests/rhai_fn_rename_to_prop_setter.rs | 28 ++++++++++++ .../rhai_fn_rename_to_prop_setter.stderr | 11 +++++ 11 files changed, 189 insertions(+), 16 deletions(-) create mode 100644 codegen/ui_tests/rhai_fn_rename_to_index_getter.rs create mode 100644 codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr create mode 100644 codegen/ui_tests/rhai_fn_rename_to_index_setter.rs create mode 100644 codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr create mode 100644 codegen/ui_tests/rhai_fn_rename_to_prop_getter.rs create mode 100644 codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr create mode 100644 codegen/ui_tests/rhai_fn_rename_to_prop_setter.rs create mode 100644 codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr diff --git a/codegen/src/attrs.rs b/codegen/src/attrs.rs index 5d1e42d7..32d258f7 100644 --- a/codegen/src/attrs.rs +++ b/codegen/src/attrs.rs @@ -22,6 +22,7 @@ pub trait ExportedParams: Sized { pub struct AttrItem { pub key: proc_macro2::Ident, pub value: Option, + pub span: proc_macro2::Span, } pub struct ExportInfo { @@ -46,6 +47,7 @@ pub fn parse_punctuated_items( let mut attrs: Vec = Vec::new(); for arg in arg_list { + let arg_span = arg.span(); let (key, value) = match arg { syn::Expr::Assign(syn::ExprAssign { ref left, @@ -78,7 +80,7 @@ pub fn parse_punctuated_items( .ok_or_else(|| syn::Error::new(attr_path.span(), "expecting attribute name"))?, x => return Err(syn::Error::new(x.span(), "expecting identifier")), }; - attrs.push(AttrItem { key, value }); + attrs.push(AttrItem { key, value, span: arg_span }); } Ok(ExportInfo { item_span: list_span, items: attrs }) diff --git a/codegen/src/function.rs b/codegen/src/function.rs index aa4001f5..2f80fb03 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -64,23 +64,38 @@ impl ExportedParams for ExportedFnParams { let mut return_raw = false; let mut skip = false; for attr in attrs { - let crate::attrs::AttrItem { key, value } = attr; + let crate::attrs::AttrItem { key, value, span: item_span } = attr; match (key.to_string().as_ref(), value) { - ("name", Some(s)) => { - // check validity of name - if s.value().contains('.') { - return Err(syn::Error::new( - s.span(), - "Rhai function names may not contain dot", - )); - } - name.push(s.value()) - } - ("get", Some(s)) => name.push(make_getter(&s.value())), - ("set", Some(s)) => name.push(make_setter(&s.value())), ("get", None) | ("set", None) | ("name", None) => { return Err(syn::Error::new(key.span(), "requires value")) - } + }, + ("name", Some(s)) if &s.value() == FN_IDX_GET => { + return Err(syn::Error::new(item_span, + "use attribute 'index_get' instead")) + }, + ("name", Some(s)) if &s.value() == FN_IDX_SET => { + return Err(syn::Error::new(item_span, + "use attribute 'index_set' instead")) + }, + ("name", Some(s)) if s.value().starts_with("get$") => { + return Err(syn::Error::new(item_span, + format!("use attribute 'getter = \"{}\"' instead", + &s.value()["get$".len()..]))) + }, + ("name", Some(s)) if s.value().starts_with("set$") => { + return Err(syn::Error::new(item_span, + format!("use attribute 'setter = \"{}\"' instead", + &s.value()["set$".len()..]))) + }, + ("name", Some(s)) if s.value().contains('.') => { + return Err(syn::Error::new(s.span(), + "Rhai function names may not contain dot")) + }, + ("name", Some(s)) => { + name.push(s.value()) + }, + ("get", Some(s)) => name.push(make_getter(&s.value())), + ("set", Some(s)) => name.push(make_setter(&s.value())), ("index_get", None) => name.push(FN_IDX_GET.to_string()), ("index_set", None) => name.push(FN_IDX_SET.to_string()), ("return_raw", None) => return_raw = true, diff --git a/codegen/src/module.rs b/codegen/src/module.rs index 07ae54da..1ebc25b8 100644 --- a/codegen/src/module.rs +++ b/codegen/src/module.rs @@ -53,7 +53,7 @@ impl ExportedParams for ExportedModParams { let mut skip = false; let mut scope = ExportScope::default(); for attr in attrs { - let AttrItem { key, value } = attr; + let AttrItem { key, value, .. } = attr; match (key.to_string().as_ref(), value) { ("name", Some(s)) => name = Some(s.value()), ("name", None) => return Err(syn::Error::new(key.span(), "requires value")), diff --git a/codegen/ui_tests/rhai_fn_rename_to_index_getter.rs b/codegen/ui_tests/rhai_fn_rename_to_index_getter.rs new file mode 100644 index 00000000..394113b4 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_rename_to_index_getter.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(name = "index$get$")] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr b/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr new file mode 100644 index 00000000..287283f9 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr @@ -0,0 +1,11 @@ +error: use attribute 'index_get' instead + --> $DIR/rhai_fn_rename_to_index_getter.rs:12:15 + | +12 | #[rhai_fn(name = "index$get$")] + | ^^^^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_rename_to_index_getter.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_index_setter.rs b/codegen/ui_tests/rhai_fn_rename_to_index_setter.rs new file mode 100644 index 00000000..cb5d7c8e --- /dev/null +++ b/codegen/ui_tests/rhai_fn_rename_to_index_setter.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(name = "index$set$")] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr b/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr new file mode 100644 index 00000000..712f2c59 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr @@ -0,0 +1,11 @@ +error: use attribute 'index_set' instead + --> $DIR/rhai_fn_rename_to_index_setter.rs:12:15 + | +12 | #[rhai_fn(name = "index$set$")] + | ^^^^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_rename_to_index_setter.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_prop_getter.rs b/codegen/ui_tests/rhai_fn_rename_to_prop_getter.rs new file mode 100644 index 00000000..d81aa5d5 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_rename_to_prop_getter.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(name = "get$foo")] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr b/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr new file mode 100644 index 00000000..d9d9b3e8 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr @@ -0,0 +1,11 @@ +error: use attribute 'getter = "foo"' instead + --> $DIR/rhai_fn_rename_to_prop_getter.rs:12:15 + | +12 | #[rhai_fn(name = "get$foo")] + | ^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_rename_to_prop_getter.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_prop_setter.rs b/codegen/ui_tests/rhai_fn_rename_to_prop_setter.rs new file mode 100644 index 00000000..d81aa5d5 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_rename_to_prop_setter.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(name = "get$foo")] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr b/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr new file mode 100644 index 00000000..a1dfbebd --- /dev/null +++ b/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr @@ -0,0 +1,11 @@ +error: use attribute 'getter = "foo"' instead + --> $DIR/rhai_fn_rename_to_prop_setter.rs:12:15 + | +12 | #[rhai_fn(name = "get$foo")] + | ^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_rename_to_prop_setter.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` From 43969a7bee344a58b2edde03326a59a4f26b449d Mon Sep 17 00:00:00 2001 From: J Henry Waugh Date: Wed, 9 Sep 2020 16:25:09 -0500 Subject: [PATCH 2/9] Forbid $ in renames --- codegen/src/function.rs | 4 +++ .../ui_tests/rhai_fn_rename_dollar_sign.rs | 28 +++++++++++++++++++ .../rhai_fn_rename_dollar_sign.stderr | 11 ++++++++ 3 files changed, 43 insertions(+) create mode 100644 codegen/ui_tests/rhai_fn_rename_dollar_sign.rs create mode 100644 codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 2f80fb03..b96180d2 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -87,6 +87,10 @@ impl ExportedParams for ExportedFnParams { format!("use attribute 'setter = \"{}\"' instead", &s.value()["set$".len()..]))) }, + ("name", Some(s)) if s.value().contains('$') => { + return Err(syn::Error::new(s.span(), + "Rhai function names may not contain dollar sign")) + }, ("name", Some(s)) if s.value().contains('.') => { return Err(syn::Error::new(s.span(), "Rhai function names may not contain dot")) diff --git a/codegen/ui_tests/rhai_fn_rename_dollar_sign.rs b/codegen/ui_tests/rhai_fn_rename_dollar_sign.rs new file mode 100644 index 00000000..69af645c --- /dev/null +++ b/codegen/ui_tests/rhai_fn_rename_dollar_sign.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(name = "big$caching")] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr b/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr new file mode 100644 index 00000000..96f4c4de --- /dev/null +++ b/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr @@ -0,0 +1,11 @@ +error: Rhai function names may not contain dollar sign + --> $DIR/rhai_fn_rename_dollar_sign.rs:12:22 + | +12 | #[rhai_fn(name = "big$caching")] + | ^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_rename_dollar_sign.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` From b74923a63cd780a7208d14354f06a79f3622a0c9 Mon Sep 17 00:00:00 2001 From: J Henry Waugh Date: Sat, 12 Sep 2020 14:56:02 -0500 Subject: [PATCH 3/9] Unit tests for property getters and setters --- codegen/src/test/module.rs | 118 +++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 5d4e6186..a173b787 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -1004,6 +1004,124 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn one_getter_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod one_fn { + #[rhai_fn(get = "square")] + pub fn int_foo(x: &mut u64) -> u64 { + (*x) * (*x) + } + } + }; + + let expected_tokens = quote! { + pub mod one_fn { + pub fn int_foo(x: &mut u64) -> u64 { + (*x) * (*x) + } + #[allow(unused_imports)] + use super::*; + #[allow(unused_mut)] + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + m.set_fn("get$square", FnAccess::Public, &[core::any::TypeId::of::()], + CallableFunction::from_plugin(int_foo_token())); + m + } + #[allow(non_camel_case_types)] + struct int_foo_token(); + impl PluginFunction for int_foo_token { + fn call(&self, + args: &mut [&mut Dynamic], pos: Position + ) -> Result> { + debug_assert_eq!(args.len(), 1usize, + "wrong arg count: {} != {}", args.len(), 1usize); + let arg0: &mut _ = &mut args[0usize].write_lock::().unwrap(); + Ok(Dynamic::from(int_foo(arg0))) + } + + fn is_method_call(&self) -> bool { true } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(int_foo_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::()].into_boxed_slice() + } + } + pub fn int_foo_token_callable() -> CallableFunction { + CallableFunction::from_plugin(int_foo_token()) + } + pub fn int_foo_token_input_types() -> Box<[TypeId]> { + int_foo_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + + #[test] + fn one_setter_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod one_fn { + #[rhai_fn(set = "squared")] + pub fn int_foo(x: &mut u64) { + *x = (*x) * (*x) + } + } + }; + + let expected_tokens = quote! { + pub mod one_fn { + pub fn int_foo(x: &mut u64) { + *x = (*x) * (*x) + } + #[allow(unused_imports)] + use super::*; + #[allow(unused_mut)] + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + m.set_fn("set$squared", FnAccess::Public, &[core::any::TypeId::of::()], + CallableFunction::from_plugin(int_foo_token())); + m + } + #[allow(non_camel_case_types)] + struct int_foo_token(); + impl PluginFunction for int_foo_token { + fn call(&self, + args: &mut [&mut Dynamic], pos: Position + ) -> Result> { + debug_assert_eq!(args.len(), 1usize, + "wrong arg count: {} != {}", args.len(), 1usize); + let arg0: &mut _ = &mut args[0usize].write_lock::().unwrap(); + Ok(Dynamic::from(int_foo(arg0))) + } + + fn is_method_call(&self) -> bool { true } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(int_foo_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::()].into_boxed_slice() + } + } + pub fn int_foo_token_callable() -> CallableFunction { + CallableFunction::from_plugin(int_foo_token()) + } + pub fn int_foo_token_input_types() -> Box<[TypeId]> { + int_foo_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_constant_nested_module() { let input_tokens: TokenStream = quote! { From cecf3dd58501aebccc10c66b804e4e047bfc2d04 Mon Sep 17 00:00:00 2001 From: J Henry Waugh Date: Sat, 12 Sep 2020 15:22:09 -0500 Subject: [PATCH 4/9] Unit tests for index getters and setters --- codegen/src/test/module.rs | 129 +++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index a173b787..dff603dd 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -1122,6 +1122,135 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn one_index_getter_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod one_index_fn { + #[rhai_fn(index_get)] + pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT { + x.get(i) + } + } + }; + + let expected_tokens = quote! { + pub mod one_index_fn { + pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT { + x.get(i) + } + #[allow(unused_imports)] + use super::*; + #[allow(unused_mut)] + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + m.set_fn("index$get$", FnAccess::Public, + &[core::any::TypeId::of::(), + core::any::TypeId::of::()], + CallableFunction::from_plugin(get_by_index_token())); + m + } + #[allow(non_camel_case_types)] + struct get_by_index_token(); + impl PluginFunction for get_by_index_token { + fn call(&self, + args: &mut [&mut Dynamic], pos: Position + ) -> Result> { + debug_assert_eq!(args.len(), 2usize, + "wrong arg count: {} != {}", args.len(), 2usize); + let arg1 = mem::take(args[1usize]).clone().cast::(); + let arg0: &mut _ = &mut args[0usize].write_lock::().unwrap(); + Ok(Dynamic::from(get_by_index(arg0, arg1))) + } + + fn is_method_call(&self) -> bool { true } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(get_by_index_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::(), + TypeId::of::()].into_boxed_slice() + } + } + pub fn get_by_index_token_callable() -> CallableFunction { + CallableFunction::from_plugin(get_by_index_token()) + } + pub fn get_by_index_token_input_types() -> Box<[TypeId]> { + get_by_index_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + + #[test] + fn one_index_setter_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod one_index_fn { + #[rhai_fn(index_set)] + pub fn set_by_index(x: &mut MyCollection, i: u64, item: FLOAT) { + x.entry(i).set(item) + } + } + }; + + let expected_tokens = quote! { + pub mod one_index_fn { + pub fn set_by_index(x: &mut MyCollection, i: u64, item: FLOAT) { + x.entry(i).set(item) + } + #[allow(unused_imports)] + use super::*; + #[allow(unused_mut)] + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + m.set_fn("index$set$", FnAccess::Public, + &[core::any::TypeId::of::(), + core::any::TypeId::of::(), + core::any::TypeId::of::()], + CallableFunction::from_plugin(set_by_index_token())); + m + } + #[allow(non_camel_case_types)] + struct set_by_index_token(); + impl PluginFunction for set_by_index_token { + fn call(&self, + args: &mut [&mut Dynamic], pos: Position + ) -> Result> { + debug_assert_eq!(args.len(), 3usize, + "wrong arg count: {} != {}", args.len(), 3usize); + let arg1 = mem::take(args[1usize]).clone().cast::(); + let arg2 = mem::take(args[2usize]).clone().cast::(); + let arg0: &mut _ = &mut args[0usize].write_lock::().unwrap(); + Ok(Dynamic::from(set_by_index(arg0, arg1, arg2))) + } + + fn is_method_call(&self) -> bool { true } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(set_by_index_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::(), + TypeId::of::(), + TypeId::of::()].into_boxed_slice() + } + } + pub fn set_by_index_token_callable() -> CallableFunction { + CallableFunction::from_plugin(set_by_index_token()) + } + pub fn set_by_index_token_input_types() -> Box<[TypeId]> { + set_by_index_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_constant_nested_module() { let input_tokens: TokenStream = quote! { From 18032ab8a022daec217d1da70a80dae4fbac13f5 Mon Sep 17 00:00:00 2001 From: J Henry Waugh Date: Sat, 12 Sep 2020 17:10:43 -0500 Subject: [PATCH 5/9] Unit test for multiple renames --- codegen/src/test/module.rs | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index dff603dd..35e3a6cb 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -538,6 +538,74 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn one_double_rename_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod one_fn { + #[rhai_fn(name = "add", name = "+", name = "add_together")] + pub fn add_together(x: INT, y: INT) -> INT { + x + y + } + } + }; + + let expected_tokens = quote! { + pub mod one_fn { + pub fn add_together(x: INT, y: INT) -> INT { + x + y + } + #[allow(unused_imports)] + use super::*; + #[allow(unused_mut)] + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + m.set_fn("add", FnAccess::Public, &[core::any::TypeId::of::(), + core::any::TypeId::of::()], + CallableFunction::from_plugin(add_together_token())); + m.set_fn("+", FnAccess::Public, &[core::any::TypeId::of::(), + core::any::TypeId::of::()], + CallableFunction::from_plugin(add_together_token())); + m.set_fn("add_together", FnAccess::Public, &[core::any::TypeId::of::(), + core::any::TypeId::of::()], + CallableFunction::from_plugin(add_together_token())); + m + } + #[allow(non_camel_case_types)] + struct add_together_token(); + impl PluginFunction for add_together_token { + fn call(&self, + args: &mut [&mut Dynamic], pos: Position + ) -> Result> { + debug_assert_eq!(args.len(), 2usize, + "wrong arg count: {} != {}", args.len(), 2usize); + let arg0 = mem::take(args[0usize]).clone().cast::(); + let arg1 = mem::take(args[1usize]).clone().cast::(); + Ok(Dynamic::from(add_together(arg0, arg1))) + } + + fn is_method_call(&self) -> bool { false } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(add_together_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::(), + TypeId::of::()].into_boxed_slice() + } + } + pub fn add_together_token_callable() -> CallableFunction { + CallableFunction::from_plugin(add_together_token()) + } + pub fn add_together_token_input_types() -> Box<[TypeId]> { + add_together_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_constant_module() { let input_tokens: TokenStream = quote! { From 335d853060330a49338aecf05d12eb5972c356e7 Mon Sep 17 00:00:00 2001 From: J Henry Waugh Date: Sat, 12 Sep 2020 17:20:51 -0500 Subject: [PATCH 6/9] Unit tests for rename + getter/setter/indexer --- codegen/src/test/module.rs | 260 +++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 35e3a6cb..e830600e 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -1131,6 +1131,67 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn one_getter_and_rename_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod one_fn { + #[rhai_fn(name = "square", get = "square")] + pub fn int_foo(x: &mut u64) -> u64 { + (*x) * (*x) + } + } + }; + + let expected_tokens = quote! { + pub mod one_fn { + pub fn int_foo(x: &mut u64) -> u64 { + (*x) * (*x) + } + #[allow(unused_imports)] + use super::*; + #[allow(unused_mut)] + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + m.set_fn("square", FnAccess::Public, &[core::any::TypeId::of::()], + CallableFunction::from_plugin(int_foo_token())); + m.set_fn("get$square", FnAccess::Public, &[core::any::TypeId::of::()], + CallableFunction::from_plugin(int_foo_token())); + m + } + #[allow(non_camel_case_types)] + struct int_foo_token(); + impl PluginFunction for int_foo_token { + fn call(&self, + args: &mut [&mut Dynamic], pos: Position + ) -> Result> { + debug_assert_eq!(args.len(), 1usize, + "wrong arg count: {} != {}", args.len(), 1usize); + let arg0: &mut _ = &mut args[0usize].write_lock::().unwrap(); + Ok(Dynamic::from(int_foo(arg0))) + } + + fn is_method_call(&self) -> bool { true } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(int_foo_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::()].into_boxed_slice() + } + } + pub fn int_foo_token_callable() -> CallableFunction { + CallableFunction::from_plugin(int_foo_token()) + } + pub fn int_foo_token_input_types() -> Box<[TypeId]> { + int_foo_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_setter_fn_module() { let input_tokens: TokenStream = quote! { @@ -1190,6 +1251,67 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn one_setter_and_rename_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod one_fn { + #[rhai_fn(name = "set_sq", set = "squared")] + pub fn int_foo(x: &mut u64) { + *x = (*x) * (*x) + } + } + }; + + let expected_tokens = quote! { + pub mod one_fn { + pub fn int_foo(x: &mut u64) { + *x = (*x) * (*x) + } + #[allow(unused_imports)] + use super::*; + #[allow(unused_mut)] + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + m.set_fn("set_sq", FnAccess::Public, &[core::any::TypeId::of::()], + CallableFunction::from_plugin(int_foo_token())); + m.set_fn("set$squared", FnAccess::Public, &[core::any::TypeId::of::()], + CallableFunction::from_plugin(int_foo_token())); + m + } + #[allow(non_camel_case_types)] + struct int_foo_token(); + impl PluginFunction for int_foo_token { + fn call(&self, + args: &mut [&mut Dynamic], pos: Position + ) -> Result> { + debug_assert_eq!(args.len(), 1usize, + "wrong arg count: {} != {}", args.len(), 1usize); + let arg0: &mut _ = &mut args[0usize].write_lock::().unwrap(); + Ok(Dynamic::from(int_foo(arg0))) + } + + fn is_method_call(&self) -> bool { true } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(int_foo_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::()].into_boxed_slice() + } + } + pub fn int_foo_token_callable() -> CallableFunction { + CallableFunction::from_plugin(int_foo_token()) + } + pub fn int_foo_token_input_types() -> Box<[TypeId]> { + int_foo_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_index_getter_fn_module() { let input_tokens: TokenStream = quote! { @@ -1253,6 +1375,73 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn one_index_getter_and_rename_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod one_index_fn { + #[rhai_fn(name = "get", index_get)] + pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT { + x.get(i) + } + } + }; + + let expected_tokens = quote! { + pub mod one_index_fn { + pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT { + x.get(i) + } + #[allow(unused_imports)] + use super::*; + #[allow(unused_mut)] + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + m.set_fn("get", FnAccess::Public, + &[core::any::TypeId::of::(), + core::any::TypeId::of::()], + CallableFunction::from_plugin(get_by_index_token())); + m.set_fn("index$get$", FnAccess::Public, + &[core::any::TypeId::of::(), + core::any::TypeId::of::()], + CallableFunction::from_plugin(get_by_index_token())); + m + } + #[allow(non_camel_case_types)] + struct get_by_index_token(); + impl PluginFunction for get_by_index_token { + fn call(&self, + args: &mut [&mut Dynamic], pos: Position + ) -> Result> { + debug_assert_eq!(args.len(), 2usize, + "wrong arg count: {} != {}", args.len(), 2usize); + let arg1 = mem::take(args[1usize]).clone().cast::(); + let arg0: &mut _ = &mut args[0usize].write_lock::().unwrap(); + Ok(Dynamic::from(get_by_index(arg0, arg1))) + } + + fn is_method_call(&self) -> bool { true } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(get_by_index_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::(), + TypeId::of::()].into_boxed_slice() + } + } + pub fn get_by_index_token_callable() -> CallableFunction { + CallableFunction::from_plugin(get_by_index_token()) + } + pub fn get_by_index_token_input_types() -> Box<[TypeId]> { + get_by_index_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_index_setter_fn_module() { let input_tokens: TokenStream = quote! { @@ -1319,6 +1508,77 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn one_index_setter_and_rename_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod one_index_fn { + #[rhai_fn(name = "set", index_set)] + pub fn set_by_index(x: &mut MyCollection, i: u64, item: FLOAT) { + x.entry(i).set(item) + } + } + }; + + let expected_tokens = quote! { + pub mod one_index_fn { + pub fn set_by_index(x: &mut MyCollection, i: u64, item: FLOAT) { + x.entry(i).set(item) + } + #[allow(unused_imports)] + use super::*; + #[allow(unused_mut)] + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + m.set_fn("set", FnAccess::Public, + &[core::any::TypeId::of::(), + core::any::TypeId::of::(), + core::any::TypeId::of::()], + CallableFunction::from_plugin(set_by_index_token())); + m.set_fn("index$set$", FnAccess::Public, + &[core::any::TypeId::of::(), + core::any::TypeId::of::(), + core::any::TypeId::of::()], + CallableFunction::from_plugin(set_by_index_token())); + m + } + #[allow(non_camel_case_types)] + struct set_by_index_token(); + impl PluginFunction for set_by_index_token { + fn call(&self, + args: &mut [&mut Dynamic], pos: Position + ) -> Result> { + debug_assert_eq!(args.len(), 3usize, + "wrong arg count: {} != {}", args.len(), 3usize); + let arg1 = mem::take(args[1usize]).clone().cast::(); + let arg2 = mem::take(args[2usize]).clone().cast::(); + let arg0: &mut _ = &mut args[0usize].write_lock::().unwrap(); + Ok(Dynamic::from(set_by_index(arg0, arg1, arg2))) + } + + fn is_method_call(&self) -> bool { true } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(set_by_index_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::(), + TypeId::of::(), + TypeId::of::()].into_boxed_slice() + } + } + pub fn set_by_index_token_callable() -> CallableFunction { + CallableFunction::from_plugin(set_by_index_token()) + } + pub fn set_by_index_token_input_types() -> Box<[TypeId]> { + set_by_index_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_constant_nested_module() { let input_tokens: TokenStream = quote! { From 0a2f93439eb5e0d792c6926ece8661ad19b6bd77 Mon Sep 17 00:00:00 2001 From: J Henry Waugh Date: Sat, 12 Sep 2020 22:27:54 -0500 Subject: [PATCH 7/9] Reorganize get/set/index code into FnSpecialAccess --- codegen/src/function.rs | 96 ++++++++++++++++--- codegen/src/rhai_module.rs | 10 +- ...n_rename_collision_oneattr_multiple.stderr | 14 +-- .../rhai_fn_rename_dollar_sign.stderr | 4 +- .../rhai_fn_rename_to_index_getter.stderr | 4 +- .../rhai_fn_rename_to_index_setter.stderr | 4 +- .../rhai_fn_rename_to_prop_getter.stderr | 4 +- .../rhai_fn_rename_to_prop_setter.stderr | 4 +- 8 files changed, 104 insertions(+), 36 deletions(-) diff --git a/codegen/src/function.rs b/codegen/src/function.rs index b96180d2..3b0edee8 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -17,24 +17,43 @@ use syn::{parse::Parse, parse::ParseStream, parse::Parser, spanned::Spanned}; use crate::attrs::{ExportInfo, ExportScope, ExportedParams}; +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Index { + Get, + Set, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Property { + Get(syn::Ident), + Set(syn::Ident), +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum FnSpecialAccess { + None, + Index(Index), + Property(Property), +} + +impl Default for FnSpecialAccess { + fn default() -> FnSpecialAccess { + FnSpecialAccess::None + } +} + #[derive(Debug, Default)] pub(crate) struct ExportedFnParams { pub name: Option>, pub return_raw: bool, pub skip: bool, pub span: Option, + pub special: FnSpecialAccess, } pub const FN_IDX_GET: &str = "index$get$"; pub const FN_IDX_SET: &str = "index$set$"; -pub fn make_getter(id: &str) -> String { - format!("get${}", id) -} -pub fn make_setter(id: &str) -> String { - format!("set${}", id) -} - impl Parse for ExportedFnParams { fn parse(args: ParseStream) -> syn::Result { if args.is_empty() { @@ -63,6 +82,7 @@ impl ExportedParams for ExportedFnParams { let mut name = Vec::new(); let mut return_raw = false; let mut skip = false; + let mut special = FnSpecialAccess::None; for attr in attrs { let crate::attrs::AttrItem { key, value, span: item_span } = attr; match (key.to_string().as_ref(), value) { @@ -98,10 +118,37 @@ impl ExportedParams for ExportedFnParams { ("name", Some(s)) => { name.push(s.value()) }, - ("get", Some(s)) => name.push(make_getter(&s.value())), - ("set", Some(s)) => name.push(make_setter(&s.value())), - ("index_get", None) => name.push(FN_IDX_GET.to_string()), - ("index_set", None) => name.push(FN_IDX_SET.to_string()), + ("set", Some(s)) => special = match special { + FnSpecialAccess::None => + FnSpecialAccess::Property(Property::Set(syn::Ident::new(&s.value(), + s.span()))), + _ => { + return Err(syn::Error::new(item_span.span(), "conflicting setter")) + } + }, + ("get", Some(s)) => special = match special { + FnSpecialAccess::None => + FnSpecialAccess::Property(Property::Get(syn::Ident::new(&s.value(), + s.span()))), + _ => { + return Err(syn::Error::new(item_span.span(), "conflicting getter")) + } + }, + ("index_get", None) => special = match special { + FnSpecialAccess::None => + FnSpecialAccess::Index(Index::Get), + _ => { + return Err(syn::Error::new(item_span.span(), "conflicting index_get")) + } + }, + + ("index_set", None) => special = match special { + FnSpecialAccess::None => + FnSpecialAccess::Index(Index::Set), + _ => { + return Err(syn::Error::new(item_span.span(), "conflicting index_set")) + } + }, ("return_raw", None) => return_raw = true, ("index_get", Some(s)) | ("index_set", Some(s)) | ("return_raw", Some(s)) => { return Err(syn::Error::new(s.span(), "extraneous value")) @@ -121,6 +168,7 @@ impl ExportedParams for ExportedFnParams { name: if name.is_empty() { None } else { Some(name) }, return_raw, skip, + special, span: Some(span), ..Default::default() }) @@ -278,6 +326,32 @@ impl ExportedFn { &self.signature.ident } + pub(crate) fn exported_names(&self) -> Vec { + let mut literals = self.params.name.as_ref() + .map(|v| v.iter() + .map(|s| syn::LitStr::new(s, proc_macro2::Span::call_site())).collect()) + .unwrap_or_else(|| Vec::new()); + + match self.params.special { + FnSpecialAccess::None => {}, + FnSpecialAccess::Property(Property::Get(ref g)) => + literals.push(syn::LitStr::new(&format!("get${}", g.to_string()), g.span())), + FnSpecialAccess::Property(Property::Set(ref s)) => + literals.push(syn::LitStr::new(&format!("set${}", s.to_string()), s.span())), + FnSpecialAccess::Index(Index::Get) => + literals.push(syn::LitStr::new(FN_IDX_GET, proc_macro2::Span::call_site())), + FnSpecialAccess::Index(Index::Set) => + literals.push(syn::LitStr::new(FN_IDX_SET, proc_macro2::Span::call_site())), + } + + if literals.is_empty() { + literals.push(syn::LitStr::new(&self.signature.ident.to_string(), + self.signature.ident.span())); + } + + literals + } + pub(crate) fn exported_name<'n>(&'n self) -> Cow<'n, str> { if let Some(ref name) = self.params.name { Cow::Borrowed(name.last().unwrap().as_str()) diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index 57ec78a8..d318f351 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -67,11 +67,7 @@ pub(crate) fn generate_body( &format!("{}_token", function.name().to_string()), function.name().span(), ); - let reg_names = function - .params() - .name - .clone() - .unwrap_or_else(|| vec![function.name().to_string()]); + let reg_names = function.exported_names(); let fn_input_types: Vec = function .arg_list() @@ -110,9 +106,7 @@ pub(crate) fn generate_body( }) .collect(); - for reg_name in reg_names { - let fn_literal = syn::LitStr::new(®_name, proc_macro2::Span::call_site()); - + for fn_literal in reg_names { set_fn_stmts.push( syn::parse2::(quote! { m.set_fn(#fn_literal, FnAccess::Public, &[#(#fn_input_types),*], diff --git a/codegen/ui_tests/rhai_fn_rename_collision_oneattr_multiple.stderr b/codegen/ui_tests/rhai_fn_rename_collision_oneattr_multiple.stderr index 2f2f6623..77375279 100644 --- a/codegen/ui_tests/rhai_fn_rename_collision_oneattr_multiple.stderr +++ b/codegen/ui_tests/rhai_fn_rename_collision_oneattr_multiple.stderr @@ -1,15 +1,15 @@ -error: duplicate Rhai signature for 'get$bar' - --> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:17:15 - | -17 | #[rhai_fn(get = "bar")] - | ^^^^^^^^^^^ - -error: duplicated function renamed 'get$bar' +error: duplicate Rhai signature for 'foo' --> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:12:15 | 12 | #[rhai_fn(name = "foo", get = "bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error: duplicated function 'foo' + --> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:18:12 + | +18 | pub fn foo(input: Point) -> bool { + | ^^^ + error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:25:8 | diff --git a/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr b/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr index 96f4c4de..3438bdfc 100644 --- a/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr +++ b/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr @@ -4,8 +4,8 @@ error: Rhai function names may not contain dollar sign 12 | #[rhai_fn(name = "big$caching")] | ^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_dollar_sign.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr b/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr index 287283f9..64c11d92 100644 --- a/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr +++ b/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr @@ -4,8 +4,8 @@ error: use attribute 'index_get' instead 12 | #[rhai_fn(name = "index$get$")] | ^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_to_index_getter.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr b/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr index 712f2c59..0d9c9f3d 100644 --- a/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr +++ b/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr @@ -4,8 +4,8 @@ error: use attribute 'index_set' instead 12 | #[rhai_fn(name = "index$set$")] | ^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_to_index_setter.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr b/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr index d9d9b3e8..cee9c66b 100644 --- a/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr +++ b/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr @@ -4,8 +4,8 @@ error: use attribute 'getter = "foo"' instead 12 | #[rhai_fn(name = "get$foo")] | ^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_to_prop_getter.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr b/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr index a1dfbebd..9544ce93 100644 --- a/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr +++ b/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr @@ -4,8 +4,8 @@ error: use attribute 'getter = "foo"' instead 12 | #[rhai_fn(name = "get$foo")] | ^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_to_prop_setter.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` From b1f23ac3edbed26ee18c36047d63ddd3732eee5a Mon Sep 17 00:00:00 2001 From: J Henry Waugh Date: Sat, 12 Sep 2020 22:28:41 -0500 Subject: [PATCH 8/9] Enforce signatures on user get/set/index functions --- codegen/src/function.rs | 58 ++++++++++++++++++- codegen/src/test/module.rs | 46 +++++++++------ codegen/ui_tests/rhai_fn_getter_conflict.rs | 28 +++++++++ .../ui_tests/rhai_fn_getter_conflict.stderr | 11 ++++ codegen/ui_tests/rhai_fn_getter_multiple.rs | 28 +++++++++ .../ui_tests/rhai_fn_getter_multiple.stderr | 11 ++++ codegen/ui_tests/rhai_fn_getter_return.rs | 29 ++++++++++ codegen/ui_tests/rhai_fn_getter_return.stderr | 11 ++++ codegen/ui_tests/rhai_fn_getter_signature.rs | 28 +++++++++ .../ui_tests/rhai_fn_getter_signature.stderr | 11 ++++ .../ui_tests/rhai_fn_index_getter_multiple.rs | 28 +++++++++ .../rhai_fn_index_getter_multiple.stderr | 11 ++++ .../ui_tests/rhai_fn_index_getter_return.rs | 28 +++++++++ .../rhai_fn_index_getter_return.stderr | 11 ++++ .../rhai_fn_index_getter_signature.rs | 28 +++++++++ .../rhai_fn_index_getter_signature.stderr | 11 ++++ .../ui_tests/rhai_fn_index_setter_multiple.rs | 28 +++++++++ .../rhai_fn_index_setter_multiple.stderr | 11 ++++ .../rhai_fn_setter_index_signature.rs | 28 +++++++++ .../rhai_fn_setter_index_signature.stderr | 11 ++++ codegen/ui_tests/rhai_fn_setter_multiple.rs | 28 +++++++++ .../ui_tests/rhai_fn_setter_multiple.stderr | 11 ++++ codegen/ui_tests/rhai_fn_setter_return.rs | 29 ++++++++++ codegen/ui_tests/rhai_fn_setter_return.stderr | 11 ++++ codegen/ui_tests/rhai_fn_setter_signature.rs | 28 +++++++++ .../ui_tests/rhai_fn_setter_signature.stderr | 11 ++++ 26 files changed, 553 insertions(+), 21 deletions(-) create mode 100644 codegen/ui_tests/rhai_fn_getter_conflict.rs create mode 100644 codegen/ui_tests/rhai_fn_getter_conflict.stderr create mode 100644 codegen/ui_tests/rhai_fn_getter_multiple.rs create mode 100644 codegen/ui_tests/rhai_fn_getter_multiple.stderr create mode 100644 codegen/ui_tests/rhai_fn_getter_return.rs create mode 100644 codegen/ui_tests/rhai_fn_getter_return.stderr create mode 100644 codegen/ui_tests/rhai_fn_getter_signature.rs create mode 100644 codegen/ui_tests/rhai_fn_getter_signature.stderr create mode 100644 codegen/ui_tests/rhai_fn_index_getter_multiple.rs create mode 100644 codegen/ui_tests/rhai_fn_index_getter_multiple.stderr create mode 100644 codegen/ui_tests/rhai_fn_index_getter_return.rs create mode 100644 codegen/ui_tests/rhai_fn_index_getter_return.stderr create mode 100644 codegen/ui_tests/rhai_fn_index_getter_signature.rs create mode 100644 codegen/ui_tests/rhai_fn_index_getter_signature.stderr create mode 100644 codegen/ui_tests/rhai_fn_index_setter_multiple.rs create mode 100644 codegen/ui_tests/rhai_fn_index_setter_multiple.stderr create mode 100644 codegen/ui_tests/rhai_fn_setter_index_signature.rs create mode 100644 codegen/ui_tests/rhai_fn_setter_index_signature.stderr create mode 100644 codegen/ui_tests/rhai_fn_setter_multiple.rs create mode 100644 codegen/ui_tests/rhai_fn_setter_multiple.stderr create mode 100644 codegen/ui_tests/rhai_fn_setter_return.rs create mode 100644 codegen/ui_tests/rhai_fn_setter_return.stderr create mode 100644 codegen/ui_tests/rhai_fn_setter_signature.rs create mode 100644 codegen/ui_tests/rhai_fn_setter_signature.stderr diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 3b0edee8..75812dbd 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -377,9 +377,11 @@ impl ExportedFn { } pub fn set_params(&mut self, mut params: ExportedFnParams) -> syn::Result<()> { - // Do not allow non-returning raw functions. + // Several issues are checked here to avoid issues with diagnostics caused by raising them + // later. + // + // 1. Do not allow non-returning raw functions. // - // This is caught now to avoid issues with diagnostics later. if params.return_raw && mem::discriminant(&self.signature.output) == mem::discriminant(&syn::ReturnType::Default) @@ -390,6 +392,58 @@ impl ExportedFn { )); } + match params.special { + // 2a. Property getters must take only the subject as an argument. + FnSpecialAccess::Property(Property::Get(_)) if self.arg_count() != 1 => + return Err(syn::Error::new( + self.signature.span(), + "property getter requires exactly 1 argument", + )), + // 2b. Property getters must return a value. + FnSpecialAccess::Property(Property::Get(_)) if self.return_type().is_none() => + return Err(syn::Error::new( + self.signature.span(), + "property getter must return a value" + )), + // 3a. Property setters must take the subject and a new value as arguments. + FnSpecialAccess::Property(Property::Set(_)) if self.arg_count() != 2 => + return Err(syn::Error::new( + self.signature.span(), + "property setter requires exactly 2 arguments", + )), + // 3b. Property setters must return nothing. + FnSpecialAccess::Property(Property::Set(_)) if self.return_type().is_some() => + return Err(syn::Error::new( + self.signature.span(), + "property setter must return no value" + )), + // 4a. Index getters must take the subject and the accessed "index" as arguments. + FnSpecialAccess::Index(Index::Get) if self.arg_count() != 2 => + return Err(syn::Error::new( + self.signature.span(), + "index getter requires exactly 2 arguments", + )), + // 4b. Index getters must return a value. + FnSpecialAccess::Index(Index::Get) if self.return_type().is_none() => + return Err(syn::Error::new( + self.signature.span(), + "index getter must return a value" + )), + // 5a. Index setters must take the subject, "index", and new value as arguments. + FnSpecialAccess::Index(Index::Set) if self.arg_count() != 3 => + return Err(syn::Error::new( + self.signature.span(), + "index setter requires exactly 3 arguments", + )), + // 5b. Index setters must return nothing. + FnSpecialAccess::Index(Index::Set) if self.return_type().is_some() => + return Err(syn::Error::new( + self.signature.span(), + "index setter must return no value" + )), + _ => {} + } + self.params = params; Ok(()) } diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index e830600e..2bf48752 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -1197,23 +1197,25 @@ mod generate_tests { let input_tokens: TokenStream = quote! { pub mod one_fn { #[rhai_fn(set = "squared")] - pub fn int_foo(x: &mut u64) { - *x = (*x) * (*x) + pub fn int_foo(x: &mut u64, y: u64) { + *x = y * y } } }; let expected_tokens = quote! { pub mod one_fn { - pub fn int_foo(x: &mut u64) { - *x = (*x) * (*x) + pub fn int_foo(x: &mut u64, y: u64) { + *x = y * y } #[allow(unused_imports)] use super::*; #[allow(unused_mut)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); - m.set_fn("set$squared", FnAccess::Public, &[core::any::TypeId::of::()], + m.set_fn("set$squared", FnAccess::Public, + &[core::any::TypeId::of::(), + core::any::TypeId::of::()], CallableFunction::from_plugin(int_foo_token())); m } @@ -1223,10 +1225,11 @@ mod generate_tests { fn call(&self, args: &mut [&mut Dynamic], pos: Position ) -> Result> { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); + debug_assert_eq!(args.len(), 2usize, + "wrong arg count: {} != {}", args.len(), 2usize); + let arg1 = mem::take(args[1usize]).clone().cast::(); let arg0: &mut _ = &mut args[0usize].write_lock::().unwrap(); - Ok(Dynamic::from(int_foo(arg0))) + Ok(Dynamic::from(int_foo(arg0, arg1))) } fn is_method_call(&self) -> bool { true } @@ -1235,7 +1238,7 @@ mod generate_tests { Box::new(int_foo_token()) } fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() + new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } } pub fn int_foo_token_callable() -> CallableFunction { @@ -1256,25 +1259,29 @@ mod generate_tests { let input_tokens: TokenStream = quote! { pub mod one_fn { #[rhai_fn(name = "set_sq", set = "squared")] - pub fn int_foo(x: &mut u64) { - *x = (*x) * (*x) + pub fn int_foo(x: &mut u64, y: u64) { + *x = y * y } } }; let expected_tokens = quote! { pub mod one_fn { - pub fn int_foo(x: &mut u64) { - *x = (*x) * (*x) + pub fn int_foo(x: &mut u64, y: u64) { + *x = y * y } #[allow(unused_imports)] use super::*; #[allow(unused_mut)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); - m.set_fn("set_sq", FnAccess::Public, &[core::any::TypeId::of::()], + m.set_fn("set_sq", FnAccess::Public, + &[core::any::TypeId::of::(), + core::any::TypeId::of::()], CallableFunction::from_plugin(int_foo_token())); - m.set_fn("set$squared", FnAccess::Public, &[core::any::TypeId::of::()], + m.set_fn("set$squared", FnAccess::Public, + &[core::any::TypeId::of::(), + core::any::TypeId::of::()], CallableFunction::from_plugin(int_foo_token())); m } @@ -1284,10 +1291,11 @@ mod generate_tests { fn call(&self, args: &mut [&mut Dynamic], pos: Position ) -> Result> { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); + debug_assert_eq!(args.len(), 2usize, + "wrong arg count: {} != {}", args.len(), 2usize); + let arg1 = mem::take(args[1usize]).clone().cast::(); let arg0: &mut _ = &mut args[0usize].write_lock::().unwrap(); - Ok(Dynamic::from(int_foo(arg0))) + Ok(Dynamic::from(int_foo(arg0, arg1))) } fn is_method_call(&self) -> bool { true } @@ -1296,7 +1304,7 @@ mod generate_tests { Box::new(int_foo_token()) } fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() + new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } } pub fn int_foo_token_callable() -> CallableFunction { diff --git a/codegen/ui_tests/rhai_fn_getter_conflict.rs b/codegen/ui_tests/rhai_fn_getter_conflict.rs new file mode 100644 index 00000000..66cdb9d0 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_getter_conflict.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(name = "foo", get = "foo", set = "bar")] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_getter_conflict.stderr b/codegen/ui_tests/rhai_fn_getter_conflict.stderr new file mode 100644 index 00000000..de276c78 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_getter_conflict.stderr @@ -0,0 +1,11 @@ +error: conflicting setter + --> $DIR/rhai_fn_getter_conflict.rs:12:42 + | +12 | #[rhai_fn(name = "foo", get = "foo", set = "bar")] + | ^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_getter_conflict.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_getter_multiple.rs b/codegen/ui_tests/rhai_fn_getter_multiple.rs new file mode 100644 index 00000000..d60a11ba --- /dev/null +++ b/codegen/ui_tests/rhai_fn_getter_multiple.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(name = "foo", get = "foo", get = "bar")] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_getter_multiple.stderr b/codegen/ui_tests/rhai_fn_getter_multiple.stderr new file mode 100644 index 00000000..d5167326 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_getter_multiple.stderr @@ -0,0 +1,11 @@ +error: conflicting getter + --> $DIR/rhai_fn_getter_multiple.rs:12:42 + | +12 | #[rhai_fn(name = "foo", get = "foo", get = "bar")] + | ^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_getter_multiple.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_getter_return.rs b/codegen/ui_tests/rhai_fn_getter_return.rs new file mode 100644 index 00000000..da7c8454 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_getter_return.rs @@ -0,0 +1,29 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(get = "foo")] + pub fn test_fn(input: &mut Point) { + input.x *= 2.0; + } +} + +fn main() { + let mut n = Point { + x: 0.0, + y: 10.0, + }; + test_module::test_fn(&mut n); + if n.x > 10.0 { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_getter_return.stderr b/codegen/ui_tests/rhai_fn_getter_return.stderr new file mode 100644 index 00000000..6f7a7e40 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_getter_return.stderr @@ -0,0 +1,11 @@ +error: property getter must return a value + --> $DIR/rhai_fn_getter_return.rs:13:9 + | +13 | pub fn test_fn(input: &mut Point) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_getter_return.rs:23:5 + | +23 | test_module::test_fn(&mut n); + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_getter_signature.rs b/codegen/ui_tests/rhai_fn_getter_signature.rs new file mode 100644 index 00000000..c4f1952d --- /dev/null +++ b/codegen/ui_tests/rhai_fn_getter_signature.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(get = "foo")] + pub fn test_fn(input: Point, value: bool) -> bool { + value && input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n, true) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_getter_signature.stderr b/codegen/ui_tests/rhai_fn_getter_signature.stderr new file mode 100644 index 00000000..863757e1 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_getter_signature.stderr @@ -0,0 +1,11 @@ +error: property getter requires exactly 1 argument + --> $DIR/rhai_fn_getter_signature.rs:13:9 + | +13 | pub fn test_fn(input: Point, value: bool) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_getter_signature.rs:23:8 + | +23 | if test_module::test_fn(n, true) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_index_getter_multiple.rs b/codegen/ui_tests/rhai_fn_index_getter_multiple.rs new file mode 100644 index 00000000..450c8aa5 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_index_getter_multiple.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(name = "foo", index_get, index_get)] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_index_getter_multiple.stderr b/codegen/ui_tests/rhai_fn_index_getter_multiple.stderr new file mode 100644 index 00000000..94e8df2e --- /dev/null +++ b/codegen/ui_tests/rhai_fn_index_getter_multiple.stderr @@ -0,0 +1,11 @@ +error: conflicting index_get + --> $DIR/rhai_fn_index_getter_multiple.rs:12:40 + | +12 | #[rhai_fn(name = "foo", index_get, index_get)] + | ^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_index_getter_multiple.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_index_getter_return.rs b/codegen/ui_tests/rhai_fn_index_getter_return.rs new file mode 100644 index 00000000..32b8c3ee --- /dev/null +++ b/codegen/ui_tests/rhai_fn_index_getter_return.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(index_get)] + pub fn test_fn(input: &mut Point, i: f32) { + input.x *= 2.0; + } +} + +fn main() { + let mut n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(&mut n, 5.0) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_index_getter_return.stderr b/codegen/ui_tests/rhai_fn_index_getter_return.stderr new file mode 100644 index 00000000..cb4c020f --- /dev/null +++ b/codegen/ui_tests/rhai_fn_index_getter_return.stderr @@ -0,0 +1,11 @@ +error: index getter must return a value + --> $DIR/rhai_fn_index_getter_return.rs:13:9 + | +13 | pub fn test_fn(input: &mut Point, i: f32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_index_getter_return.rs:23:8 + | +23 | if test_module::test_fn(&mut n, 5.0) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_index_getter_signature.rs b/codegen/ui_tests/rhai_fn_index_getter_signature.rs new file mode 100644 index 00000000..e6fe68f5 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_index_getter_signature.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(index_get)] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_index_getter_signature.stderr b/codegen/ui_tests/rhai_fn_index_getter_signature.stderr new file mode 100644 index 00000000..efdcff4a --- /dev/null +++ b/codegen/ui_tests/rhai_fn_index_getter_signature.stderr @@ -0,0 +1,11 @@ +error: index getter requires exactly 2 arguments + --> $DIR/rhai_fn_index_getter_signature.rs:13:9 + | +13 | pub fn test_fn(input: Point) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_index_getter_signature.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_index_setter_multiple.rs b/codegen/ui_tests/rhai_fn_index_setter_multiple.rs new file mode 100644 index 00000000..77d8cf3e --- /dev/null +++ b/codegen/ui_tests/rhai_fn_index_setter_multiple.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(name = "foo", index_set, index_set)] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_index_setter_multiple.stderr b/codegen/ui_tests/rhai_fn_index_setter_multiple.stderr new file mode 100644 index 00000000..5a6de59d --- /dev/null +++ b/codegen/ui_tests/rhai_fn_index_setter_multiple.stderr @@ -0,0 +1,11 @@ +error: conflicting index_set + --> $DIR/rhai_fn_index_setter_multiple.rs:12:40 + | +12 | #[rhai_fn(name = "foo", index_set, index_set)] + | ^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_index_setter_multiple.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_setter_index_signature.rs b/codegen/ui_tests/rhai_fn_setter_index_signature.rs new file mode 100644 index 00000000..21a71846 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_setter_index_signature.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(index_set)] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_setter_index_signature.stderr b/codegen/ui_tests/rhai_fn_setter_index_signature.stderr new file mode 100644 index 00000000..c4123d51 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_setter_index_signature.stderr @@ -0,0 +1,11 @@ +error: index setter requires exactly 3 arguments + --> $DIR/rhai_fn_setter_index_signature.rs:13:9 + | +13 | pub fn test_fn(input: Point) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_setter_index_signature.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_setter_multiple.rs b/codegen/ui_tests/rhai_fn_setter_multiple.rs new file mode 100644 index 00000000..170a373c --- /dev/null +++ b/codegen/ui_tests/rhai_fn_setter_multiple.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(name = "foo", set = "foo", set = "bar")] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_setter_multiple.stderr b/codegen/ui_tests/rhai_fn_setter_multiple.stderr new file mode 100644 index 00000000..aa4553ec --- /dev/null +++ b/codegen/ui_tests/rhai_fn_setter_multiple.stderr @@ -0,0 +1,11 @@ +error: conflicting setter + --> $DIR/rhai_fn_setter_multiple.rs:12:42 + | +12 | #[rhai_fn(name = "foo", set = "foo", set = "bar")] + | ^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_setter_multiple.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_setter_return.rs b/codegen/ui_tests/rhai_fn_setter_return.rs new file mode 100644 index 00000000..5a2542a8 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_setter_return.rs @@ -0,0 +1,29 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(set = "foo")] + pub fn test_fn(input: &mut Point, value: f32) -> bool { + let z = if value % 2 { input.x } else { input.y }; + *input.x = z; + } +} + +fn main() { + let mut n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(&mut n, 5.0) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_setter_return.stderr b/codegen/ui_tests/rhai_fn_setter_return.stderr new file mode 100644 index 00000000..383b6711 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_setter_return.stderr @@ -0,0 +1,11 @@ +error: property setter must return no value + --> $DIR/rhai_fn_setter_return.rs:13:9 + | +13 | pub fn test_fn(input: &mut Point, value: f32) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_setter_return.rs:24:8 + | +24 | if test_module::test_fn(&mut n, 5.0) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_setter_signature.rs b/codegen/ui_tests/rhai_fn_setter_signature.rs new file mode 100644 index 00000000..06e401a6 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_setter_signature.rs @@ -0,0 +1,28 @@ +use rhai::plugin::*; + +#[derive(Clone)] +pub struct Point { + x: f32, + y: f32, +} + +#[export_module] +pub mod test_module { + pub use super::Point; + #[rhai_fn(set = "foo")] + pub fn test_fn(input: Point) -> bool { + input.x > input.y + } +} + +fn main() { + let n = Point { + x: 0.0, + y: 10.0, + }; + if test_module::test_fn(n) { + println!("yes"); + } else { + println!("no"); + } +} diff --git a/codegen/ui_tests/rhai_fn_setter_signature.stderr b/codegen/ui_tests/rhai_fn_setter_signature.stderr new file mode 100644 index 00000000..719663f2 --- /dev/null +++ b/codegen/ui_tests/rhai_fn_setter_signature.stderr @@ -0,0 +1,11 @@ +error: property setter requires exactly 2 arguments + --> $DIR/rhai_fn_setter_signature.rs:13:9 + | +13 | pub fn test_fn(input: Point) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared type or module `test_module` + --> $DIR/rhai_fn_setter_signature.rs:23:8 + | +23 | if test_module::test_fn(n) { + | ^^^^^^^^^^^ use of undeclared type or module `test_module` From 381e80179e0696b3e621cfac8345d0e7ce71b86c Mon Sep 17 00:00:00 2001 From: J Henry Waugh Date: Sat, 12 Sep 2020 22:57:17 -0500 Subject: [PATCH 9/9] Re-bless ui tests --- codegen/ui_tests/rhai_fn_getter_conflict.stderr | 4 ++-- codegen/ui_tests/rhai_fn_getter_multiple.stderr | 4 ++-- codegen/ui_tests/rhai_fn_getter_return.stderr | 4 ++-- codegen/ui_tests/rhai_fn_getter_signature.stderr | 4 ++-- codegen/ui_tests/rhai_fn_index_getter_multiple.stderr | 4 ++-- codegen/ui_tests/rhai_fn_index_getter_return.stderr | 4 ++-- codegen/ui_tests/rhai_fn_index_getter_signature.stderr | 4 ++-- codegen/ui_tests/rhai_fn_index_setter_multiple.stderr | 4 ++-- codegen/ui_tests/rhai_fn_setter_index_signature.stderr | 4 ++-- codegen/ui_tests/rhai_fn_setter_multiple.stderr | 4 ++-- codegen/ui_tests/rhai_fn_setter_return.stderr | 4 ++-- codegen/ui_tests/rhai_fn_setter_signature.stderr | 4 ++-- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/codegen/ui_tests/rhai_fn_getter_conflict.stderr b/codegen/ui_tests/rhai_fn_getter_conflict.stderr index de276c78..b1011bc6 100644 --- a/codegen/ui_tests/rhai_fn_getter_conflict.stderr +++ b/codegen/ui_tests/rhai_fn_getter_conflict.stderr @@ -4,8 +4,8 @@ error: conflicting setter 12 | #[rhai_fn(name = "foo", get = "foo", set = "bar")] | ^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_getter_conflict.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_getter_multiple.stderr b/codegen/ui_tests/rhai_fn_getter_multiple.stderr index d5167326..b37aca65 100644 --- a/codegen/ui_tests/rhai_fn_getter_multiple.stderr +++ b/codegen/ui_tests/rhai_fn_getter_multiple.stderr @@ -4,8 +4,8 @@ error: conflicting getter 12 | #[rhai_fn(name = "foo", get = "foo", get = "bar")] | ^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_getter_multiple.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_getter_return.stderr b/codegen/ui_tests/rhai_fn_getter_return.stderr index 6f7a7e40..9dad293b 100644 --- a/codegen/ui_tests/rhai_fn_getter_return.stderr +++ b/codegen/ui_tests/rhai_fn_getter_return.stderr @@ -4,8 +4,8 @@ error: property getter must return a value 13 | pub fn test_fn(input: &mut Point) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_getter_return.rs:23:5 | 23 | test_module::test_fn(&mut n); - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_getter_signature.stderr b/codegen/ui_tests/rhai_fn_getter_signature.stderr index 863757e1..0689c83f 100644 --- a/codegen/ui_tests/rhai_fn_getter_signature.stderr +++ b/codegen/ui_tests/rhai_fn_getter_signature.stderr @@ -4,8 +4,8 @@ error: property getter requires exactly 1 argument 13 | pub fn test_fn(input: Point, value: bool) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_getter_signature.rs:23:8 | 23 | if test_module::test_fn(n, true) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_index_getter_multiple.stderr b/codegen/ui_tests/rhai_fn_index_getter_multiple.stderr index 94e8df2e..30cc273d 100644 --- a/codegen/ui_tests/rhai_fn_index_getter_multiple.stderr +++ b/codegen/ui_tests/rhai_fn_index_getter_multiple.stderr @@ -4,8 +4,8 @@ error: conflicting index_get 12 | #[rhai_fn(name = "foo", index_get, index_get)] | ^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_index_getter_multiple.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_index_getter_return.stderr b/codegen/ui_tests/rhai_fn_index_getter_return.stderr index cb4c020f..b8da178e 100644 --- a/codegen/ui_tests/rhai_fn_index_getter_return.stderr +++ b/codegen/ui_tests/rhai_fn_index_getter_return.stderr @@ -4,8 +4,8 @@ error: index getter must return a value 13 | pub fn test_fn(input: &mut Point, i: f32) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_index_getter_return.rs:23:8 | 23 | if test_module::test_fn(&mut n, 5.0) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_index_getter_signature.stderr b/codegen/ui_tests/rhai_fn_index_getter_signature.stderr index efdcff4a..7e86413e 100644 --- a/codegen/ui_tests/rhai_fn_index_getter_signature.stderr +++ b/codegen/ui_tests/rhai_fn_index_getter_signature.stderr @@ -4,8 +4,8 @@ error: index getter requires exactly 2 arguments 13 | pub fn test_fn(input: Point) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_index_getter_signature.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_index_setter_multiple.stderr b/codegen/ui_tests/rhai_fn_index_setter_multiple.stderr index 5a6de59d..1e45346d 100644 --- a/codegen/ui_tests/rhai_fn_index_setter_multiple.stderr +++ b/codegen/ui_tests/rhai_fn_index_setter_multiple.stderr @@ -4,8 +4,8 @@ error: conflicting index_set 12 | #[rhai_fn(name = "foo", index_set, index_set)] | ^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_index_setter_multiple.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_setter_index_signature.stderr b/codegen/ui_tests/rhai_fn_setter_index_signature.stderr index c4123d51..80cfc5fb 100644 --- a/codegen/ui_tests/rhai_fn_setter_index_signature.stderr +++ b/codegen/ui_tests/rhai_fn_setter_index_signature.stderr @@ -4,8 +4,8 @@ error: index setter requires exactly 3 arguments 13 | pub fn test_fn(input: Point) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_setter_index_signature.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_setter_multiple.stderr b/codegen/ui_tests/rhai_fn_setter_multiple.stderr index aa4553ec..6783fb1a 100644 --- a/codegen/ui_tests/rhai_fn_setter_multiple.stderr +++ b/codegen/ui_tests/rhai_fn_setter_multiple.stderr @@ -4,8 +4,8 @@ error: conflicting setter 12 | #[rhai_fn(name = "foo", set = "foo", set = "bar")] | ^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_setter_multiple.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_setter_return.stderr b/codegen/ui_tests/rhai_fn_setter_return.stderr index 383b6711..db37a80f 100644 --- a/codegen/ui_tests/rhai_fn_setter_return.stderr +++ b/codegen/ui_tests/rhai_fn_setter_return.stderr @@ -4,8 +4,8 @@ error: property setter must return no value 13 | pub fn test_fn(input: &mut Point, value: f32) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_setter_return.rs:24:8 | 24 | if test_module::test_fn(&mut n, 5.0) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_setter_signature.stderr b/codegen/ui_tests/rhai_fn_setter_signature.stderr index 719663f2..55127a25 100644 --- a/codegen/ui_tests/rhai_fn_setter_signature.stderr +++ b/codegen/ui_tests/rhai_fn_setter_signature.stderr @@ -4,8 +4,8 @@ error: property setter requires exactly 2 arguments 13 | pub fn test_fn(input: Point) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_setter_signature.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module`