From 75f5bbd711cd8b4d21ecd9f69a1ac21c215e705a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 14 Jan 2020 16:43:31 +0100 Subject: [PATCH] Improve error reporting, add a test. --- datapond-derive/tests/fail/arg_mismatch.rs | 11 ++++++ .../tests/fail/arg_mismatch.stderr | 11 ++++++ datapond-derive/tests/test.rs | 1 + src/typechecker.rs | 35 +++++++++++++------ 4 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 datapond-derive/tests/fail/arg_mismatch.rs create mode 100644 datapond-derive/tests/fail/arg_mismatch.stderr diff --git a/datapond-derive/tests/fail/arg_mismatch.rs b/datapond-derive/tests/fail/arg_mismatch.rs new file mode 100644 index 0000000..a8f3a03 --- /dev/null +++ b/datapond-derive/tests/fail/arg_mismatch.rs @@ -0,0 +1,11 @@ +use datapond_derive::datapond; + +fn main() { + let inp = vec![(1, 2), (2, 3)]; + let out; + datapond! { + input inp(x: u32, y: u32, z: u32) + output out(x: u32, y: u32) + out(x, y) :- inp(y, x). + }; +} diff --git a/datapond-derive/tests/fail/arg_mismatch.stderr b/datapond-derive/tests/fail/arg_mismatch.stderr new file mode 100644 index 0000000..9e6f671 --- /dev/null +++ b/datapond-derive/tests/fail/arg_mismatch.stderr @@ -0,0 +1,11 @@ +error: Wrong number of arguments for inp: expected 2, found 3. + --> $DIR/arg_mismatch.rs:9:22 + | +9 | out(x, y) :- inp(y, x). + | ^^^ + +error: The predicate inp was declared here. + --> $DIR/arg_mismatch.rs:7:15 + | +7 | input inp(x: u32, y: u32, z: u32) + | ^^^ diff --git a/datapond-derive/tests/test.rs b/datapond-derive/tests/test.rs index 135782a..35ec0e5 100644 --- a/datapond-derive/tests/test.rs +++ b/datapond-derive/tests/test.rs @@ -2,4 +2,5 @@ fn tests() { let runner = trybuild::TestCases::new(); runner.pass("tests/pass/*.rs"); + runner.compile_fail("tests/fail/*.rs"); } diff --git a/src/typechecker.rs b/src/typechecker.rs index 39ebbf2..97665b0 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -9,7 +9,7 @@ use std::fmt; pub struct Error { pub msg: String, pub span: Span, - pub hint_span: Option, + pub hint: Option<(String, Span)>, } impl Error { @@ -17,26 +17,34 @@ impl Error { Self { msg: msg, span: span, - hint_span: None, + hint: None, } } - fn with_hint_span(msg: String, span: Span, hint_span: Span) -> Self { + fn with_hint_span(msg: String, span: Span, hint_msg: String, hint_span: Span) -> Self { Self { msg: msg, span: span, - hint_span: Some(hint_span), + hint: Some((hint_msg, hint_span)), } } + pub fn to_syn_error(&self) -> syn::Error { + let mut error = syn::Error::new(self.span, &self.msg); + if let Some((hint_msg, hint_span)) = &self.hint { + error.combine(syn::Error::new(hint_span.clone(), hint_msg)); + } + error + } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(hint_span) = self.hint_span { + if let Some((hint_msg, hint_span)) = &self.hint { write!( f, - "{} at {:?} (hint: {:?})", + "{} at {:?} ({} at {:?})", self.msg, self.span.start(), + hint_msg, hint_span.start() ) } else { @@ -57,13 +65,15 @@ fn check_head( })?; if head.args.len() != decl.parameters.len() { let msg = format!( - "Wrong number of arguments: expected {}, found {}.", + "Wrong number of arguments for {}: expected {}, found {}.", + head.predicate, + decl.parameters.len(), head.args.len(), - decl.parameters.len() ); return Err(Error::with_hint_span( msg, head.predicate.span(), + format!("The predicate {} was declared here.", head.predicate), decl.name.span(), )); } @@ -86,13 +96,15 @@ fn check_body( past::ArgList::Positional(positional_args) => { if positional_args.len() != decl.parameters.len() { let msg = format!( - "Wrong number of arguments: expected {}, found {}.", + "Wrong number of arguments for {}: expected {}, found {}.", + literal.predicate, positional_args.len(), decl.parameters.len() ); return Err(Error::with_hint_span( msg, literal.predicate.span(), + format!("The predicate {} was declared here.", decl.name), decl.name.span(), )); } @@ -131,8 +143,11 @@ fn check_body( } for key in kwargs.keys() { if !used_parameters.contains(key) { + let available_parameters: Vec<_> = used_parameters.iter().map(|parameter| parameter.to_string()).collect(); return Err(Error::new( - format!("Unknown parameter {} in predicate.", key), + format!("Unknown parameter {} in predicate {}. Available parameters are: {}.", + key, literal.predicate, available_parameters.join(","), + ), literal.predicate.span(), )); }