diff options
Diffstat (limited to 'dhall/src/semantics')
-rw-r--r-- | dhall/src/semantics/nze/lazy.rs | 32 | ||||
-rw-r--r-- | dhall/src/semantics/nze/nir.rs | 58 | ||||
-rw-r--r-- | dhall/src/semantics/nze/normalize.rs | 4 | ||||
-rw-r--r-- | dhall/src/semantics/tck/tir.rs | 3 | ||||
-rw-r--r-- | dhall/src/semantics/tck/typecheck.rs | 4 |
5 files changed, 57 insertions, 44 deletions
diff --git a/dhall/src/semantics/nze/lazy.rs b/dhall/src/semantics/nze/lazy.rs index d361313..d3b5c8d 100644 --- a/dhall/src/semantics/nze/lazy.rs +++ b/dhall/src/semantics/nze/lazy.rs @@ -35,6 +35,22 @@ where let _ = lazy.tgt.set(tgt); lazy } + + pub fn force(&self) -> &Tgt { + self.tgt.get_or_init(|| { + let src = self.src.take().unwrap(); + src.eval() + }) + } + + pub fn get_mut(&mut self) -> &mut Tgt { + self.force(); + self.tgt.get_mut().unwrap() + } + pub fn into_inner(self) -> Tgt { + self.force(); + self.tgt.into_inner().unwrap() + } } impl<Src, Tgt> Deref for Lazy<Src, Tgt> @@ -43,10 +59,18 @@ where { type Target = Tgt; fn deref(&self) -> &Self::Target { - self.tgt.get_or_init(|| { - let src = self.src.take().unwrap(); - src.eval() - }) + self.force() + } +} + +/// This implementation evaluates before cloning, because we can't clone the contents of a `Cell`. +impl<Src, Tgt> Clone for Lazy<Src, Tgt> +where + Src: Eval<Tgt>, + Tgt: Clone, +{ + fn clone(&self) -> Self { + Self::new_completed(self.force().clone()) } } diff --git a/dhall/src/semantics/nze/nir.rs b/dhall/src/semantics/nze/nir.rs index 12f1b14..7bda836 100644 --- a/dhall/src/semantics/nze/nir.rs +++ b/dhall/src/semantics/nze/nir.rs @@ -14,18 +14,13 @@ use crate::syntax::{ use crate::ToExprOptions; /// Stores a possibly unevaluated value. Gets (partially) normalized on-demand, sharing computation -/// automatically. Uses a Rc<RefCell> to share computation. +/// automatically. Uses a Rc<OnceCell> to share computation. /// If you compare for equality two `Nir`s, then equality will be up to alpha-equivalence /// (renaming of bound variables) and beta-equivalence (normalization). It will recursively /// normalize as needed. -/// Stands for "Normalized intermediate representation" +/// Stands for "Normalized Intermediate Representation" #[derive(Clone)] -pub struct Nir(Rc<NirInternal>); - -#[derive(Debug)] -struct NirInternal { - kind: lazy::Lazy<Thunk, NirKind>, -} +pub struct Nir(Rc<lazy::Lazy<Thunk, NirKind>>); /// An unevaluated subexpression #[derive(Debug, Clone)] @@ -101,17 +96,17 @@ pub enum NirKind { impl Nir { /// Construct a Nir from a completely unnormalized expression. pub fn new_thunk(env: NzEnv, hir: Hir) -> Nir { - NirInternal::from_thunk(Thunk::new(env, hir)).into_nir() + Nir(Rc::new(lazy::Lazy::new(Thunk::new(env, hir)))) } /// Construct a Nir from a partially normalized expression that's not in WHNF. pub fn from_partial_expr(e: ExprKind<Nir>) -> Nir { // TODO: env let env = NzEnv::new(); - NirInternal::from_thunk(Thunk::from_partial_expr(env, e)).into_nir() + Nir(Rc::new(lazy::Lazy::new(Thunk::from_partial_expr(env, e)))) } /// Make a Nir from a NirKind pub fn from_kind(v: NirKind) -> Nir { - NirInternal::from_whnf(v).into_nir() + Nir(Rc::new(lazy::Lazy::new_completed(v))) } pub fn from_const(c: Const) -> Self { Self::from_kind(NirKind::Const(c)) @@ -135,7 +130,20 @@ impl Nir { /// This is what you want if you want to pattern-match on the value. pub fn kind(&self) -> &NirKind { - self.0.kind() + &*self.0 + } + + /// The contents of a `Nir` are immutable and shared. If however we happen to be the sole + /// owners, we can mutate it directly. Otherwise, this clones the internal value first. + pub fn kind_mut(&mut self) -> &mut NirKind { + Rc::make_mut(&mut self.0).get_mut() + } + /// If we are the sole owner of this Nir, we can avoid a clone. + pub fn into_kind(self) -> NirKind { + match Rc::try_unwrap(self.0) { + Ok(lazy) => lazy.into_inner(), + Err(rc) => (**rc).clone(), + } } pub fn to_type(&self, u: impl Into<Universe>) -> Type { @@ -273,26 +281,6 @@ impl Nir { } } -impl NirInternal { - fn from_whnf(k: NirKind) -> Self { - NirInternal { - kind: lazy::Lazy::new_completed(k), - } - } - fn from_thunk(th: Thunk) -> Self { - NirInternal { - kind: lazy::Lazy::new(th), - } - } - fn into_nir(self) -> Nir { - Nir(Rc::new(self)) - } - - fn kind(&self) -> &NirKind { - &self.kind - } -} - impl NirKind { pub fn into_nir(self) -> Nir { Nir::from_kind(self) @@ -448,13 +436,11 @@ impl std::cmp::Eq for Closure {} impl std::fmt::Debug for Nir { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let vint: &NirInternal = &self.0; - let kind = vint.kind(); - if let NirKind::Const(c) = kind { + if let NirKind::Const(c) = self.kind() { return write!(fmt, "{:?}", c); } let mut x = fmt.debug_struct("Nir"); - x.field("kind", kind); + x.field("kind", self.kind()); x.finish() } } diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index d042f3f..62efc5f 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -84,7 +84,7 @@ where pub type Ret = NirKind; pub fn ret_nir(x: Nir) -> Ret { - ret_ref(&x) + x.into_kind() } pub fn ret_kind(x: NirKind) -> Ret { x @@ -144,7 +144,7 @@ pub fn normalize_one_layer(expr: ExprKind<Nir>, env: &NzEnv) -> NirKind { ExprKind::UnionType(kvs) => { ret_kind(UnionType(kvs.into_iter().collect())) } - ExprKind::Op(ref op) => normalize_operation(op), + ExprKind::Op(op) => normalize_operation(op), ExprKind::Annot(x, _) => ret_nir(x), ExprKind::Assert(x) => ret_kind(Assert(x)), ExprKind::Import(..) => { diff --git a/dhall/src/semantics/tck/tir.rs b/dhall/src/semantics/tck/tir.rs index ec15a1f..f34802c 100644 --- a/dhall/src/semantics/tck/tir.rs +++ b/dhall/src/semantics/tck/tir.rs @@ -117,6 +117,9 @@ impl<'hir> Tir<'hir> { pub fn ty(&self) -> &Type { &self.ty } + pub fn into_ty(self) -> Type { + self.ty + } pub fn to_hir(&self) -> Hir { self.as_hir().clone() diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index d21c7ce..498bd76 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -35,7 +35,7 @@ fn type_one_layer( ) -> Result<Type, TypeError> { let span_err = |msg: &str| mk_span_err(span.clone(), msg); - Ok(match &ekind { + Ok(match ekind { ExprKind::Import(..) => { unreachable!("This case should have been handled in resolution") } @@ -57,7 +57,7 @@ fn type_one_layer( NumKind::Double(_) => Builtin::Double, }), ExprKind::Builtin(b) => { - let t_hir = type_of_builtin(*b); + let t_hir = type_of_builtin(b); typecheck(&t_hir)?.eval_to_type(env)? } ExprKind::TextLit(interpolated) => { |