diff options
author | Nadrieril Feneanar | 2019-11-11 17:01:02 +0100 |
---|---|---|
committer | GitHub | 2019-11-11 17:01:02 +0100 |
commit | 84cd6f386d6f4c7952fbc1da87dcd754f26ee404 (patch) | |
tree | d348f580a00c4b97f04f3a2e41ea2a23d67af824 /dhall_syntax | |
parent | f58ff637c8d53af1fcee43bfba5a9f8de799084c (diff) | |
parent | 8b566b2575096562c2e15d6ac9ee8750db2cf14f (diff) |
Merge pull request #114 from Nadrieril/nice-type-errors
Ground work for pretty type errors
Diffstat (limited to '')
-rw-r--r-- | dhall_syntax/src/core/expr.rs | 53 | ||||
-rw-r--r-- | dhall_syntax/src/core/mod.rs | 2 | ||||
-rw-r--r-- | dhall_syntax/src/core/span.rs | 81 | ||||
-rw-r--r-- | dhall_syntax/src/parser.rs | 14 |
4 files changed, 92 insertions, 58 deletions
diff --git a/dhall_syntax/src/core/expr.rs b/dhall_syntax/src/core/expr.rs index 2ad3ba8..750b58b 100644 --- a/dhall_syntax/src/core/expr.rs +++ b/dhall_syntax/src/core/expr.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use crate::map::{DupTreeMap, DupTreeSet}; use crate::visitor::{self, ExprFMutVisitor, ExprFVisitor}; use crate::*; @@ -15,40 +13,6 @@ pub fn trivial_result<T>(x: Result<T, !>) -> T { } } -/// A location in the source text -#[derive(Debug, Clone)] -pub struct Span { - input: Rc<str>, - /// # Safety - /// - /// Must be a valid character boundary index into `input`. - start: usize, - /// # Safety - /// - /// Must be a valid character boundary index into `input`. - end: usize, -} - -impl Span { - pub(crate) fn make(input: Rc<str>, sp: pest::Span) -> Self { - Span { - input, - start: sp.start(), - end: sp.end(), - } - } - /// Takes the union of the two spans. Assumes that the spans come from the same input. - /// This will also capture any input between the spans. - pub fn union(&self, other: &Span) -> Self { - use std::cmp::{max, min}; - Span { - input: self.input.clone(), - start: min(self.start, other.start), - end: max(self.start, other.start), - } - } -} - /// Double with bitwise equality #[derive(Debug, Copy, Clone)] pub struct NaiveDouble(f64); @@ -178,7 +142,7 @@ pub enum Builtin { // Each node carries an annotation. #[derive(Debug, Clone)] -pub struct Expr<Embed>(Box<(RawExpr<Embed>, Option<Span>)>); +pub struct Expr<Embed>(Box<(RawExpr<Embed>, Span)>); pub type RawExpr<Embed> = ExprF<Expr<Embed>, Embed>; @@ -334,16 +298,12 @@ impl<E> Expr<E> { pub fn as_mut(&mut self) -> &mut RawExpr<E> { &mut self.0.as_mut().0 } - pub fn span(&self) -> Option<Span> { + pub fn span(&self) -> Span { self.0.as_ref().1.clone() } - pub(crate) fn new(x: RawExpr<E>, n: Span) -> Self { - Expr(Box::new((x, Some(n)))) - } - - pub fn from_expr_no_span(x: RawExpr<E>) -> Self { - Expr(Box::new((x, None))) + pub fn new(x: RawExpr<E>, n: Span) -> Self { + Expr(Box::new((x, n))) } pub fn rewrap<E2>(&self, x: RawExpr<E2>) -> Expr<E2> { @@ -388,11 +348,6 @@ impl<E> Expr<E> { } } -// Should probably rename this -pub fn rc<E>(x: RawExpr<E>) -> Expr<E> { - Expr::from_expr_no_span(x) -} - /// Add an isize to an usize /// Panics on over/underflow fn add_ui(u: usize, i: isize) -> Option<usize> { diff --git a/dhall_syntax/src/core/mod.rs b/dhall_syntax/src/core/mod.rs index fe2c0be..66bf229 100644 --- a/dhall_syntax/src/core/mod.rs +++ b/dhall_syntax/src/core/mod.rs @@ -4,6 +4,8 @@ mod import; pub use import::*; mod label; pub use label::*; +mod span; +pub use span::*; mod text; pub use text::*; pub mod context; diff --git a/dhall_syntax/src/core/span.rs b/dhall_syntax/src/core/span.rs new file mode 100644 index 0000000..f9c7008 --- /dev/null +++ b/dhall_syntax/src/core/span.rs @@ -0,0 +1,81 @@ +use std::rc::Rc; + +/// A location in the source text +#[derive(Debug, Clone)] +pub struct ParsedSpan { + input: Rc<str>, + /// # Safety + /// + /// Must be a valid character boundary index into `input`. + start: usize, + /// # Safety + /// + /// Must be a valid character boundary index into `input`. + end: usize, +} + +#[derive(Debug, Clone)] +pub enum Span { + /// A location in the source text + Parsed(ParsedSpan), + /// For expressions obtained from decoding binary + Decoded, + /// For expressions constructed during normalization/typecheck + Artificial, +} + +impl Span { + pub(crate) fn make(input: Rc<str>, sp: pest::Span) -> Self { + Span::Parsed(ParsedSpan { + input, + start: sp.start(), + end: sp.end(), + }) + } + + /// Takes the union of the two spans, i.e. the range of input covered by the two spans plus any + /// input between them. Assumes that the spans come from the same input. Fails if one of the + /// spans does not point to an input location. + pub fn union(&self, other: &Span) -> Self { + use std::cmp::{max, min}; + use Span::*; + match (self, other) { + (Parsed(x), Parsed(y)) if Rc::ptr_eq(&x.input, &y.input) => { + Parsed(ParsedSpan { + input: x.input.clone(), + start: min(x.start, y.start), + end: max(x.end, y.end), + }) + } + _ => panic!( + "Tried to union incompatible spans: {:?} and {:?}", + self, other + ), + } + } + + /// Merges two spans assumed to point to a similar thing. If only one of them points to an + /// input location, use that one. + pub fn merge(&self, other: &Span) -> Self { + use Span::*; + match (self, other) { + (Parsed(x), _) | (_, Parsed(x)) => Parsed(x.clone()), + (Artificial, _) | (_, Artificial) => Artificial, + (Decoded, Decoded) => Decoded, + } + } + + 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) + } +} diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index 83f62ee..eaded50 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -650,7 +650,7 @@ impl DhallParser { final_expr, |acc, x| { spanned_union( - acc.span().unwrap(), + acc.span(), x.3, Let(x.0, x.1, x.2, acc) ) @@ -717,11 +717,7 @@ impl DhallParser { r => Err(op.error(format!("Rule {:?} isn't an operator", r)))?, }; - Ok(spanned_union( - l.span().unwrap(), - r.span().unwrap(), - BinOp(op, l, r), - )) + Ok(spanned_union(l.span(), r.span(), BinOp(op, l, r))) } fn Some_(_input: ParseInput) -> ParseResult<()> { @@ -739,8 +735,8 @@ impl DhallParser { first, |acc, e| { spanned_union( - acc.span().unwrap(), - e.span().unwrap(), + acc.span(), + e.span(), App(acc, e) ) } @@ -778,7 +774,7 @@ impl DhallParser { first, |acc, e| { spanned_union( - acc.span().unwrap(), + acc.span(), e.1, match e.0 { Either::Left(l) => Field(acc, l), |