summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadrieril2019-11-11 12:43:09 +0000
committerNadrieril2019-11-11 13:50:36 +0000
commit330f063e80a51f8f399864f9d01412e1bff34fe9 (patch)
treed008005efc57222c0b33f5069c6ce8576cc7bd43
parent5d5a356b8eb36e277c312e5550d1cb0a2f82e9fa (diff)
Display first pretty type error
Diffstat (limited to '')
-rw-r--r--dhall/src/error/mod.rs8
-rw-r--r--dhall/src/phase/typecheck.rs2
-rw-r--r--dhall/src/tests.rs25
-rw-r--r--dhall/tests/type-errors/unit/AssertAlphaTrap.txt7
-rw-r--r--dhall/tests/type-errors/unit/UnionDeprecatedConstructorsKeyword.txt7
-rw-r--r--dhall/tests/type-errors/unit/VariableFree.txt7
-rw-r--r--dhall_syntax/src/core/span.rs14
7 files changed, 61 insertions, 9 deletions
diff --git a/dhall/src/error/mod.rs b/dhall/src/error/mod.rs
index 5338e2d..efbd578 100644
--- a/dhall/src/error/mod.rs
+++ b/dhall/src/error/mod.rs
@@ -1,6 +1,6 @@
use std::io::Error as IOError;
-use dhall_syntax::{BinOp, Import, Label, ParseError, V};
+use dhall_syntax::{BinOp, Import, Label, ParseError, Span};
use crate::core::context::TypecheckContext;
use crate::core::value::Value;
@@ -48,7 +48,7 @@ pub struct TypeError {
/// The specific type error
#[derive(Debug)]
pub(crate) enum TypeMessage {
- UnboundVariable(V<Label>),
+ UnboundVariable(Span),
InvalidInputType(Value),
InvalidOutputType(Value),
NotAFunction(Value),
@@ -102,8 +102,8 @@ impl TypeError {
impl std::fmt::Display for TypeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use TypeMessage::*;
- let msg = match self.message {
- UnboundVariable(_) => "Unbound variable".to_string(),
+ let msg = match &self.message {
+ UnboundVariable(span) => span.error("Unbound variable"),
InvalidInputType(_) => "Invalid function input".to_string(),
InvalidOutputType(_) => "Invalid function output".to_string(),
NotAFunction(_) => "Not a function".to_string(),
diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs
index 63f5157..9d2c69b 100644
--- a/dhall/src/phase/typecheck.rs
+++ b/dhall/src/phase/typecheck.rs
@@ -339,7 +339,7 @@ fn type_with(
None => {
return Err(TypeError::new(
ctx,
- TypeMessage::UnboundVariable(var.clone()),
+ TypeMessage::UnboundVariable(span),
))
}
},
diff --git a/dhall/src/tests.rs b/dhall/src/tests.rs
index 9790b95..cde3b03 100644
--- a/dhall/src/tests.rs
+++ b/dhall/src/tests.rs
@@ -20,6 +20,29 @@ right: `{}`"#,
}};
}
+/// Wrapper around string slice that makes debug output `{:?}` to print string same way as `{}`.
+/// Used in different `assert*!` macros in combination with `pretty_assertions` crate to make
+/// test failures to show nice diffs.
+#[derive(PartialEq, Eq)]
+#[doc(hidden)]
+pub struct PrettyString(String);
+
+/// Make diff to display string as multi-line string
+impl std::fmt::Debug for PrettyString {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ f.write_str(&self.0)
+ }
+}
+
+macro_rules! assert_eq_pretty_str {
+ ($left:expr, $right:expr) => {
+ assert_eq_pretty!(
+ PrettyString($left.to_string()),
+ PrettyString($right.to_string())
+ );
+ };
+}
+
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
@@ -172,7 +195,7 @@ pub fn run_test(test: Test<'_>) -> Result<()> {
if error_file_path.is_file() {
let expected_msg = std::fs::read_to_string(error_file_path)?;
let msg = format!("{}\n", err);
- assert_eq_pretty!(msg, expected_msg);
+ assert_eq_pretty_str!(msg, expected_msg);
} else {
std::fs::create_dir_all(error_file_path.parent().unwrap())?;
let mut file = File::create(error_file_path)?;
diff --git a/dhall/tests/type-errors/unit/AssertAlphaTrap.txt b/dhall/tests/type-errors/unit/AssertAlphaTrap.txt
index df2b6c1..f2fc8ce 100644
--- a/dhall/tests/type-errors/unit/AssertAlphaTrap.txt
+++ b/dhall/tests/type-errors/unit/AssertAlphaTrap.txt
@@ -1 +1,6 @@
-Type error: Unbound variable
+Type error: --> 1:47
+ |
+1 | assert : (\(_: Bool) -> _) === (\(x: Bool) -> _)␊
+ | ^
+ |
+ = Unbound variable
diff --git a/dhall/tests/type-errors/unit/UnionDeprecatedConstructorsKeyword.txt b/dhall/tests/type-errors/unit/UnionDeprecatedConstructorsKeyword.txt
index df2b6c1..f7903de 100644
--- a/dhall/tests/type-errors/unit/UnionDeprecatedConstructorsKeyword.txt
+++ b/dhall/tests/type-errors/unit/UnionDeprecatedConstructorsKeyword.txt
@@ -1 +1,6 @@
-Type error: Unbound variable
+Type error: --> 1:1
+ |
+1 | constructors < Left : Natural | Right : Bool >␊
+ | ^----------^
+ |
+ = Unbound variable
diff --git a/dhall/tests/type-errors/unit/VariableFree.txt b/dhall/tests/type-errors/unit/VariableFree.txt
index df2b6c1..ef1d16e 100644
--- a/dhall/tests/type-errors/unit/VariableFree.txt
+++ b/dhall/tests/type-errors/unit/VariableFree.txt
@@ -1 +1,6 @@
-Type error: Unbound variable
+Type error: --> 1:1
+ |
+1 | x␊
+ | ^
+ |
+ = Unbound variable
diff --git a/dhall_syntax/src/core/span.rs b/dhall_syntax/src/core/span.rs
index fa89c30..e2bf26d 100644
--- a/dhall_syntax/src/core/span.rs
+++ b/dhall_syntax/src/core/span.rs
@@ -53,4 +53,18 @@ impl Span {
),
}
}
+
+ pub fn error(&self, message: impl Into<String>) -> String {
+ use pest::error::{Error, ErrorVariant};
+ use pest::Span;
+ let message: String = message.into();
+ let span = match self {
+ self::Span::Parsed(span) => span,
+ _ => return format!("Unknown location: {}", message),
+ };
+ let span = Span::new(&*span.input, span.start, span.end).unwrap();
+ let err: ErrorVariant<!> = ErrorVariant::CustomError { message };
+ let err = Error::new_from_span(err, span);
+ format!("{}", err)
+ }
}