diff options
Diffstat (limited to 'dhall/src')
-rw-r--r-- | dhall/src/normalize.rs | 21 | ||||
-rw-r--r-- | dhall/src/typecheck.rs | 79 |
2 files changed, 68 insertions, 32 deletions
diff --git a/dhall/src/normalize.rs b/dhall/src/normalize.rs index 9c62923..9ca890e 100644 --- a/dhall/src/normalize.rs +++ b/dhall/src/normalize.rs @@ -9,7 +9,7 @@ use dhall_core::{ }; use dhall_generator as dhall; -use crate::expr::{Normalized, PartiallyNormalized, Typed}; +use crate::expr::{Normalized, PartiallyNormalized, Type, Typed}; type InputSubExpr = SubExpr<X, Normalized<'static>>; type OutputSubExpr = SubExpr<X, X>; @@ -365,7 +365,7 @@ pub(crate) enum WHNF { impl WHNF { /// Convert the value back to a (normalized) syntactic expression - fn normalize_to_expr(self) -> OutputSubExpr { + pub(crate) fn normalize_to_expr(self) -> OutputSubExpr { match self { WHNF::Lam(x, t, (ctx, e)) => { let ctx2 = ctx.skip(&x); @@ -615,7 +615,7 @@ impl Thunk { Thunk::Normalized(Box::new(v)) } - fn normalize(self) -> WHNF { + pub(crate) fn normalize(self) -> WHNF { match self { Thunk::Normalized(v) => *v, Thunk::Unnormalized(ctx, e) => normalize_whnf(ctx, e), @@ -634,7 +634,7 @@ impl Thunk { #[derive(Debug, Clone)] pub(crate) enum TypeThunk { Thunk(Thunk), - // Type(Type<'static>), + Type(Type<'static>), } impl TypeThunk { @@ -646,6 +646,10 @@ impl TypeThunk { TypeThunk::Thunk(th) } + pub(crate) fn from_type(t: Type<'static>) -> Self { + TypeThunk::Type(t) + } + fn from_whnf(v: WHNF) -> Self { TypeThunk::from_thunk(Thunk::from_whnf(v)) } @@ -653,12 +657,21 @@ impl TypeThunk { fn normalize(self) -> WHNF { match self { TypeThunk::Thunk(th) => th.normalize(), + // TODO: let's hope for the best with the unwraps + TypeThunk::Type(t) => normalize_whnf( + NormalizationContext::new(), + t.into_normalized().unwrap().0.embed_absurd(), + ), } } fn shift(&mut self, delta: isize, var: &V<Label>) { match self { TypeThunk::Thunk(th) => th.shift(delta, var), + TypeThunk::Type(t) => { + let shifted = t.shift(delta, var); + std::mem::replace(t, shifted); + } } } } diff --git a/dhall/src/typecheck.rs b/dhall/src/typecheck.rs index 2c3a36f..9e985e4 100644 --- a/dhall/src/typecheck.rs +++ b/dhall/src/typecheck.rs @@ -6,6 +6,7 @@ use std::fmt; use std::marker::PhantomData; use crate::expr::*; +use crate::normalize::{TypeThunk, WHNF}; use crate::traits::DynamicType; use dhall_core; use dhall_core::context::Context; @@ -113,10 +114,13 @@ impl<'a> Type<'a> { fn into_internal(self) -> TypeInternal<'a> { self.0 } - fn shift0(&self, delta: isize, label: &Label) -> Self { + fn internal_whnf(&self) -> Option<&WHNF> { + self.0.whnf() + } + pub(crate) fn shift0(&self, delta: isize, label: &Label) -> Self { Type(self.0.shift0(delta, label)) } - fn shift(&self, delta: isize, var: &V<Label>) -> Self { + pub(crate) fn shift(&self, delta: isize, var: &V<Label>) -> Self { Type(self.0.shift(delta, var)) } @@ -136,6 +140,20 @@ impl Type<'static> { } } +impl TypeThunk { + fn normalize_to_type( + self, + ctx: &TypecheckContext, + ) -> Result<Type<'static>, TypeError> { + match self { + TypeThunk::Type(t) => Ok(t), + TypeThunk::Thunk(th) => { + mktype(ctx, th.normalize().normalize_to_expr().embed_absurd()) + } + } + } +} + /// A semantic type. This is partially redundant with `dhall_core::Expr`, on purpose. `TypeInternal` should /// be limited to syntactic expressions: either written by the user or meant to be printed. /// The rule is the following: we must _not_ construct values of type `Expr` while typechecking, @@ -144,7 +162,6 @@ impl Type<'static> { pub(crate) enum TypeInternal<'a> { Const(Const), Pi(Const, Label, Box<Type<'static>>, Box<Type<'static>>), - RecordType(Const, BTreeMap<Label, Type<'static>>), UnionType(Const, BTreeMap<Label, Option<Type<'static>>>), ListType(Box<Type<'static>>), OptionalType(Box<Type<'static>>), @@ -152,12 +169,14 @@ pub(crate) enum TypeInternal<'a> { SuperType, /// This must not contain a value captured by one of the variants above. Expr(Box<Normalized<'a>>), + PNzed(Box<PartiallyNormalized<'a>>), } impl<'a> TypeInternal<'a> { pub(crate) fn into_normalized(self) -> Result<Normalized<'a>, TypeError> { Ok(match self { TypeInternal::Expr(e) => *e, + TypeInternal::PNzed(e) => e.normalize(), TypeInternal::Const(c) => const_to_normalized(c), TypeInternal::SuperType => { return Err(TypeError::new( @@ -175,13 +194,6 @@ impl<'a> TypeInternal<'a> { Some(const_to_type(c)), PhantomData, ), - TypeInternal::RecordType(c, kts) => Normalized( - rc(ExprF::RecordType(kts).traverse_ref_simple(|e| { - Ok(e.clone().into_normalized()?.into_expr()) - })?), - Some(const_to_type(c)), - PhantomData, - ), TypeInternal::UnionType(c, kts) => Normalized( rc(ExprF::UnionType(kts).traverse_ref_simple(|e| { Ok(e.clone().into_normalized()?.into_expr()) @@ -207,6 +219,12 @@ impl<'a> TypeInternal<'a> { ), }) } + fn whnf(&self) -> Option<&WHNF> { + match self { + TypeInternal::PNzed(e) => Some(&e.0), + _ => None, + } + } fn shift0(&self, delta: isize, label: &Label) -> Self { self.shift(delta, &V(label.clone(), 0)) } @@ -214,18 +232,13 @@ impl<'a> TypeInternal<'a> { use TypeInternal::*; match self { Expr(e) => Expr(Box::new(e.shift(delta, var))), + PNzed(e) => PNzed(Box::new(e.shift(delta, var))), Pi(c, x, t, e) => Pi( *c, x.clone(), Box::new(t.shift(delta, var)), Box::new(e.shift(delta, &var.shift0(1, x))), ), - RecordType(c, kts) => RecordType( - *c, - kts.iter() - .map(|(k, v)| (k.clone(), v.shift(delta, var))) - .collect(), - ), UnionType(c, kts) => UnionType( *c, kts.iter() @@ -642,10 +655,20 @@ impl TypeIntermediate { // An empty record type has type Type let k = k.unwrap_or(dhall_core::Const::Type); - Ok(TypedOrType::Type(Type(TypeInternal::RecordType( - k, - kts.clone(), - )))) + let pnormalized = PartiallyNormalized( + WHNF::RecordType( + kts.iter() + .map(|(k, t)| { + (k.clone(), TypeThunk::from_type(t.clone())) + }) + .collect(), + ), + Some(const_to_type(k)), + PhantomData, + ); + Ok(TypedOrType::Type(Type(TypeInternal::PNzed(Box::new( + pnormalized, + ))))) } TypeIntermediate::UnionType(ctx, kts) => { // Check that all types are the same const @@ -998,12 +1021,12 @@ fn type_last_layer( .normalize_to_type()?, )) } - Field(r, x) => match r.get_type()?.internal() { - TypeInternal::RecordType(_, kts) => match kts.get(&x) { - Some(t) => Ok(RetType(t.clone())), + Field(r, x) => match r.get_type()?.internal_whnf() { + Some(WHNF::RecordType(kts)) => match kts.get(&x) { + Some(tth) => Ok(RetType(tth.clone().normalize_to_type(ctx)?)), None => Err(mkerr(MissingRecordField(x, r))), }, - TypeInternal::Const(_) => { + _ => { let r = r.normalize_to_type()?; match r.internal() { TypeInternal::UnionType(_, kts) => match kts.get(&x) { @@ -1028,10 +1051,10 @@ fn type_last_layer( _ => Err(mkerr(NotARecord(x, r.into_normalized()?))), } } - _ => Err(mkerr(NotARecord( - x, - r.normalize_to_type()?.into_normalized()?, - ))), + // _ => Err(mkerr(NotARecord( + // x, + // r.normalize_to_type()?.into_normalized()?, + // ))), }, Const(c) => Ok(RetType(type_of_const(c))), Builtin(b) => Ok(RetExpr(type_of_builtin(b))), |