From 5df25cd8349a6084aad367878499b4d06cccef18 Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Fri, 25 Nov 2022 18:46:30 +0900 Subject: [PATCH] revset: add origin field to RevsetParseError to chain alias errors This could be embedded in a variant of RevsetParseErrorKind, but I want to keep the enum comparable. --- lib/src/revset.rs | 30 ++++++++++++++++++++++++++++++ src/cli_util.rs | 4 +++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/src/revset.rs b/lib/src/revset.rs index 8b749ec85..c3a67b986 100644 --- a/lib/src/revset.rs +++ b/lib/src/revset.rs @@ -198,6 +198,7 @@ pub struct RevsetParser; pub struct RevsetParseError { kind: RevsetParseErrorKind, pest_error: Option>>, + origin: Option>, } #[derive(Debug, Error, PartialEq, Eq)] @@ -219,6 +220,7 @@ impl RevsetParseError { RevsetParseError { kind, pest_error: None, + origin: None, } } @@ -232,12 +234,36 @@ impl RevsetParseError { RevsetParseError { kind, pest_error: Some(Box::new(err)), + origin: None, + } + } + + fn with_span_and_origin( + kind: RevsetParseErrorKind, + span: pest::Span<'_>, + origin: Self, + ) -> Self { + let err = pest::error::Error::new_from_span( + pest::error::ErrorVariant::CustomError { + message: kind.to_string(), + }, + span, + ); + RevsetParseError { + kind, + pest_error: Some(Box::new(err)), + origin: Some(Box::new(origin)), } } pub fn kind(&self) -> &RevsetParseErrorKind { &self.kind } + + /// Original parsing error which typically occurred in an alias expression. + pub fn origin(&self) -> Option<&Self> { + self.origin.as_deref() + } } impl From> for RevsetParseError { @@ -245,6 +271,7 @@ impl From> for RevsetParseError { RevsetParseError { kind: RevsetParseErrorKind::SyntaxError, pest_error: Some(Box::new(err)), + origin: None, } } } @@ -261,6 +288,9 @@ impl fmt::Display for RevsetParseError { impl error::Error for RevsetParseError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { + if let Some(e) = self.origin() { + return Some(e as &dyn error::Error); + } match &self.kind { // SyntaxError is a wrapper for pest::error::Error. RevsetParseErrorKind::SyntaxError => { diff --git a/src/cli_util.rs b/src/cli_util.rs index abe3d3a04..130f350ba 100644 --- a/src/cli_util.rs +++ b/src/cli_util.rs @@ -16,6 +16,7 @@ use std::collections::{HashSet, VecDeque}; use std::env::ArgsOs; use std::ffi::OsString; use std::fmt::Debug; +use std::iter; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; @@ -175,7 +176,8 @@ impl From for CommandError { impl From for CommandError { fn from(err: RevsetParseError) -> Self { - user_error(format!("Failed to parse revset: {err}")) + let message = iter::successors(Some(&err), |e| e.origin()).join("\n"); + user_error(format!("Failed to parse revset: {message}")) } }