Merge pull request #45 from jhwgh1968/diagnostic_improvements

Diagnostic improvements for Codegen Macros
This commit is contained in:
Stephen Chung 2020-08-28 16:41:52 +08:00 committed by GitHub
commit 0a3b5e2bc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 561 additions and 17 deletions

View File

@ -111,7 +111,7 @@ pub(crate) struct ExportedFn {
signature: syn::Signature,
is_public: bool,
mut_receiver: bool,
pub params: ExportedFnParams,
params: ExportedFnParams,
}
impl Parse for ExportedFn {
@ -218,6 +218,14 @@ impl Parse for ExportedFn {
}
impl ExportedFn {
pub(crate) fn params(&self) -> &ExportedFnParams {
&self.params
}
pub(crate) fn skipped(&self) -> bool {
self.params.skip
}
pub(crate) fn mutable_receiver(&self) -> bool {
self.mut_receiver
}
@ -314,15 +322,17 @@ impl ExportedFn {
})
.collect();
let return_span = self.return_type().map(|r| r.span())
.unwrap_or_else(|| proc_macro2::Span::call_site());
if !self.params.return_raw {
quote! {
quote_spanned! { return_span=>
type EvalBox = Box<EvalAltResult>;
pub #dynamic_signature {
Ok(Dynamic::from(super::#name(#(#arguments),*)))
}
}
} else {
quote_spanned! { self.return_type().unwrap().span()=>
quote_spanned! { return_span=>
type EvalBox = Box<EvalAltResult>;
pub #dynamic_signature {
super::#name(#(#arguments),*)
@ -484,12 +494,14 @@ impl ExportedFn {
// Handle "raw returns", aka cases where the result is a dynamic or an error.
//
// This allows skipping the Dynamic::from wrap.
let return_span = self.return_type().map(|r| r.span())
.unwrap_or_else(|| proc_macro2::Span::call_site());
let return_expr = if !self.params.return_raw {
quote! {
quote_spanned! { return_span=>
Ok(Dynamic::from(#sig_name(#(#unpack_exprs),*)))
}
} else {
quote_spanned! { self.return_type().unwrap().span()=>
quote_spanned! { return_span=>
#sig_name(#(#unpack_exprs),*)
}
};

View File

@ -112,9 +112,9 @@ impl Parse for Module {
true
};
syn::parse2::<ExportedFn>(itemfn.to_token_stream())
.map(|mut f| {
f.params = params;
f
.and_then(|mut f| {
f.set_params(params)?;
Ok(f)
})
.map(|f| vec.push(f))
.map(|_| vec)
@ -411,7 +411,7 @@ mod module_tests {
assert!(item_mod.consts.is_empty());
assert_eq!(item_mod.submodules.len(), 1);
assert_eq!(item_mod.submodules[0].fns.len(), 1);
assert!(item_mod.submodules[0].fns[0].params.skip);
assert!(item_mod.submodules[0].fns[0].skipped());
assert!(item_mod.submodules[0].consts.is_empty());
assert!(item_mod.submodules[0].submodules.is_empty());
}
@ -433,7 +433,7 @@ mod module_tests {
assert!(item_mod.fns.is_empty());
assert!(item_mod.consts.is_empty());
assert_eq!(item_mod.submodules.len(), 1);
assert!(item_mod.submodules[0].params.skip);
assert!(item_mod.submodules[0].skipped());
}
#[test]
@ -466,7 +466,7 @@ mod module_tests {
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
assert_eq!(item_mod.fns.len(), 1);
assert!(item_mod.fns[0].params.skip);
assert!(item_mod.fns[0].skipped());
assert!(item_mod.consts.is_empty());
}
@ -483,7 +483,7 @@ mod module_tests {
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
assert_eq!(item_mod.fns.len(), 1);
assert!(item_mod.fns[0].params.skip);
assert!(item_mod.fns[0].skipped());
assert!(item_mod.consts.is_empty());
}

View File

@ -56,7 +56,7 @@ pub(crate) fn generate_body(
// NB: these are token streams, because reparsing messes up "> >" vs ">>"
let mut gen_fn_tokens: Vec<proc_macro2::TokenStream> = Vec::new();
for function in fns {
if function.params.skip {
if function.skipped() {
continue;
}
let fn_token_name = syn::Ident::new(
@ -64,7 +64,7 @@ pub(crate) fn generate_body(
function.name().span(),
);
let reg_name = function
.params
.params()
.name
.clone()
.unwrap_or_else(|| function.name().to_string());
@ -151,8 +151,8 @@ pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::
let mut renames = HashMap::<String, proc_macro2::Span>::new();
let mut names = HashMap::<String, proc_macro2::Span>::new();
for itemfn in fns.iter() {
if let Some(ref name) = itemfn.params.name {
let current_span = itemfn.params.span.as_ref().unwrap();
if let Some(ref name) = itemfn.params().name {
let current_span = itemfn.params().span.as_ref().unwrap();
let key = itemfn.arg_list().fold(name.clone(), |mut argstr, fnarg| {
let type_string: String = match fnarg {
syn::FnArg::Receiver(_) => unimplemented!("receiver rhai_fns not implemented"),
@ -177,7 +177,17 @@ pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::
}
} else {
let ident = itemfn.name();
names.insert(ident.to_string(), ident.span());
if let Some(other_span) = names.insert(ident.to_string(), ident.span()) {
let mut err = syn::Error::new(
ident.span(),
format!("duplicate function '{}'", ident.to_string()),
);
err.combine(syn::Error::new(
other_span,
format!("duplicated function '{}'", ident.to_string()),
));
return Err(err);
}
}
}
for (new_name, attr_span) in renames.drain() {

View File

@ -0,0 +1,27 @@
use rhai::plugin::*;
#[derive(Clone)]
struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_mod {
#[rhai_fn(unknown = "thing")]
pub fn test_fn(input: Point) -> bool {
input.x > input.y
}
}
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
};
if test_mod::test_fn(n) {
println!("yes");
} else {
println!("no");
}
}

View File

@ -0,0 +1,11 @@
error: unknown attribute 'unknown'
--> $DIR/export_mod_bad_attr.rs:11:11
|
11 | #[rhai_fn(unknown = "thing")]
| ^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
--> $DIR/export_mod_bad_attr.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`

View File

@ -0,0 +1,27 @@
use rhai::plugin::*;
#[derive(Clone)]
struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_mod {
#[rhai_fn(name = true)]
pub fn test_fn(input: Point) -> bool {
input.x > input.y
}
}
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
};
if test_mod::test_fn(n) {
println!("yes");
} else {
println!("no");
}
}

View File

@ -0,0 +1,11 @@
error: expecting string literal
--> $DIR/export_mod_bad_value.rs:11:18
|
11 | #[rhai_fn(name = true)]
| ^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
--> $DIR/export_mod_bad_value.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`

View File

@ -0,0 +1,28 @@
use rhai::plugin::*;
#[derive(Clone)]
pub struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_mod {
#[cfg(not(feature = "foo"))]
#[rhai_fn]
pub fn test_fn(input: Point) -> bool {
input.x > input.y
}
}
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
};
if test_mod::test_fn(n) {
println!("yes");
} else {
println!("no");
}
}

View File

@ -0,0 +1,11 @@
error: cfg attributes not allowed on this item
--> $DIR/export_mod_cfg.rs:11:1
|
11 | #[cfg(not(feature = "foo"))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
--> $DIR/export_mod_cfg.rs:23:8
|
23 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`

View File

@ -0,0 +1,27 @@
use rhai::plugin::*;
#[derive(Clone)]
struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_mod {
#[rhai_fn(return_raw = "yes")]
pub fn test_fn(input: Point) -> bool {
input.x > input.y
}
}
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
};
if test_mod::test_fn(n) {
println!("yes");
} else {
println!("no");
}
}

View File

@ -0,0 +1,11 @@
error: extraneous value
--> $DIR/export_mod_extra_value.rs:11:24
|
11 | #[rhai_fn(return_raw = "yes")]
| ^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
--> $DIR/export_mod_extra_value.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`

View File

@ -0,0 +1,27 @@
use rhai::plugin::*;
#[derive(Clone)]
struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_mod {
#[rhai_fn("wheeeee")]
pub fn test_fn(input: Point) -> bool {
input.x > input.y
}
}
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
};
if test_mod::test_fn(n) {
println!("yes");
} else {
println!("no");
}
}

View File

@ -0,0 +1,11 @@
error: expecting identifier
--> $DIR/export_mod_junk_arg.rs:11:11
|
11 | #[rhai_fn("wheeeee")]
| ^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
--> $DIR/export_mod_junk_arg.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`

View File

@ -0,0 +1,27 @@
use rhai::plugin::*;
#[derive(Clone)]
struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_mod {
#[rhai_fn(name)]
pub fn test_fn(input: Point) -> bool {
input.x > input.y
}
}
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
};
if test_mod::test_fn(n) {
println!("yes");
} else {
println!("no");
}
}

View File

@ -0,0 +1,11 @@
error: requires value
--> $DIR/export_mod_missing_value.rs:11:11
|
11 | #[rhai_fn(name)]
| ^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
--> $DIR/export_mod_missing_value.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`

View File

@ -0,0 +1,27 @@
use rhai::plugin::*;
#[derive(Clone)]
struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_mod {
#[rhai_fn(rhai::name = "thing")]
pub fn test_fn(input: Point) -> bool {
input.x > input.y
}
}
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
};
if test_mod::test_fn(n) {
println!("yes");
} else {
println!("no");
}
}

View File

@ -0,0 +1,11 @@
error: expecting attribute name
--> $DIR/export_mod_path_attr.rs:11:11
|
11 | #[rhai_fn(rhai::name = "thing")]
| ^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
--> $DIR/export_mod_path_attr.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`

View File

@ -0,0 +1,28 @@
use rhai::plugin::*;
#[derive(Clone)]
struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_mod {
#[rhai_fn(return_raw)]
pub fn test_fn(input: &mut Point) {
input.x += 1.0;
}
}
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
};
test_mod::test_fn(&mut n);
if n.x >= 10.0 {
println!("yes");
} else {
println!("no");
}
}

View File

@ -0,0 +1,11 @@
error: return_raw functions must return Result<T>
--> $DIR/export_mod_raw_noreturn.rs:12:5
|
12 | pub fn test_fn(input: &mut Point) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
--> $DIR/export_mod_raw_noreturn.rs:22:5
|
22 | test_mod::test_fn(&mut n);
| ^^^^^^^^ use of undeclared type or module `test_mod`

View File

@ -0,0 +1,27 @@
use rhai::plugin::*;
#[derive(Clone)]
struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_mod {
#[rhai_fn(return_raw)]
pub fn test_fn(input: Point) -> bool {
input.x > input.y
}
}
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
};
if test_mod::test_fn(n) {
println!("yes");
} else {
println!("no");
}
}

View File

@ -0,0 +1,11 @@
error[E0308]: mismatched types
--> $DIR/export_mod_raw_return.rs:12:8
|
9 | #[export_module]
| ---------------- expected `std::result::Result<rhai::Dynamic, std::boxed::Box<rhai::EvalAltResult>>` because of return type
...
12 | pub fn test_fn(input: Point) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `bool`
|
= note: expected enum `std::result::Result<rhai::Dynamic, std::boxed::Box<rhai::EvalAltResult>>`
found type `bool`

View File

@ -0,0 +1,31 @@
use rhai::plugin::*;
#[derive(Clone)]
pub struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_module {
pub use super::Point;
pub fn test_fn(input: Point) -> bool {
input.x > input.y
}
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");
}
}

View File

@ -0,0 +1,17 @@
error: duplicate function 'test_fn'
--> $DIR/rhai_mod_name_collisions.rs:16:12
|
16 | pub fn test_fn(input: Point) -> bool {
| ^^^^^^^
error: duplicated function 'test_fn'
--> $DIR/rhai_mod_name_collisions.rs:12:12
|
12 | pub fn test_fn(input: Point) -> bool {
| ^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
--> $DIR/rhai_mod_name_collisions.rs:26:8
|
26 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`

View File

@ -0,0 +1,27 @@
use rhai::plugin::*;
#[derive(Clone)]
pub struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_module {
pub use super::Point;
pub fn test_fn(input: Pointer) -> 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");
}
}

View File

@ -0,0 +1,23 @@
error[E0412]: cannot find type `Pointer` in this scope
--> $DIR/rhai_mod_unknown_type.rs:12:27
|
4 | pub struct Point {
| ---------------- similarly named struct `Point` defined here
...
12 | pub fn test_fn(input: Pointer) -> bool {
| ^^^^^^^
|
help: a struct with a similar name exists
|
12 | pub fn test_fn(input: Point) -> bool {
| ^^^^^
help: consider importing one of these items
|
11 | use core::fmt::Pointer;
|
11 | use crate::mem::fmt::Pointer;
|
11 | use std::fmt::Pointer;
|
11 | use syn::export::fmt::Pointer;
|

View File

@ -0,0 +1,27 @@
use rhai::plugin::*;
#[derive(Clone)]
pub struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_module {
pub use super::Point;
pub fn test_fn(input: Point) -> boool {
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");
}
}

View File

@ -0,0 +1,5 @@
error[E0412]: cannot find type `boool` in this scope
--> $DIR/rhai_mod_unknown_type_return.rs:12:37
|
12 | pub fn test_fn(input: Point) -> boool {
| ^^^^^ help: a builtin type with a similar name exists: `bool`

13
diag_test/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "diag_test"
version = "0.1.0"
authors = ["J Henry Waugh <jhwgh1968@protonmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "test_template"
path = "test_template.rs"
[dependencies]
rhai = { version = "*", path = ".." }

View File

@ -0,0 +1,35 @@
use rhai::plugin::*;
#[derive(Clone)]
pub struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_module {
#[rhai_mod(name = "bar")]
pub mod test_mod {
#[rhai_fn(name = "foo")]
pub fn test_fn(input: Point) -> bool {
input.x > input.y
}
#[rhai_fn(return_raw)]
pub fn test_fn_raw(input: Point) -> Result<rhai::Dynamic, Box<rhai::EvalAltResult>> {
Ok(Dynamic::from(input.x > input.y))
}
}
}
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
};
if test_module::test_mod::test_fn(n) {
println!("yes");
} else {
println!("no");
}
}