diff --git a/tamer/src/asg/graph/xmli.rs b/tamer/src/asg/graph/xmli.rs index f9a82e82..87ab17d9 100644 --- a/tamer/src/asg/graph/xmli.rs +++ b/tamer/src/asg/graph/xmli.rs @@ -54,7 +54,7 @@ use crate::{ }, }; use arrayvec::ArrayVec; -use std::{convert::Infallible, fmt::Display, marker::PhantomData}; +use std::{fmt::Display, marker::PhantomData}; #[derive(Debug, PartialEq, Eq)] pub enum AsgTreeToXirf<'a> { @@ -75,10 +75,14 @@ impl<'a> Display for AsgTreeToXirf<'a> { type Xirf = XirfToken; +diagnostic_infallible! { + pub enum AsgTreeToXirfError {} +} + impl<'a> ParseState for AsgTreeToXirf<'a> { type Token = TreeWalkRel; type Object = Xirf; - type Error = Infallible; + type Error = AsgTreeToXirfError; type Context = TreeContext<'a>; fn parse_token( diff --git a/tamer/src/asg/mod.rs b/tamer/src/asg/mod.rs index 444c5b46..d7a86df2 100644 --- a/tamer/src/asg/mod.rs +++ b/tamer/src/asg/mod.rs @@ -74,7 +74,7 @@ pub use graph::{ ObjectKind, }, visit, - xmli::AsgTreeToXirf, + xmli::{AsgTreeToXirf, AsgTreeToXirfError}, Asg, AsgResult, IndexType, }; diff --git a/tamer/src/bin/tamec.rs b/tamer/src/bin/tamec.rs index 03e1ba6f..338fc156 100644 --- a/tamer/src/bin/tamec.rs +++ b/tamer/src/bin/tamec.rs @@ -39,16 +39,21 @@ use std::{ path::Path, }; use tamer::{ - asg::{air::Air, AsgError, DefaultAsg}, + asg::{ + air::Air, visit::TreeWalkRel, AsgError, AsgTreeToXirfError, DefaultAsg, + }, diagnose::{ AnnotatedSpan, Diagnostic, FsSpanResolver, Reporter, VisualReporter, }, - nir::{InterpError, Nir, NirToAirError, XirfToNirError}, + nir::{ + InterpError, Nir, NirToAirError, TplShortDesugarError, XirfToNirError, + }, parse::{lowerable, FinalizeError, ParseError, Token, UnknownToken}, pipeline::parse_package_xml, xir::{ self, - flat::{RefinedText, XirToXirfError, XirfToken}, + autoclose::XirfAutoCloseError, + flat::{RefinedText, Text, XirToXirfError, XirfToXirError, XirfToken}, reader::XmlXirReader, DefaultEscaper, Token as XirToken, }, @@ -317,6 +322,9 @@ pub enum UnrecoverableError { Io(io::Error), Fmt(fmt::Error), XirWriterError(xir::writer::Error), + AsgTreeToXirfError(ParseError), + XirfAutoCloseError(ParseError, XirfAutoCloseError>), + XirfToXirError(ParseError, XirfToXirError>), ErrorsDuringLowering(ErrorCount), FinalizeError(FinalizeError), } @@ -353,6 +361,7 @@ pub enum RecoverableError { XirParseError(ParseError), XirfParseError(ParseError), NirParseError(ParseError, XirfToNirError>), + TplShortDesugarError(ParseError), InterpError(ParseError), NirToAirError(ParseError), AirAggregateError(ParseError), @@ -376,15 +385,29 @@ impl From for UnrecoverableError { } } -impl From for UnrecoverableError { - fn from(e: FinalizeError) -> Self { - Self::FinalizeError(e) +impl From> for UnrecoverableError { + fn from(e: ParseError) -> Self { + Self::AsgTreeToXirfError(e) } } -impl From for UnrecoverableError { - fn from(_: Infallible) -> Self { - unreachable!(">::from") +impl From, XirfToXirError>> for UnrecoverableError { + fn from(e: ParseError, XirfToXirError>) -> Self { + Self::XirfToXirError(e) + } +} + +impl From, XirfAutoCloseError>> + for UnrecoverableError +{ + fn from(e: ParseError, XirfAutoCloseError>) -> Self { + Self::XirfAutoCloseError(e) + } +} + +impl From for UnrecoverableError { + fn from(e: FinalizeError) -> Self { + Self::FinalizeError(e) } } @@ -396,14 +419,6 @@ impl From> for UnrecoverableError { } } -impl From> for RecoverableError { - fn from(_: ParseError) -> Self { - unreachable!( - ">>::from" - ) - } -} - impl From> for RecoverableError { fn from(e: ParseError) -> Self { Self::XirParseError(e) @@ -424,6 +439,12 @@ impl From, XirfToNirError>> } } +impl From> for RecoverableError { + fn from(e: ParseError) -> Self { + Self::TplShortDesugarError(e) + } +} + impl From> for RecoverableError { fn from(e: ParseError) -> Self { Self::InterpError(e) @@ -450,6 +471,9 @@ impl Display for UnrecoverableError { Io(e) => Display::fmt(e, f), Fmt(e) => Display::fmt(e, f), XirWriterError(e) => Display::fmt(e, f), + AsgTreeToXirfError(e) => Display::fmt(e, f), + XirfToXirError(e) => Display::fmt(e, f), + XirfAutoCloseError(e) => Display::fmt(e, f), FinalizeError(e) => Display::fmt(e, f), // TODO: Use formatter for dynamic "error(s)" @@ -468,6 +492,7 @@ impl Display for RecoverableError { XirParseError(e) => Display::fmt(e, f), XirfParseError(e) => Display::fmt(e, f), NirParseError(e) => Display::fmt(e, f), + TplShortDesugarError(e) => Display::fmt(e, f), InterpError(e) => Display::fmt(e, f), NirToAirError(e) => Display::fmt(e, f), AirAggregateError(e) => Display::fmt(e, f), @@ -475,40 +500,16 @@ impl Display for RecoverableError { } } -impl Error for UnrecoverableError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - use UnrecoverableError::*; - - match self { - Io(e) => Some(e), - Fmt(e) => Some(e), - XirWriterError(e) => Some(e), - ErrorsDuringLowering(_) => None, - FinalizeError(e) => Some(e), - } - } -} - -impl Error for RecoverableError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - use RecoverableError::*; - - match self { - XirParseError(e) => Some(e), - XirfParseError(e) => Some(e), - NirParseError(e) => Some(e), - InterpError(e) => Some(e), - NirToAirError(e) => Some(e), - AirAggregateError(e) => Some(e), - } - } -} +impl Error for UnrecoverableError {} impl Diagnostic for UnrecoverableError { fn describe(&self) -> Vec { use UnrecoverableError::*; match self { + AsgTreeToXirfError(e) => e.describe(), + XirfToXirError(e) => e.describe(), + XirfAutoCloseError(e) => e.describe(), FinalizeError(e) => e.describe(), // Fall back to `Display` @@ -527,6 +528,7 @@ impl Diagnostic for RecoverableError { XirParseError(e) => e.describe(), XirfParseError(e) => e.describe(), NirParseError(e) => e.describe(), + TplShortDesugarError(e) => e.describe(), InterpError(e) => e.describe(), NirToAirError(e) => e.describe(), AirAggregateError(e) => e.describe(), diff --git a/tamer/src/diagnose.rs b/tamer/src/diagnose.rs index db38190b..390df30e 100644 --- a/tamer/src/diagnose.rs +++ b/tamer/src/diagnose.rs @@ -332,3 +332,55 @@ impl> Annotate for S { AnnotatedSpan(self.into(), level, label) } } + +/// Generate a variant-less error enum akin to [`Infallible`]. +/// +/// This is used to create [`Infallible`]-like newtypes where unique error +/// types are beneficial. +/// For example, +/// this can be used so that [`From`] implementations can be exclusively +/// used to widen errors +/// (or lack thereof) +/// into error sum variants, +/// and is especially useful when code generation is involved to avoid +/// generation of overlapping [`From`] `impl`s. +/// +/// The generated enum is convertable [`Into`] and [`From`] [`Infallible`]. +macro_rules! diagnostic_infallible { + ($vis:vis enum $name:ident {}) => { + /// A unique [`Infallible`](std::convert::Infallible) type. + #[derive(Debug, PartialEq)] + $vis enum $name {} + + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, stringify!($name)) + } + } + + impl $crate::diagnose::Diagnostic for $name { + fn describe(&self) -> Vec<$crate::diagnose::AnnotatedSpan> { + // This is a unit struct and should not be able to be + // instantiated! + unreachable!( + concat!( + stringify!($name), + " should be unreachable!" + ) + ) + } + } + + impl From for $name { + fn from(_: std::convert::Infallible) -> Self { + unreachable!() + } + } + + impl From<$name> for std::convert::Infallible { + fn from(_: $name) -> Self { + unreachable!() + } + } + } +} diff --git a/tamer/src/lib.rs b/tamer/src/lib.rs index 1aadabab..471fe037 100644 --- a/tamer/src/lib.rs +++ b/tamer/src/lib.rs @@ -181,12 +181,13 @@ pub mod global; #[macro_use] extern crate static_assertions; +#[macro_use] +pub mod diagnose; #[macro_use] pub mod xir; pub mod asg; pub mod convert; -pub mod diagnose; pub mod f; pub mod fmt; pub mod fs; diff --git a/tamer/src/nir.rs b/tamer/src/nir.rs index 7d9157b0..6a4ee756 100644 --- a/tamer/src/nir.rs +++ b/tamer/src/nir.rs @@ -77,7 +77,7 @@ pub use interp::{InterpError, InterpState as InterpolateNir}; pub use parse::{ NirParseState as XirfToNir, NirParseStateError_ as XirfToNirError, }; -pub use tplshort::TplShortDesugar; +pub use tplshort::{TplShortDesugar, TplShortDesugarError}; /// IR that is "near" the source code. /// diff --git a/tamer/src/nir/air.rs b/tamer/src/nir/air.rs index ff43a83d..d543bc5d 100644 --- a/tamer/src/nir/air.rs +++ b/tamer/src/nir/air.rs @@ -108,8 +108,6 @@ impl ParseState for NirToAir { use NirToAir::*; use NirToAirError::*; - use crate::diagnostic_panic; - if let Some(obj) = stack.pop() { return Transition(Ready).ok(obj).with_lookahead(tok); } diff --git a/tamer/src/nir/tplshort.rs b/tamer/src/nir/tplshort.rs index 7032388f..cc1f9072 100644 --- a/tamer/src/nir/tplshort.rs +++ b/tamer/src/nir/tplshort.rs @@ -88,7 +88,6 @@ use crate::{ SymbolId, }, }; -use std::convert::Infallible; use Nir::*; use NirEntity::*; @@ -130,10 +129,14 @@ impl Display for TplShortDesugar { } } +diagnostic_infallible! { + pub enum TplShortDesugarError {} +} + impl ParseState for TplShortDesugar { type Token = Nir; type Object = Nir; - type Error = Infallible; + type Error = TplShortDesugarError; type Context = Stack; fn parse_token( diff --git a/tamer/src/pipeline.rs b/tamer/src/pipeline.rs index 648e9819..75f23528 100644 --- a/tamer/src/pipeline.rs +++ b/tamer/src/pipeline.rs @@ -39,6 +39,18 @@ //! The module is responsible for pipeline composition. //! For information on the lowering pipeline as an abstraction, //! see [`Lower`]. +//! +//! Error Widening +//! ============== +//! Each [`ParseState`] in the pipeline is expected to have its own unique +//! error type, +//! utilizing newtypes if necessary; +//! this ensures that errors are able to be uniquely paired with each +//! [`ParseState`] that produced it without having to perform an +//! explicit mapping at the call site. +//! To facilitate that automatic mapping/aggregation, +//! this uniqueness property also allows for generation of [`From`] +//! implementations that will not overlap. use crate::{ asg::{air::AirAggregate, AsgTreeToXirf}, diff --git a/tamer/src/xir/autoclose.rs b/tamer/src/xir/autoclose.rs index 6870543b..d17c9d98 100644 --- a/tamer/src/xir/autoclose.rs +++ b/tamer/src/xir/autoclose.rs @@ -106,7 +106,7 @@ use crate::{ span::{Span, UNKNOWN_SPAN}, xir::EleSpan, }; -use std::{convert::Infallible, fmt::Display}; +use std::fmt::Display; use XirfAutoClose::*; @@ -138,10 +138,14 @@ impl Display for XirfAutoClose { } } +diagnostic_infallible! { + pub enum XirfAutoCloseError {} +} + impl ParseState for XirfAutoClose { type Token = XirfToken; type Object = XirfToken; - type Error = Infallible; + type Error = XirfAutoCloseError; type Context = AutoCloseStack; fn parse_token( diff --git a/tamer/src/xir/flat.rs b/tamer/src/xir/flat.rs index 9365eee1..57484fcd 100644 --- a/tamer/src/xir/flat.rs +++ b/tamer/src/xir/flat.rs @@ -55,7 +55,6 @@ use crate::{ }; use arrayvec::ArrayVec; use std::{ - convert::Infallible, error::Error, fmt::{Debug, Display}, marker::PhantomData, @@ -926,10 +925,14 @@ impl Display for XirfToXir { } } +diagnostic_infallible! { + pub enum XirfToXirError {} +} + impl ParseState for XirfToXir { type Token = XirfToken; type Object = XirToken; - type Error = Infallible; + type Error = XirfToXirError; fn parse_token( self, diff --git a/tamer/src/xir/flat/test.rs b/tamer/src/xir/flat/test.rs index 23179f46..c7b70c46 100644 --- a/tamer/src/xir/flat/test.rs +++ b/tamer/src/xir/flat/test.rs @@ -619,10 +619,10 @@ fn xirf_to_xir() { ); // The lowering pipeline above requires compatible errors. - impl From, Infallible>> + impl From, XirfToXirError>> for ParseError { - fn from(_value: ParseError, Infallible>) -> Self { + fn from(_value: ParseError, XirfToXirError>) -> Self { unreachable!() } }