From 77af0bbc171618f48531cc6b1d77e18089928885 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 20:54:15 +0200 Subject: Stop tracking the absence of Embed values at the type level --- dhall_syntax/src/core/context.rs | 2 +- dhall_syntax/src/core/expr.rs | 16 ++-------------- dhall_syntax/src/core/visitor.rs | 15 +-------------- 3 files changed, 4 insertions(+), 29 deletions(-) (limited to 'dhall_syntax/src/core') diff --git a/dhall_syntax/src/core/context.rs b/dhall_syntax/src/core/context.rs index eeec121..6844baa 100644 --- a/dhall_syntax/src/core/context.rs +++ b/dhall_syntax/src/core/context.rs @@ -4,7 +4,7 @@ use std::hash::Hash; /// A `(Context a)` associates `Text` labels with values of type `a` /// -/// The `Context` is used for type-checking when `(a = Expr X)` +/// The `Context` is used for type-checking when `(a = Expr)` /// /// * You create a `Context` using `empty` and `insert` /// * You transform a `Context` using `fmap` diff --git a/dhall_syntax/src/core/expr.rs b/dhall_syntax/src/core/expr.rs index 0cbece3..e08d816 100644 --- a/dhall_syntax/src/core/expr.rs +++ b/dhall_syntax/src/core/expr.rs @@ -10,9 +10,9 @@ pub type Double = NaiveDouble; /// An empty type #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum X {} +pub enum Void {} -pub fn trivial_result(x: Result) -> T { +pub fn trivial_result(x: Result) -> T { match x { Ok(x) => x, Err(e) => match e {}, @@ -351,12 +351,6 @@ impl Expr { } } -impl Expr { - pub fn absurd(&self) -> Expr { - self.visit(&mut visitor::AbsurdVisitor) - } -} - impl SubExpr { pub fn as_ref(&self) -> &Expr { &self.0.as_ref().0 @@ -416,12 +410,6 @@ impl SubExpr { } } -impl SubExpr { - pub fn absurd(&self) -> SubExpr { - SubExpr::from_expr_no_span(self.as_ref().absurd()) - } -} - impl Clone for SubExpr { fn clone(&self) -> Self { SubExpr(Rc::clone(&self.0)) diff --git a/dhall_syntax/src/core/visitor.rs b/dhall_syntax/src/core/visitor.rs index 50ec68a..e39e95b 100644 --- a/dhall_syntax/src/core/visitor.rs +++ b/dhall_syntax/src/core/visitor.rs @@ -243,7 +243,7 @@ impl<'a, T, SE1, SE2, E1, E2> ExprFFallibleVisitor<'a, SE1, SE2, E1, E2> where T: ExprFInFallibleVisitor<'a, SE1, SE2, E1, E2>, { - type Error = X; + type Error = Void; fn visit_subexpr(&mut self, subexpr: &'a SE1) -> Result { Ok(self.0.visit_subexpr(subexpr)) @@ -379,16 +379,3 @@ where (self.0)(embed) } } - -pub struct AbsurdVisitor; - -impl<'a, 'b, E> ExprFInFallibleVisitor<'a, SubExpr, SubExpr, X, E> - for &'b mut AbsurdVisitor -{ - fn visit_subexpr(&mut self, subexpr: &'a SubExpr) -> SubExpr { - SubExpr::from_expr_no_span(subexpr.as_ref().visit(&mut **self)) - } - fn visit_embed(self, embed: &'a X) -> E { - match *embed {} - } -} -- cgit v1.2.3 From 51dbaa0b66089bca63aa9cf69a1e0ec59df053b9 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 21:10:59 +0200 Subject: Considerably simplify Embed handling --- dhall_syntax/src/core/expr.rs | 110 +++++++++------------------------------ dhall_syntax/src/core/visitor.rs | 60 ++++++--------------- 2 files changed, 43 insertions(+), 127 deletions(-) (limited to 'dhall_syntax/src/core') diff --git a/dhall_syntax/src/core/expr.rs b/dhall_syntax/src/core/expr.rs index e08d816..74eb993 100644 --- a/dhall_syntax/src/core/expr.rs +++ b/dhall_syntax/src/core/expr.rs @@ -245,92 +245,62 @@ impl ExprF { v.visit(self) } - pub fn traverse_ref_with_special_handling_of_binders<'a, SE2, E2, Err>( + pub fn traverse_ref_with_special_handling_of_binders<'a, SE2, Err>( &'a self, visit_subexpr: impl FnMut(&'a SE) -> Result, visit_under_binder: impl FnOnce(&'a Label, &'a SE) -> Result, - visit_embed: impl FnOnce(&'a E) -> Result, - ) -> Result, Err> { + ) -> Result, Err> + where + E: Clone, + { self.visit(visitor::TraverseRefWithBindersVisitor { visit_subexpr, visit_under_binder, - visit_embed, }) } - fn traverse_ref<'a, SE2, E2, Err>( + fn traverse_ref<'a, SE2, Err>( &'a self, visit_subexpr: impl FnMut(&'a SE) -> Result, - visit_embed: impl FnOnce(&'a E) -> Result, - ) -> Result, Err> { - self.visit(visitor::TraverseRefVisitor { - visit_subexpr, - visit_embed, - }) + ) -> Result, Err> + where + E: Clone, + { + self.visit(visitor::TraverseRefVisitor { visit_subexpr }) } - pub fn map_ref_with_special_handling_of_binders<'a, SE2, E2>( + pub fn map_ref_with_special_handling_of_binders<'a, SE2>( &'a self, mut map_subexpr: impl FnMut(&'a SE) -> SE2, mut map_under_binder: impl FnMut(&'a Label, &'a SE) -> SE2, - map_embed: impl FnOnce(&'a E) -> E2, - ) -> ExprF { + ) -> ExprF + where + E: Clone, + { trivial_result(self.traverse_ref_with_special_handling_of_binders( |x| Ok(map_subexpr(x)), |l, x| Ok(map_under_binder(l, x)), - |x| Ok(map_embed(x)), )) } - pub fn map_ref<'a, SE2, E2>( + pub fn map_ref<'a, SE2>( &'a self, mut map_subexpr: impl FnMut(&'a SE) -> SE2, - map_embed: impl FnOnce(&'a E) -> E2, - ) -> ExprF { - trivial_result( - self.traverse_ref(|x| Ok(map_subexpr(x)), |x| Ok(map_embed(x))), - ) - } - - pub fn traverse_ref_simple<'a, SE2, Err>( - &'a self, - visit_subexpr: impl FnMut(&'a SE) -> Result, - ) -> Result, Err> - where - E: Clone, - { - self.traverse_ref(visit_subexpr, |x| Ok(E::clone(x))) - } - - pub fn map_ref_simple<'a, SE2>( - &'a self, - map_subexpr: impl Fn(&'a SE) -> SE2, ) -> ExprF where E: Clone, { - self.map_ref(map_subexpr, E::clone) + trivial_result(self.traverse_ref(|x| Ok(map_subexpr(x)))) } } -impl Expr { - fn traverse_embed( - &self, - visit_embed: impl FnMut(&E) -> Result, - ) -> Result, Err> { - self.visit(&mut visitor::TraverseEmbedVisitor(visit_embed)) - } - - fn map_embed(&self, mut map_embed: impl FnMut(&E) -> E2) -> Expr { - trivial_result(self.traverse_embed(|x| Ok(map_embed(x)))) - } - +impl Expr { pub fn traverse_resolve( &self, - visit_embed: impl FnMut(&E) -> Result, + visit_import: impl FnMut(&Import) -> Result, ) -> Result, Err> { self.traverse_resolve_with_visitor(&mut visitor::ResolveVisitor( - visit_embed, + visit_import, )) } @@ -339,7 +309,7 @@ impl Expr { visitor: &mut visitor::ResolveVisitor, ) -> Result, Err> where - F1: FnMut(&E) -> Result, + F1: FnMut(&Import) -> Result, { match self { ExprF::BinOp(BinOp::ImportAlt, l, r) => l @@ -371,42 +341,14 @@ impl SubExpr { pub fn rewrap(&self, x: Expr) -> SubExpr { SubExpr(Rc::new((x, (self.0).1.clone()))) } +} - pub fn traverse_embed( - &self, - visit_embed: impl FnMut(&E) -> Result, - ) -> Result, Err> { - Ok(self.rewrap(self.as_ref().traverse_embed(visit_embed)?)) - } - - pub fn map_embed( - &self, - map_embed: impl FnMut(&E) -> E2, - ) -> SubExpr { - self.rewrap(self.as_ref().map_embed(map_embed)) - } - - pub fn map_subexprs_with_special_handling_of_binders<'a>( - &'a self, - map_expr: impl FnMut(&'a Self) -> Self, - map_under_binder: impl FnMut(&'a Label, &'a Self) -> Self, - ) -> Self { - match self.as_ref() { - ExprF::Embed(_) => SubExpr::clone(self), - // This calls ExprF::map_ref - e => self.rewrap(e.map_ref_with_special_handling_of_binders( - map_expr, - map_under_binder, - |_| unreachable!(), - )), - } - } - +impl SubExpr { pub fn traverse_resolve( &self, - visit_embed: impl FnMut(&E) -> Result, + visit_import: impl FnMut(&Import) -> Result, ) -> Result, Err> { - Ok(self.rewrap(self.as_ref().traverse_resolve(visit_embed)?)) + Ok(self.rewrap(self.as_ref().traverse_resolve(visit_import)?)) } } diff --git a/dhall_syntax/src/core/visitor.rs b/dhall_syntax/src/core/visitor.rs index e39e95b..647f76f 100644 --- a/dhall_syntax/src/core/visitor.rs +++ b/dhall_syntax/src/core/visitor.rs @@ -278,21 +278,18 @@ where } } -pub struct TraverseRefWithBindersVisitor { +pub struct TraverseRefWithBindersVisitor { pub visit_subexpr: F1, pub visit_under_binder: F2, - pub visit_embed: F4, } -impl<'a, SE, E, SE2, E2, Err, F1, F2, F4> - ExprFFallibleVisitor<'a, SE, SE2, E, E2> - for TraverseRefWithBindersVisitor +impl<'a, SE, E, SE2, Err, F1, F2> ExprFFallibleVisitor<'a, SE, SE2, E, E> + for TraverseRefWithBindersVisitor where SE: 'a, - E: 'a, + E: 'a + Clone, F1: FnMut(&'a SE) -> Result, F2: FnOnce(&'a Label, &'a SE) -> Result, - F4: FnOnce(&'a E) -> Result, { type Error = Err; @@ -306,68 +303,45 @@ where ) -> Result { (self.visit_under_binder)(label, subexpr) } - fn visit_embed(self, embed: &'a E) -> Result { - (self.visit_embed)(embed) + fn visit_embed(self, embed: &'a E) -> Result { + Ok(embed.clone()) } } -pub struct TraverseRefVisitor { +pub struct TraverseRefVisitor { pub visit_subexpr: F1, - pub visit_embed: F3, } -impl<'a, SE, E, SE2, E2, Err, F1, F3> ExprFFallibleVisitor<'a, SE, SE2, E, E2> - for TraverseRefVisitor +impl<'a, SE, E, SE2, Err, F1> ExprFFallibleVisitor<'a, SE, SE2, E, E> + for TraverseRefVisitor where SE: 'a, - E: 'a, + E: 'a + Clone, F1: FnMut(&'a SE) -> Result, - F3: FnOnce(&'a E) -> Result, { type Error = Err; fn visit_subexpr(&mut self, subexpr: &'a SE) -> Result { (self.visit_subexpr)(subexpr) } - fn visit_embed(self, embed: &'a E) -> Result { - (self.visit_embed)(embed) - } -} - -pub struct TraverseEmbedVisitor(pub F1); - -impl<'a, 'b, E, E2, Err, F1> - ExprFFallibleVisitor<'a, SubExpr, SubExpr, E, E2> - for &'b mut TraverseEmbedVisitor -where - F1: FnMut(&E) -> Result, -{ - type Error = Err; - - fn visit_subexpr( - &mut self, - subexpr: &'a SubExpr, - ) -> Result, Self::Error> { - Ok(subexpr.rewrap(subexpr.as_ref().visit(&mut **self)?)) - } - fn visit_embed(self, embed: &'a E) -> Result { - (self.0)(embed) + fn visit_embed(self, embed: &'a E) -> Result { + Ok(embed.clone()) } } pub struct ResolveVisitor(pub F1); -impl<'a, 'b, E, E2, Err, F1> - ExprFFallibleVisitor<'a, SubExpr, SubExpr, E, E2> +impl<'a, 'b, E2, Err, F1> + ExprFFallibleVisitor<'a, SubExpr, SubExpr, Import, E2> for &'b mut ResolveVisitor where - F1: FnMut(&E) -> Result, + F1: FnMut(&Import) -> Result, { type Error = Err; fn visit_subexpr( &mut self, - subexpr: &'a SubExpr, + subexpr: &'a SubExpr, ) -> Result, Self::Error> { Ok(subexpr.rewrap( subexpr @@ -375,7 +349,7 @@ where .traverse_resolve_with_visitor(&mut **self)?, )) } - fn visit_embed(self, embed: &'a E) -> Result { + fn visit_embed(self, embed: &'a Import) -> Result { (self.0)(embed) } } -- cgit v1.2.3 From 07956ccb1daf4a6819f64776f70b6f5f26869184 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 21:38:17 +0200 Subject: Cleanup visitor code --- dhall_syntax/src/core/visitor.rs | 193 +++++++++++---------------------------- 1 file changed, 54 insertions(+), 139 deletions(-) (limited to 'dhall_syntax/src/core') diff --git a/dhall_syntax/src/core/visitor.rs b/dhall_syntax/src/core/visitor.rs index 647f76f..f2f3b32 100644 --- a/dhall_syntax/src/core/visitor.rs +++ b/dhall_syntax/src/core/visitor.rs @@ -2,52 +2,56 @@ use crate::*; use std::iter::FromIterator; /// A way too generic Visitor trait. -pub trait GenericVisitor: Sized { - fn visit(self, input: Input) -> Return; +pub trait GenericVisitor: Sized { + fn visit(self, input: Input) -> Output; } -/// A visitor trait that can be used to traverse `ExprF`s. We need this pattern -/// so that Rust lets us have as much mutability as we can. -/// For example, `traverse_embed` cannot be made using only `traverse_ref`, because -/// `traverse_ref` takes a `FnMut` so we would need to pass multiple mutable -/// reverences to this argument to `traverse_ref`. But Rust's ownership system -/// is all about preventing exactly this ! So we have to be more clever. -/// The visitor pattern allows us to have only one mutable thing the whole -/// time: the visitor itself. The visitor can then carry around multiple closures -/// or just one, and Rust is ok with either. See for example TraverseRefVisitor -/// and TraverseEmbedVisitor. -/// This is very generic. For a more legible trait, see ExprFInFallibleVisitor -pub trait ExprFVeryGenericVisitor<'a, Ret, SE1, E1>: Sized { +/// A visitor trait that can be used to traverse `ExprF`s. We need this pattern so that Rust lets +/// us have as much mutability as we can. +/// For example, `traverse_ref_with_special_handling_of_binders` cannot be made using only +/// `traverse_ref`, because `traverse_ref` takes a `FnMut` so we would need to pass multiple +/// mutable reverences to this argument to `traverse_ref`. But Rust's ownership system is all about +/// preventing exactly this ! So we have to be more clever. The visitor pattern allows us to have +/// only one mutable thing the whole time: the visitor itself. The visitor can then carry around +/// multiple closures or just one, and Rust is ok with either. See for example TraverseRefVisitor. +pub trait ExprFFallibleVisitor<'a, SE1, SE2, E1, E2>: Sized { type Error; - type SE2; - type E2; - fn visit_subexpr( - &mut self, - subexpr: &'a SE1, - ) -> Result; + fn visit_subexpr(&mut self, subexpr: &'a SE1) -> Result; + fn visit_embed(self, embed: &'a E1) -> Result; fn visit_subexpr_under_binder( - self, - label: &'a Label, + mut self, + _label: &'a Label, subexpr: &'a SE1, - ) -> Result; + ) -> Result { + self.visit_subexpr(subexpr) + } +} - fn visit_embed_squash(self, embed: &'a E1) -> Result; +/// Like ExprFFallibleVisitor, but without the error handling. +pub trait ExprFInFallibleVisitor<'a, SE1, SE2, E1, E2>: Sized { + fn visit_subexpr(&mut self, subexpr: &'a SE1) -> SE2; + fn visit_embed(self, embed: &'a E1) -> E2; - // Called with the result of the map, in the non-embed case. - // Useful to change the result type, and/or avoid some loss of info - fn visit_resulting_exprf( - result: ExprF, - ) -> Result; + fn visit_subexpr_under_binder( + mut self, + _label: &'a Label, + subexpr: &'a SE1, + ) -> SE2 { + self.visit_subexpr(subexpr) + } } -impl<'a, T, Ret, SE1, E1> - GenericVisitor<&'a ExprF, Result> for T +impl<'a, T, SE1, SE2, E1, E2> + GenericVisitor<&'a ExprF, Result, T::Error>> for T where - T: ExprFVeryGenericVisitor<'a, Ret, SE1, E1>, + T: ExprFFallibleVisitor<'a, SE1, SE2, E1, E2>, { - fn visit(self, input: &'a ExprF) -> Result { + fn visit( + self, + input: &'a ExprF, + ) -> Result, T::Error> { fn vec<'a, T, U, Err, F: FnMut(&'a T) -> Result>( x: &'a [T], f: F, @@ -63,27 +67,27 @@ where None => None, }) } - fn dupmap<'a, V, Ret, SE, E, T>( - x: impl IntoIterator, + fn dupmap<'a, V, SE1, SE2, E1, E2, T>( + x: impl IntoIterator, mut v: V, ) -> Result where - SE: 'a, - T: FromIterator<(Label, V::SE2)>, - V: ExprFVeryGenericVisitor<'a, Ret, SE, E>, + SE1: 'a, + T: FromIterator<(Label, SE2)>, + V: ExprFFallibleVisitor<'a, SE1, SE2, E1, E2>, { x.into_iter() .map(|(k, x)| Ok((k.clone(), v.visit_subexpr(x)?))) .collect() } - fn optdupmap<'a, V, Ret, SE, E, T>( - x: impl IntoIterator)>, + fn optdupmap<'a, V, SE1, SE2, E1, E2, T>( + x: impl IntoIterator)>, mut v: V, ) -> Result where - SE: 'a, - T: FromIterator<(Label, Option)>, - V: ExprFVeryGenericVisitor<'a, Ret, SE, E>, + SE1: 'a, + T: FromIterator<(Label, Option)>, + V: ExprFFallibleVisitor<'a, SE1, SE2, E1, E2>, { x.into_iter() .map(|(k, x)| { @@ -100,7 +104,7 @@ where let mut v = self; use crate::ExprF::*; - T::visit_resulting_exprf(match input { + Ok(match input { Var(v) => Var(v.clone()), Lam(l, t, e) => { let t = v.visit_subexpr(t)?; @@ -149,90 +153,18 @@ where Field(e, l) => Field(v.visit_subexpr(e)?, l.clone()), Projection(e, ls) => Projection(v.visit_subexpr(e)?, ls.clone()), Assert(e) => Assert(v.visit_subexpr(e)?), - Embed(a) => return v.visit_embed_squash(a), + Embed(a) => Embed(v.visit_embed(a)?), }) } } -/// Like ExprFVeryGenericVisitor, but sets the return -/// type to ExprF<_> -pub trait ExprFFallibleVisitor<'a, SE1, SE2, E1, E2>: Sized { - type Error; - - fn visit_subexpr(&mut self, subexpr: &'a SE1) -> Result; - fn visit_embed(self, embed: &'a E1) -> Result; - - fn visit_subexpr_under_binder( - mut self, - _label: &'a Label, - subexpr: &'a SE1, - ) -> Result { - self.visit_subexpr(subexpr) - } - - fn visit_embed_squash( - self, - embed: &'a E1, - ) -> Result, Self::Error> { - Ok(ExprF::Embed(self.visit_embed(embed)?)) - } -} - -impl<'a, T, SE1, SE2, E1, E2> - ExprFVeryGenericVisitor<'a, ExprF, SE1, E1> for T +impl<'a, T, SE1, SE2, E1, E2> GenericVisitor<&'a ExprF, ExprF> + for T where - T: ExprFFallibleVisitor<'a, SE1, SE2, E1, E2>, + T: ExprFInFallibleVisitor<'a, SE1, SE2, E1, E2>, { - type Error = T::Error; - type SE2 = SE2; - type E2 = E2; - - fn visit_subexpr( - &mut self, - subexpr: &'a SE1, - ) -> Result { - self.visit_subexpr(subexpr) - } - - fn visit_subexpr_under_binder( - self, - label: &'a Label, - subexpr: &'a SE1, - ) -> Result { - self.visit_subexpr_under_binder(label, subexpr) - } - - fn visit_embed_squash( - self, - embed: &'a E1, - ) -> Result, Self::Error> { - self.visit_embed_squash(embed) - } - - // Called with the result of the map, in the non-embed case. - // Useful to change the result type, and/or avoid some loss of info - fn visit_resulting_exprf( - result: ExprF, - ) -> Result, Self::Error> { - Ok(result) - } -} - -/// Like ExprFFallibleVisitor, but without the error handling. -pub trait ExprFInFallibleVisitor<'a, SE1, SE2, E1, E2>: Sized { - fn visit_subexpr(&mut self, subexpr: &'a SE1) -> SE2; - fn visit_embed(self, embed: &'a E1) -> E2; - - fn visit_subexpr_under_binder( - mut self, - _label: &'a Label, - subexpr: &'a SE1, - ) -> SE2 { - self.visit_subexpr(subexpr) - } - - fn visit_embed_squash(self, embed: &'a E1) -> ExprF { - ExprF::Embed(self.visit_embed(embed)) + fn visit(self, input: &'a ExprF) -> ExprF { + trivial_result(InfallibleWrapper(self).visit(input)) } } @@ -259,23 +191,6 @@ where ) -> Result { Ok(self.0.visit_subexpr_under_binder(label, subexpr)) } - - fn visit_embed_squash( - self, - embed: &'a E1, - ) -> Result, Self::Error> { - Ok(self.0.visit_embed_squash(embed)) - } -} - -impl<'a, T, SE1, SE2, E1, E2> GenericVisitor<&'a ExprF, ExprF> - for T -where - T: ExprFInFallibleVisitor<'a, SE1, SE2, E1, E2>, -{ - fn visit(self, input: &'a ExprF) -> ExprF { - trivial_result(InfallibleWrapper(self).visit(input)) - } } pub struct TraverseRefWithBindersVisitor { -- cgit v1.2.3 From 8d45d633dfa60e8d64c9e6e742de4e33496bf0fa Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 22:11:45 +0200 Subject: Store Imports in their own node instead of in Embed --- dhall_syntax/src/core/expr.rs | 15 ++++++++++++--- dhall_syntax/src/core/visitor.rs | 11 ++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'dhall_syntax/src/core') diff --git a/dhall_syntax/src/core/expr.rs b/dhall_syntax/src/core/expr.rs index 74eb993..4c809f8 100644 --- a/dhall_syntax/src/core/expr.rs +++ b/dhall_syntax/src/core/expr.rs @@ -12,6 +12,12 @@ pub type Double = NaiveDouble; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Void {} +impl std::fmt::Display for Void { + fn fmt(&self, _f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match *self {} + } +} + pub fn trivial_result(x: Result) -> T { match x { Ok(x) => x, @@ -233,7 +239,9 @@ pub enum ExprF { Field(SubExpr, Label), /// `e.{ x, y, z }` Projection(SubExpr, DupTreeSet