From 1ed3123aeb3c9272b6810605a7ee781c42095f09 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 17:20:35 +0200 Subject: Swap Typed and TypeThunk --- dhall/src/phase/mod.rs | 95 +++++++++++++------------------------------------- 1 file changed, 25 insertions(+), 70 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index ccedff2..0b05227 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -4,14 +4,12 @@ use std::path::Path; use dhall_syntax::{Const, Import, Span, SubExpr, X}; -use crate::core::context::TypecheckContext; -use crate::core::thunk::Thunk; +use crate::core::thunk::{Thunk, TypeThunk}; use crate::core::value::Value; use crate::core::var::{AlphaVar, Shift, Subst}; -use crate::error::{EncodeError, Error, ImportError, TypeError, TypeMessage}; +use crate::error::{EncodeError, Error, ImportError, TypeError}; use resolve::ImportRoot; -use typecheck::type_of_const; pub(crate) mod binary; pub(crate) mod normalize; @@ -33,16 +31,7 @@ pub struct Resolved(ResolvedSubExpr); /// A typed expression #[derive(Debug, Clone)] -pub enum Typed { - // Any value, along with (optionally) its type - Untyped(Thunk), - Typed(Thunk, Box), - // One of the base higher-kinded typed. - // Used to avoid storing the same tower ot Type->Kind->Sort - // over and over again. Also enables having Sort as a type - // even though it doesn't itself have a type. - Const(Const), -} +pub struct Typed(TypeThunk); /// A normalized expression. /// @@ -105,83 +94,63 @@ impl Typed { /// /// However, `normalize` will not fail if the expression is ill-typed and will /// leave ill-typed sub-expressions unevaluated. - pub fn normalize(self) -> Normalized { - match &self { - Typed::Const(_) => {} - Typed::Untyped(thunk) | Typed::Typed(thunk, _) => { - thunk.normalize_nf(); - } - } + pub fn normalize(mut self) -> Normalized { + self.normalize_mut(); Normalized(self) } pub fn from_thunk_and_type(th: Thunk, t: Type) -> Self { - Typed::Typed(th, Box::new(t)) + Typed(TypeThunk::from_thunk_and_type(th, t)) } pub fn from_thunk_untyped(th: Thunk) -> Self { - Typed::Untyped(th) + Typed(TypeThunk::from_thunk_untyped(th)) } pub fn from_const(c: Const) -> Self { - Typed::Const(c) + Typed(TypeThunk::from_const(c)) } pub fn from_value_untyped(v: Value) -> Self { - Typed::from_thunk_untyped(Thunk::from_value(v)) + Typed(TypeThunk::from_value_untyped(v)) + } + pub fn from_typethunk(th: TypeThunk) -> Self { + Typed(th) } - // TODO: Avoid cloning if possible pub fn to_value(&self) -> Value { - match self { - Typed::Untyped(th) | Typed::Typed(th, _) => th.to_value(), - Typed::Const(c) => Value::Const(*c), - } + self.0.to_value() } pub fn to_expr(&self) -> NormalizedSubExpr { - self.to_value().normalize_to_expr() + self.0.to_expr() } pub fn to_expr_alpha(&self) -> NormalizedSubExpr { - self.to_value().normalize_to_expr_maybe_alpha(true) + self.0.to_expr_alpha() } pub fn to_thunk(&self) -> Thunk { - match self { - Typed::Untyped(th) | Typed::Typed(th, _) => th.clone(), - Typed::Const(c) => Thunk::from_value(Value::Const(*c)), - } + self.0.to_thunk() } // Deprecated pub fn to_type(&self) -> Type { - self.clone().into_type() + self.clone() } // Deprecated pub fn into_type(self) -> Type { self } + pub fn into_typethunk(self) -> TypeThunk { + self.0 + } pub fn to_normalized(&self) -> Normalized { self.clone().normalize() } pub fn as_const(&self) -> Option { - // TODO: avoid clone - match &self.to_value() { - Value::Const(c) => Some(*c), - _ => None, - } + self.0.as_const() } pub fn normalize_mut(&mut self) { - match self { - Typed::Untyped(th) | Typed::Typed(th, _) => th.normalize_mut(), - Typed::Const(_) => {} - } + self.0.normalize_mut() } pub fn get_type(&self) -> Result, TypeError> { - match self { - Typed::Untyped(_) => Err(TypeError::new( - &TypecheckContext::new(), - TypeMessage::Untyped, - )), - Typed::Typed(_, t) => Ok(Cow::Borrowed(t)), - Typed::Const(c) => Ok(Cow::Owned(type_of_const(*c)?)), - } + self.0.get_type() } } @@ -208,14 +177,7 @@ impl Normalized { impl Shift for Typed { fn shift(&self, delta: isize, var: &AlphaVar) -> Option { - Some(match self { - Typed::Untyped(th) => Typed::Untyped(th.shift(delta, var)?), - Typed::Typed(th, t) => Typed::Typed( - th.shift(delta, var)?, - Box::new(t.shift(delta, var)?), - ), - Typed::Const(c) => Typed::Const(*c), - }) + Some(Typed(self.0.shift(delta, var)?)) } } @@ -227,14 +189,7 @@ impl Shift for Normalized { impl Subst for Typed { fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self { - match self { - Typed::Untyped(th) => Typed::Untyped(th.subst_shift(var, val)), - Typed::Typed(th, t) => Typed::Typed( - th.subst_shift(var, val), - Box::new(t.subst_shift(var, val)), - ), - Typed::Const(c) => Typed::Const(*c), - } + Typed(self.0.subst_shift(var, val)) } } -- cgit v1.2.3 From fb0120dffe8e9552c3da7b994ad850f66dc612a3 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 17:21:54 +0200 Subject: s/TypeThunk/TypedThunk/g --- dhall/src/phase/mod.rs | 16 ++++++++-------- dhall/src/phase/normalize.rs | 34 +++++++++++++++++----------------- dhall/src/phase/typecheck.rs | 40 ++++++++++++++++++++++++---------------- 3 files changed, 49 insertions(+), 41 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 0b05227..27a6901 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -4,7 +4,7 @@ use std::path::Path; use dhall_syntax::{Const, Import, Span, SubExpr, X}; -use crate::core::thunk::{Thunk, TypeThunk}; +use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; use crate::core::var::{AlphaVar, Shift, Subst}; use crate::error::{EncodeError, Error, ImportError, TypeError}; @@ -31,7 +31,7 @@ pub struct Resolved(ResolvedSubExpr); /// A typed expression #[derive(Debug, Clone)] -pub struct Typed(TypeThunk); +pub struct Typed(TypedThunk); /// A normalized expression. /// @@ -100,18 +100,18 @@ impl Typed { } pub fn from_thunk_and_type(th: Thunk, t: Type) -> Self { - Typed(TypeThunk::from_thunk_and_type(th, t)) + Typed(TypedThunk::from_thunk_and_type(th, t)) } pub fn from_thunk_untyped(th: Thunk) -> Self { - Typed(TypeThunk::from_thunk_untyped(th)) + Typed(TypedThunk::from_thunk_untyped(th)) } pub fn from_const(c: Const) -> Self { - Typed(TypeThunk::from_const(c)) + Typed(TypedThunk::from_const(c)) } pub fn from_value_untyped(v: Value) -> Self { - Typed(TypeThunk::from_value_untyped(v)) + Typed(TypedThunk::from_value_untyped(v)) } - pub fn from_typethunk(th: TypeThunk) -> Self { + pub fn from_typethunk(th: TypedThunk) -> Self { Typed(th) } @@ -135,7 +135,7 @@ impl Typed { pub fn into_type(self) -> Type { self } - pub fn into_typethunk(self) -> TypeThunk { + pub fn into_typethunk(self) -> TypedThunk { self.0 } pub fn to_normalized(&self) -> Normalized { diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 405677a..644f98c 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -6,7 +6,7 @@ use dhall_syntax::{ }; use crate::core::context::NormalizationContext; -use crate::core::thunk::{Thunk, TypeThunk}; +use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; use crate::core::var::Subst; use crate::phase::{NormalizedSubExpr, ResolvedSubExpr, Typed}; @@ -22,7 +22,7 @@ pub fn apply_builtin(b: Builtin, args: Vec) -> Value { // Return Ok((unconsumed args, returned value)), or Err(()) if value could not be produced. let ret = match (b, args.as_slice()) { (OptionalNone, [t, r..]) => { - Ok((r, EmptyOptionalLit(TypeThunk::from_thunk(t.clone())))) + Ok((r, EmptyOptionalLit(TypedThunk::from_thunk(t.clone())))) } (NaturalIsZero, [n, r..]) => match &*n.as_value() { NaturalLit(n) => Ok((r, BoolLit(*n == 0))), @@ -144,10 +144,10 @@ pub fn apply_builtin(b: Builtin, args: Vec) -> Value { let mut kts = HashMap::new(); kts.insert( "index".into(), - TypeThunk::from_value(Value::from_builtin(Natural)), + TypedThunk::from_value(Value::from_builtin(Natural)), ); kts.insert("value".into(), t.clone()); - Ok((r, EmptyListLit(TypeThunk::from_value(RecordType(kts))))) + Ok((r, EmptyListLit(TypedThunk::from_value(RecordType(kts))))) } NEListLit(xs) => { let xs = xs @@ -179,10 +179,10 @@ pub fn apply_builtin(b: Builtin, args: Vec) -> Value { r, f.app_val(Value::from_builtin(List).app_thunk(t.clone())) .app_val(ListConsClosure( - TypeThunk::from_thunk(t.clone()), + TypedThunk::from_thunk(t.clone()), None, )) - .app_val(EmptyListLit(TypeThunk::from_thunk(t.clone()))), + .app_val(EmptyListLit(TypedThunk::from_thunk(t.clone()))), )), }, (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_value() { @@ -213,10 +213,10 @@ pub fn apply_builtin(b: Builtin, args: Vec) -> Value { _ => Ok(( r, f.app_val(Value::from_builtin(Optional).app_thunk(t.clone())) - .app_val(OptionalSomeClosure(TypeThunk::from_thunk( + .app_val(OptionalSomeClosure(TypedThunk::from_thunk( t.clone(), ))) - .app_val(EmptyOptionalLit(TypeThunk::from_thunk( + .app_val(EmptyOptionalLit(TypedThunk::from_thunk( t.clone(), ))), )), @@ -618,7 +618,7 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { } (RecursiveRecordTypeMerge, RecordType(kvs1), RecordType(kvs2)) => { let kvs = merge_maps(kvs1, kvs2, |v1, v2| { - TypeThunk::from_thunk(Thunk::from_partial_expr(ExprF::BinOp( + TypedThunk::from_thunk(Thunk::from_partial_expr(ExprF::BinOp( RecursiveRecordTypeMerge, v1.to_thunk(), v2.to_thunk(), @@ -628,8 +628,8 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { } (Equivalence, _, _) => Ret::Value(Value::Equivalence( - TypeThunk::from_thunk(x.clone()), - TypeThunk::from_thunk(y.clone()), + TypedThunk::from_thunk(x.clone()), + TypedThunk::from_thunk(y.clone()), )), _ => return None, @@ -649,12 +649,12 @@ pub fn normalize_one_layer(expr: ExprF) -> Value { ExprF::Annot(x, _) => Ret::Thunk(x), ExprF::Assert(_) => Ret::Expr(expr), ExprF::Lam(x, t, e) => { - Ret::Value(Lam(x.into(), TypeThunk::from_thunk(t), e)) + Ret::Value(Lam(x.into(), TypedThunk::from_thunk(t), e)) } ExprF::Pi(x, t, e) => Ret::Value(Pi( x.into(), - TypeThunk::from_thunk(t), - TypeThunk::from_thunk(e), + TypedThunk::from_thunk(t), + TypedThunk::from_thunk(e), )), ExprF::Let(x, _, v, b) => { let v = Typed::from_thunk_untyped(v); @@ -673,7 +673,7 @@ pub fn normalize_one_layer(expr: ExprF) -> Value { let t_borrow = t.as_value(); match &*t_borrow { AppliedBuiltin(Builtin::List, args) if args.len() == 1 => { - Ret::Value(EmptyListLit(TypeThunk::from_thunk( + Ret::Value(EmptyListLit(TypedThunk::from_thunk( args[0].clone(), ))) } @@ -691,12 +691,12 @@ pub fn normalize_one_layer(expr: ExprF) -> Value { } ExprF::RecordType(kts) => Ret::Value(RecordType( kts.into_iter() - .map(|(k, t)| (k, TypeThunk::from_thunk(t))) + .map(|(k, t)| (k, TypedThunk::from_thunk(t))) .collect(), )), ExprF::UnionType(kts) => Ret::Value(UnionType( kts.into_iter() - .map(|(k, t)| (k, t.map(|t| TypeThunk::from_thunk(t)))) + .map(|(k, t)| (k, t.map(|t| TypedThunk::from_thunk(t)))) .collect(), )), ExprF::TextLit(elts) => { diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 299997a..a19e1ca 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -6,7 +6,7 @@ use dhall_syntax::{ }; use crate::core::context::{NormalizationContext, TypecheckContext}; -use crate::core::thunk::{Thunk, TypeThunk}; +use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; use crate::core::var::{Shift, Subst}; use crate::error::{TypeError, TypeMessage}; @@ -44,8 +44,12 @@ fn tck_pi_type( let k = function_check(ka, kb); Ok(Typed::from_thunk_and_type( - Value::Pi(x.into(), TypeThunk::from_type(tx), TypeThunk::from_type(te)) - .into_thunk(), + Value::Pi( + x.into(), + TypedThunk::from_type(tx), + TypedThunk::from_type(te), + ) + .into_thunk(), Type::from_const(k), )) } @@ -77,7 +81,7 @@ fn tck_record_type( return Err(TypeError::new(ctx, RecordTypeDuplicateField)) } Entry::Vacant(_) => { - entry.or_insert_with(|| TypeThunk::from_type(t.clone())) + entry.or_insert_with(|| TypedThunk::from_type(t.clone())) } }; } @@ -119,7 +123,7 @@ fn tck_union_type( return Err(TypeError::new(ctx, UnionTypeDuplicateField)) } Entry::Vacant(_) => entry.or_insert_with(|| { - t.as_ref().map(|t| TypeThunk::from_type(t.clone())) + t.as_ref().map(|t| TypedThunk::from_type(t.clone())) }), }; } @@ -334,7 +338,7 @@ fn type_with( let b = type_with(&ctx2, b.clone())?; let v = Value::Lam( x.clone().into(), - TypeThunk::from_type(tx.clone()), + TypedThunk::from_type(tx.clone()), b.to_thunk(), ); let tb = b.get_type()?.into_owned(); @@ -658,8 +662,8 @@ fn type_last_layer( // records of records when merging. fn combine_record_types( ctx: &TypecheckContext, - kts_l: HashMap, - kts_r: HashMap, + kts_l: HashMap, + kts_r: HashMap, ) -> Result { use crate::phase::normalize::outer_join; @@ -667,8 +671,8 @@ fn type_last_layer( // are records themselves, then we hit the recursive case. // Otherwise we have a field collision. let combine = |k: &Label, - inner_l: &TypeThunk, - inner_r: &TypeThunk| + inner_l: &TypedThunk, + inner_r: &TypedThunk| -> Result { match (inner_l.to_value(), inner_r.to_value()) { ( @@ -686,7 +690,9 @@ fn type_last_layer( let kts: HashMap> = outer_join( |l| Ok(l.to_type()), |r| Ok(r.to_type()), - |k: &Label, l: &TypeThunk, r: &TypeThunk| combine(k, l, r), + |k: &Label, l: &TypedThunk, r: &TypedThunk| { + combine(k, l, r) + }, &kts_l, &kts_r, ); @@ -729,8 +735,8 @@ fn type_last_layer( // records of records when merging. fn combine_record_types( ctx: &TypecheckContext, - kts_l: HashMap, - kts_r: HashMap, + kts_l: HashMap, + kts_r: HashMap, ) -> Result { use crate::phase::normalize::intersection_with_key; @@ -738,8 +744,8 @@ fn type_last_layer( // are records themselves, then we hit the recursive case. // Otherwise we have a field collision. let combine = |k: &Label, - kts_l_inner: &TypeThunk, - kts_r_inner: &TypeThunk| + kts_l_inner: &TypedThunk, + kts_r_inner: &TypedThunk| -> Result { match (kts_l_inner.to_value(), kts_r_inner.to_value()) { ( @@ -755,7 +761,9 @@ fn type_last_layer( }; let kts = intersection_with_key( - |k: &Label, l: &TypeThunk, r: &TypeThunk| combine(k, l, r), + |k: &Label, l: &TypedThunk, r: &TypedThunk| { + combine(k, l, r) + }, &kts_l, &kts_r, ); -- cgit v1.2.3 From 5895c3aa6552f75d7e5202be561f9734fe8945e7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 19:31:23 +0200 Subject: No need to track the absence of `Span`s at the type level --- dhall/src/phase/binary.rs | 45 +++++++++++++++++++++----------------------- dhall/src/phase/mod.rs | 10 +++++----- dhall/src/phase/parse.rs | 4 ++-- dhall/src/phase/typecheck.rs | 16 ++++++++-------- 4 files changed, 36 insertions(+), 39 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index f4a9cc1..3292617 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -631,14 +631,12 @@ where ImportLocation::Remote(url) => { match &url.headers { None => ser_seq.serialize_element(&Null)?, - Some(location_hashed) => { - ser_seq.serialize_element(&self::Serialize::Expr( - &SubExpr::from_expr_no_note(ExprF::Embed(Import { - mode: ImportMode::Code, - location_hashed: location_hashed.as_ref().clone(), - })), - ))? - } + Some(location_hashed) => ser_seq.serialize_element( + &self::Serialize::Expr(&rc(ExprF::Embed(Import { + mode: ImportMode::Code, + location_hashed: location_hashed.as_ref().clone(), + }))), + )?, }; ser_seq.serialize_element(&url.authority)?; for p in &url.path { @@ -689,13 +687,13 @@ impl<'a> serde::ser::Serialize for Serialize<'a> { } } -fn collect_nested_applications<'a, N, E>( - e: &'a SubExpr, -) -> (&'a SubExpr, Vec<&'a SubExpr>) { - fn go<'a, N, E>( - e: &'a SubExpr, - vec: &mut Vec<&'a SubExpr>, - ) -> &'a SubExpr { +fn collect_nested_applications<'a, E>( + e: &'a SubExpr, +) -> (&'a SubExpr, Vec<&'a SubExpr>) { + fn go<'a, E>( + e: &'a SubExpr, + vec: &mut Vec<&'a SubExpr>, + ) -> &'a SubExpr { match e.as_ref() { ExprF::App(f, a) => { vec.push(a); @@ -709,16 +707,15 @@ fn collect_nested_applications<'a, N, E>( (e, vec) } -type LetBinding<'a, N, E> = - (&'a Label, &'a Option>, &'a SubExpr); +type LetBinding<'a, E> = (&'a Label, &'a Option>, &'a SubExpr); -fn collect_nested_lets<'a, N, E>( - e: &'a SubExpr, -) -> (&'a SubExpr, Vec>) { - fn go<'a, N, E>( - e: &'a SubExpr, - vec: &mut Vec>, - ) -> &'a SubExpr { +fn collect_nested_lets<'a, E>( + e: &'a SubExpr, +) -> (&'a SubExpr, Vec>) { + fn go<'a, E>( + e: &'a SubExpr, + vec: &mut Vec>, + ) -> &'a SubExpr { match e.as_ref() { ExprF::Let(l, t, v, e) => { vec.push((l, t, v)); diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 27a6901..8c93889 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::fmt::Display; use std::path::Path; -use dhall_syntax::{Const, Import, Span, SubExpr, X}; +use dhall_syntax::{Const, Import, SubExpr, X}; use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; @@ -17,10 +17,10 @@ pub(crate) mod parse; pub(crate) mod resolve; pub(crate) mod typecheck; -pub type ParsedSubExpr = SubExpr; -pub type DecodedSubExpr = SubExpr; -pub type ResolvedSubExpr = SubExpr; -pub type NormalizedSubExpr = SubExpr; +pub type ParsedSubExpr = SubExpr; +pub type DecodedSubExpr = SubExpr; +pub type ResolvedSubExpr = SubExpr; +pub type NormalizedSubExpr = SubExpr; #[derive(Debug, Clone)] pub struct Parsed(ParsedSubExpr, ImportRoot); diff --git a/dhall/src/phase/parse.rs b/dhall/src/phase/parse.rs index 734f6e1..9f3f2f4 100644 --- a/dhall/src/phase/parse.rs +++ b/dhall/src/phase/parse.rs @@ -25,7 +25,7 @@ pub fn parse_str(s: &str) -> Result { pub fn parse_binary(data: &[u8]) -> Result { let expr = crate::phase::binary::decode(data)?; let root = ImportRoot::LocalDir(std::env::current_dir()?); - Ok(Parsed(expr.note_absurd(), root)) + Ok(Parsed(expr, root)) } pub fn parse_binary_file(f: &Path) -> Result { @@ -33,5 +33,5 @@ pub fn parse_binary_file(f: &Path) -> Result { File::open(f)?.read_to_end(&mut buffer)?; let expr = crate::phase::binary::decode(&buffer)?; let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); - Ok(Parsed(expr.note_absurd(), root)) + Ok(Parsed(expr, root)) } diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index a19e1ca..ecf9793 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use dhall_syntax::{ - rc, Builtin, Const, Expr, ExprF, InterpolatedTextContents, Label, Span, - SubExpr, X, + rc, Builtin, Const, Expr, ExprF, InterpolatedTextContents, Label, SubExpr, + X, }; use crate::core::context::{NormalizationContext, TypecheckContext}; @@ -214,7 +214,7 @@ macro_rules! make_type { }; } -fn type_of_builtin(b: Builtin) -> Expr { +fn type_of_builtin(b: Builtin) -> Expr { use dhall_syntax::Builtin::*; match b { Bool | Natural | Integer | Double | Text => make_type!(Type), @@ -303,7 +303,7 @@ fn type_of_builtin(b: Builtin) -> Expr { /// and turn it into a type, typechecking it along the way. pub fn mktype( ctx: &TypecheckContext, - e: SubExpr, + e: SubExpr, ) -> Result { Ok(type_with(ctx, e)?.to_type()) } @@ -326,7 +326,7 @@ enum Ret { /// normalized as well. fn type_with( ctx: &TypecheckContext, - e: SubExpr, + e: SubExpr, ) -> Result { use dhall_syntax::ExprF::{Annot, Embed, Lam, Let, Pi, Var}; @@ -1002,7 +1002,7 @@ fn type_last_layer( /// `typeOf` is the same as `type_with` with an empty context, meaning that the /// expression must be closed (i.e. no free variables), otherwise type-checking /// will fail. -fn type_of(e: SubExpr) -> Result { +fn type_of(e: SubExpr) -> Result { let ctx = TypecheckContext::new(); let e = type_with(&ctx, e)?; // Ensure `e` has a type (i.e. `e` is not `Sort`) @@ -1015,8 +1015,8 @@ pub fn typecheck(e: Resolved) -> Result { } pub fn typecheck_with(e: Resolved, ty: &Type) -> Result { - let expr: SubExpr<_, _> = e.0; - let ty: SubExpr<_, _> = ty.to_expr().absurd(); + let expr: SubExpr<_> = e.0; + let ty: SubExpr<_> = ty.to_expr().absurd(); type_of(expr.rewrap(ExprF::Annot(expr.clone(), ty))) } pub fn skip_typecheck(e: Resolved) -> Typed { -- cgit v1.2.3 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/src/phase/mod.rs | 4 ++-- dhall/src/phase/normalize.rs | 21 +++++++++++---------- dhall/src/phase/typecheck.rs | 11 ++++------- 3 files changed, 17 insertions(+), 19 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 8c93889..7364949 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::fmt::Display; use std::path::Path; -use dhall_syntax::{Const, Import, SubExpr, X}; +use dhall_syntax::{Const, Import, SubExpr}; use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; @@ -20,7 +20,7 @@ pub(crate) mod typecheck; pub type ParsedSubExpr = SubExpr; pub type DecodedSubExpr = SubExpr; pub type ResolvedSubExpr = SubExpr; -pub type NormalizedSubExpr = SubExpr; +pub type NormalizedSubExpr = SubExpr; #[derive(Debug, Clone)] pub struct Parsed(ParsedSubExpr, ImportRoot); diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 644f98c..f1045a5 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -2,14 +2,14 @@ use std::collections::HashMap; use dhall_syntax::{ BinOp, Builtin, ExprF, InterpolatedText, InterpolatedTextContents, - NaiveDouble, X, + NaiveDouble, }; use crate::core::context::NormalizationContext; use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; use crate::core::var::Subst; -use crate::phase::{NormalizedSubExpr, ResolvedSubExpr, Typed}; +use crate::phase::{Normalized, NormalizedSubExpr, ResolvedSubExpr, Typed}; pub type InputSubExpr = ResolvedSubExpr; pub type OutputSubExpr = NormalizedSubExpr; @@ -86,7 +86,7 @@ pub fn apply_builtin(b: Builtin, args: Vec) -> Value { // Empty string literal. [] => { // Printing InterpolatedText takes care of all the escaping - let txt: InterpolatedText = + let txt: InterpolatedText = std::iter::empty().collect(); let s = txt.to_string(); Ok(( @@ -98,10 +98,11 @@ pub fn apply_builtin(b: Builtin, args: Vec) -> Value { // interpolations, there is a single Text item) in the literal. [InterpolatedTextContents::Text(s)] => { // Printing InterpolatedText takes care of all the escaping - let txt: InterpolatedText = std::iter::once( - InterpolatedTextContents::Text(s.clone()), - ) - .collect(); + let txt: InterpolatedText = + std::iter::once(InterpolatedTextContents::Text( + s.clone(), + )) + .collect(); let s = txt.to_string(); Ok(( r, @@ -376,7 +377,7 @@ pub fn normalize_whnf(ctx: NormalizationContext, expr: InputSubExpr) -> Value { } // Thunk subexpressions - let expr: ExprF = + let expr: ExprF = expr.as_ref().map_ref_with_special_handling_of_binders( |e| Thunk::new(ctx.clone(), e.clone()), |x, e| Thunk::new(ctx.skip(x), e.clone()), @@ -391,7 +392,7 @@ enum Ret<'a> { Value(Value), Thunk(Thunk), ThunkRef(&'a Thunk), - Expr(ExprF), + Expr(ExprF), } /// Performs an intersection of two HashMaps. @@ -636,7 +637,7 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { }) } -pub fn normalize_one_layer(expr: ExprF) -> Value { +pub fn normalize_one_layer(expr: ExprF) -> Value { use Value::{ AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, Lam, NEListLit, NEOptionalLit, NaturalLit, Pi, RecordLit, RecordType, diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index ecf9793..96ff246 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -2,7 +2,6 @@ use std::collections::HashMap; use dhall_syntax::{ rc, Builtin, Const, Expr, ExprF, InterpolatedTextContents, Label, SubExpr, - X, }; use crate::core::context::{NormalizationContext, TypecheckContext}; @@ -214,7 +213,7 @@ macro_rules! make_type { }; } -fn type_of_builtin(b: Builtin) -> Expr { +fn type_of_builtin(b: Builtin) -> Expr { use dhall_syntax::Builtin::*; match b { Bool | Natural | Integer | Double | Text => make_type!(Type), @@ -398,7 +397,7 @@ fn type_with( /// layer. fn type_last_layer( ctx: &TypecheckContext, - e: &ExprF, + e: &ExprF, ) -> Result { use crate::error::TypeMessage::*; use dhall_syntax::BinOp::*; @@ -598,9 +597,7 @@ fn type_last_layer( } } Const(c) => Ok(RetWhole(Typed::from_const(*c))), - Builtin(b) => { - Ok(RetTypeOnly(mktype(ctx, rc(type_of_builtin(*b)).absurd())?)) - } + Builtin(b) => Ok(RetTypeOnly(mktype(ctx, rc(type_of_builtin(*b)))?)), BoolLit(_) => Ok(RetTypeOnly(builtin_to_type(Bool)?)), NaturalLit(_) => Ok(RetTypeOnly(builtin_to_type(Natural)?)), IntegerLit(_) => Ok(RetTypeOnly(builtin_to_type(Integer)?)), @@ -1016,7 +1013,7 @@ pub fn typecheck(e: Resolved) -> Result { pub fn typecheck_with(e: Resolved, ty: &Type) -> Result { let expr: SubExpr<_> = e.0; - let ty: SubExpr<_> = ty.to_expr().absurd(); + let ty: SubExpr<_> = ty.to_expr(); type_of(expr.rewrap(ExprF::Annot(expr.clone(), ty))) } pub fn skip_typecheck(e: Resolved) -> Typed { -- 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/src/phase/normalize.rs | 1 - dhall/src/phase/typecheck.rs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index f1045a5..2970f5f 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -381,7 +381,6 @@ pub fn normalize_whnf(ctx: NormalizationContext, expr: InputSubExpr) -> Value { expr.as_ref().map_ref_with_special_handling_of_binders( |e| Thunk::new(ctx.clone(), e.clone()), |x, e| Thunk::new(ctx.skip(x), e.clone()), - |_| unreachable!(), ); normalize_one_layer(expr) diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 96ff246..e8b2544 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -376,12 +376,11 @@ fn type_with( e.as_ref().traverse_ref_with_special_handling_of_binders( |e| type_with(ctx, e.clone()), |_, _| unreachable!(), - |_| unreachable!(), )?; let ret = type_last_layer(ctx, &expr)?; match ret { RetTypeOnly(typ) => { - let expr = expr.map_ref_simple(|typed| typed.to_thunk()); + let expr = expr.map_ref(|typed| typed.to_thunk()); Typed::from_thunk_and_type( Thunk::from_partial_expr(expr), typ, -- 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/src/phase/binary.rs | 24 ++++++++++++++---------- dhall/src/phase/mod.rs | 8 +++++--- dhall/src/phase/normalize.rs | 3 +++ dhall/src/phase/typecheck.rs | 3 +++ 4 files changed, 25 insertions(+), 13 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index 3292617..b3a80aa 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -19,7 +19,6 @@ pub fn decode(data: &[u8]) -> Result { } } -//TODO: encode normalized expression too pub fn encode(expr: &ParsedSubExpr) -> Result, EncodeError> { serde_cbor::ser::to_vec(&Serialize::Expr(expr)) .map_err(|e| EncodeError::CBORError(e)) @@ -264,7 +263,7 @@ fn cbor_value_to_dhall( // TODO // Some(x) => { // match cbor_value_to_dhall(&x)?.as_ref() { - // Embed(import) => Some(Box::new( + // Import(import) => Some(Box::new( // import.location_hashed.clone(), // )), // _ => Err(DecodeError::WrongFormatError( @@ -340,7 +339,7 @@ fn cbor_value_to_dhall( "import/type".to_owned(), ))?, }; - Embed(Import { + Import(dhall_syntax::Import { mode, location_hashed: ImportHashed { hash, location }, }) @@ -573,7 +572,10 @@ where .chain(once(expr(x))) .chain(ls.iter().map(label)), ), - Embed(import) => serialize_import(ser, import), + Import(import) => serialize_import(ser, import), + Embed(_) => unimplemented!( + "An expression with resolved imports cannot be binary-encoded" + ), } } @@ -631,12 +633,14 @@ where ImportLocation::Remote(url) => { match &url.headers { None => ser_seq.serialize_element(&Null)?, - Some(location_hashed) => ser_seq.serialize_element( - &self::Serialize::Expr(&rc(ExprF::Embed(Import { - mode: ImportMode::Code, - location_hashed: location_hashed.as_ref().clone(), - }))), - )?, + Some(location_hashed) => { + ser_seq.serialize_element(&self::Serialize::Expr(&rc( + ExprF::Import(dhall_syntax::Import { + mode: ImportMode::Code, + location_hashed: location_hashed.as_ref().clone(), + }), + )))? + } }; ser_seq.serialize_element(&url.authority)?; for p in &url.path { diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 7364949..a1e3f29 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::fmt::Display; use std::path::Path; -use dhall_syntax::{Const, Import, SubExpr}; +use dhall_syntax::{Const, SubExpr, Void}; use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; @@ -17,8 +17,8 @@ pub(crate) mod parse; pub(crate) mod resolve; pub(crate) mod typecheck; -pub type ParsedSubExpr = SubExpr; -pub type DecodedSubExpr = SubExpr; +pub type ParsedSubExpr = SubExpr; +pub type DecodedSubExpr = SubExpr; pub type ResolvedSubExpr = SubExpr; pub type NormalizedSubExpr = SubExpr; @@ -26,6 +26,8 @@ pub type NormalizedSubExpr = SubExpr; pub struct Parsed(ParsedSubExpr, ImportRoot); /// An expression where all imports have been resolved +/// +/// Invariant: there must be no `Import` nodes or `ImportAlt` operations left. #[derive(Debug, Clone)] pub struct Resolved(ResolvedSubExpr); diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 2970f5f..adbcb02 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -644,6 +644,9 @@ pub fn normalize_one_layer(expr: ExprF) -> Value { }; let ret = match expr { + ExprF::Import(_) => unreachable!( + "There should remain no imports in a resolved expression" + ), ExprF::Embed(_) => unreachable!(), ExprF::Var(_) => unreachable!(), ExprF::Annot(x, _) => Ret::Thunk(x), diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index e8b2544..89e2da8 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -407,6 +407,9 @@ fn type_last_layer( let mkerr = |msg: TypeMessage| TypeError::new(ctx, msg); match e { + Import(_) => unreachable!( + "There should remain no imports in a resolved expression" + ), Lam(_, _, _) | Pi(_, _, _) | Let(_, _, _, _) | Embed(_) | Var(_) => { unreachable!() } -- cgit v1.2.3 From c600bae72198350b78fe19cf993b7f4c6f35225a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 23:08:48 +0200 Subject: Implement Hash for ParsedSubExpr --- dhall/src/phase/binary.rs | 41 ++++++++++++++++++----------------------- dhall/src/phase/mod.rs | 16 ++++++++++++++++ 2 files changed, 34 insertions(+), 23 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index b3a80aa..9ed823c 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -10,7 +10,7 @@ use dhall_syntax::{ }; use crate::error::{DecodeError, EncodeError}; -use crate::phase::{DecodedSubExpr, ParsedSubExpr}; +use crate::phase::DecodedSubExpr; pub fn decode(data: &[u8]) -> Result { match serde_cbor::de::from_slice(data) { @@ -19,7 +19,7 @@ pub fn decode(data: &[u8]) -> Result { } } -pub fn encode(expr: &ParsedSubExpr) -> Result, EncodeError> { +pub fn encode(expr: &SubExpr) -> Result, EncodeError> { serde_cbor::ser::to_vec(&Serialize::Expr(expr)) .map_err(|e| EncodeError::CBORError(e)) } @@ -423,11 +423,11 @@ where .collect::>() } -enum Serialize<'a> { - Expr(&'a ParsedSubExpr), +enum Serialize<'a, E> { + Expr(&'a SubExpr), CBOR(cbor::Value), - RecordMap(&'a DupTreeMap), - UnionMap(&'a DupTreeMap>), + RecordMap(&'a DupTreeMap>), + UnionMap(&'a DupTreeMap>>), } macro_rules! count { @@ -447,7 +447,7 @@ macro_rules! ser_seq { }}; } -fn serialize_subexpr(ser: S, e: &ParsedSubExpr) -> Result +fn serialize_subexpr(ser: S, e: &SubExpr) -> Result where S: serde::ser::Serializer, { @@ -457,21 +457,14 @@ where use std::iter::once; use self::Serialize::{RecordMap, UnionMap}; - fn expr(x: &ParsedSubExpr) -> self::Serialize<'_> { + fn expr(x: &SubExpr) -> self::Serialize<'_, E> { self::Serialize::Expr(x) } - fn cbor<'a>(v: cbor::Value) -> self::Serialize<'a> { - self::Serialize::CBOR(v) - } - fn tag<'a>(x: u64) -> self::Serialize<'a> { - cbor(U64(x)) - } - fn null<'a>() -> self::Serialize<'a> { - cbor(cbor::Value::Null) - } - fn label<'a>(l: &Label) -> self::Serialize<'a> { - cbor(cbor::Value::String(l.into())) - } + let cbor = + |v: cbor::Value| -> self::Serialize<'_, E> { self::Serialize::CBOR(v) }; + let tag = |x: u64| cbor(U64(x)); + let null = || cbor(cbor::Value::Null); + let label = |l: &Label| cbor(cbor::Value::String(l.into())); match e.as_ref() { Const(c) => ser.serialize_str(&c.to_string()), @@ -634,12 +627,14 @@ where match &url.headers { None => ser_seq.serialize_element(&Null)?, Some(location_hashed) => { - ser_seq.serialize_element(&self::Serialize::Expr(&rc( + let e = rc( ExprF::Import(dhall_syntax::Import { mode: ImportMode::Code, location_hashed: location_hashed.as_ref().clone(), }), - )))? + ); + let s: Serialize<'_, ()> = self::Serialize::Expr(&e); + ser_seq.serialize_element(&s)? } }; ser_seq.serialize_element(&url.authority)?; @@ -665,7 +660,7 @@ where ser_seq.end() } -impl<'a> serde::ser::Serialize for Serialize<'a> { +impl<'a, E> serde::ser::Serialize for Serialize<'a, E> { fn serialize(&self, ser: S) -> Result where S: serde::ser::Serializer, diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index a1e3f29..b73597c 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -157,6 +157,10 @@ impl Typed { } impl Normalized { + pub fn encode(&self) -> Result, EncodeError> { + crate::phase::binary::encode(&self.to_expr()) + } + #[allow(dead_code)] pub fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() @@ -220,6 +224,18 @@ derive_traits_for_wrapper_struct!(Parsed); derive_traits_for_wrapper_struct!(Resolved); derive_traits_for_wrapper_struct!(Normalized); +impl std::hash::Hash for Normalized { + fn hash(&self, state: &mut H) + where + H: std::hash::Hasher, + { + match self.encode() { + Ok(vec) => vec.hash(state), + Err(_) => {} + } + } +} + impl Eq for Typed {} impl PartialEq for Typed { fn eq(&self, other: &Self) -> bool { -- cgit v1.2.3 From 66260f8e386f7a447352bd8ccbda064b00b698bc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 23:44:52 +0200 Subject: Implement inline headers parsing --- dhall/src/phase/binary.rs | 50 ++++++++++++++++++---------------------------- dhall/src/phase/resolve.rs | 8 ++++---- 2 files changed, 23 insertions(+), 35 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index 9ed823c..36dd471 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -4,9 +4,8 @@ use std::iter::FromIterator; use dhall_syntax::map::DupTreeMap; use dhall_syntax::{ - rc, ExprF, FilePrefix, Hash, Import, ImportHashed, ImportLocation, - ImportMode, Integer, InterpolatedText, Label, Natural, Scheme, SubExpr, - URL, V, + rc, ExprF, FilePrefix, Hash, Import, ImportLocation, ImportMode, Integer, + InterpolatedText, Label, Natural, Scheme, SubExpr, URL, V, }; use crate::error::{DecodeError, EncodeError}; @@ -260,20 +259,12 @@ fn cbor_value_to_dhall( }; let headers = match rest.next() { Some(Null) => None, - // TODO - // Some(x) => { - // match cbor_value_to_dhall(&x)?.as_ref() { - // Import(import) => Some(Box::new( - // import.location_hashed.clone(), - // )), - // _ => Err(DecodeError::WrongFormatError( - // "import/remote/headers".to_owned(), - // ))?, - // } - // } + Some(x) => { + let x = cbor_value_to_dhall(&x)?; + Some(x) + } _ => Err(DecodeError::WrongFormatError( - "import/remote/headers is unimplemented" - .to_owned(), + "import/remote/headers".to_owned(), ))?, }; let authority = match rest.next() { @@ -341,7 +332,8 @@ fn cbor_value_to_dhall( }; Import(dhall_syntax::Import { mode, - location_hashed: ImportHashed { hash, location }, + hash, + location, }) } [U64(25), bindings..] => { @@ -572,14 +564,17 @@ where } } -fn serialize_import(ser: S, import: &Import) -> Result +fn serialize_import( + ser: S, + import: &Import>, +) -> Result where S: serde::ser::Serializer, { use cbor::Value::{Bytes, Null, U64}; use serde::ser::SerializeSeq; - let count = 4 + match &import.location_hashed.location { + let count = 4 + match &import.location { ImportLocation::Remote(url) => 3 + url.path.len(), ImportLocation::Local(_, path) => path.len(), ImportLocation::Env(_) => 1, @@ -589,7 +584,7 @@ where ser_seq.serialize_element(&U64(24))?; - let hash = match &import.location_hashed.hash { + let hash = match &import.hash { None => Null, Some(Hash::SHA256(h)) => { let mut bytes = vec![18, 32]; @@ -606,7 +601,7 @@ where }; ser_seq.serialize_element(&U64(mode))?; - let scheme = match &import.location_hashed.location { + let scheme = match &import.location { ImportLocation::Remote(url) => match url.scheme { Scheme::HTTP => 0, Scheme::HTTPS => 1, @@ -622,19 +617,12 @@ where }; ser_seq.serialize_element(&U64(scheme))?; - match &import.location_hashed.location { + match &import.location { ImportLocation::Remote(url) => { match &url.headers { None => ser_seq.serialize_element(&Null)?, - Some(location_hashed) => { - let e = rc( - ExprF::Import(dhall_syntax::Import { - mode: ImportMode::Code, - location_hashed: location_hashed.as_ref().clone(), - }), - ); - let s: Serialize<'_, ()> = self::Serialize::Expr(&e); - ser_seq.serialize_element(&s)? + Some(e) => { + ser_seq.serialize_element(&self::Serialize::Expr(e))? } }; ser_seq.serialize_element(&url.authority)?; diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs index abcee7e..52353e4 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/phase/resolve.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use dhall_syntax::Import; - use crate::error::{Error, ImportError}; -use crate::phase::{Normalized, Parsed, Resolved}; +use crate::phase::{Normalized, NormalizedSubExpr, Parsed, Resolved}; + +type Import = dhall_syntax::Import; /// A root from which to resolve relative imports. #[derive(Debug, Clone, PartialEq, Eq)] @@ -28,7 +28,7 @@ fn resolve_import( let cwd = match root { LocalDir(cwd) => cwd, }; - match &import.location_hashed.location { + match &import.location { Local(prefix, path) => { let path: PathBuf = path.iter().cloned().collect(); let path = match prefix { -- cgit v1.2.3 From aabca76a62256aa7cad66c2016ed504e49651d5a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 15 Aug 2019 13:06:56 +0200 Subject: Remove special closures from Value Instead construct their values directly --- dhall/src/phase/normalize.rs | 97 +++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 42 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index adbcb02..f11269e 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -1,19 +1,61 @@ use std::collections::HashMap; use dhall_syntax::{ - BinOp, Builtin, ExprF, InterpolatedText, InterpolatedTextContents, + BinOp, Builtin, ExprF, InterpolatedText, InterpolatedTextContents, Label, NaiveDouble, }; use crate::core::context::NormalizationContext; use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; -use crate::core::var::Subst; +use crate::core::var::{Shift, Subst}; use crate::phase::{Normalized, NormalizedSubExpr, ResolvedSubExpr, Typed}; pub type InputSubExpr = ResolvedSubExpr; pub type OutputSubExpr = NormalizedSubExpr; +// Ad-hoc macro to help construct closures +macro_rules! make_closure { + (#$var:ident) => { $var.clone() }; + (var($var:ident, $n:expr)) => {{ + let var = crate::core::var::AlphaVar::from_var_and_alpha( + Label::from(stringify!($var)).into(), + $n + ); + Value::Var(var).into_thunk() + }}; + (λ($var:ident : $($ty:tt)*) -> $($rest:tt)*) => { + Value::Lam( + Label::from(stringify!($var)).into(), + TypedThunk::from_thunk_untyped(make_closure!($($ty)*)), + make_closure!($($rest)*), + ).into_thunk() + }; + (Natural) => { Value::from_builtin(Builtin::Natural).into_thunk() }; + (List $($rest:tt)*) => { + Value::from_builtin(Builtin::List) + .app_thunk(make_closure!($($rest)*)) + .into_thunk() + }; + (Some $($rest:tt)*) => { + Value::NEOptionalLit(make_closure!($($rest)*)).into_thunk() + }; + (1 + $($rest:tt)*) => { + Value::PartialExpr(ExprF::BinOp( + dhall_syntax::BinOp::NaturalPlus, + make_closure!($($rest)*), + Thunk::from_value(Value::NaturalLit(1)), + )).into_thunk() + }; + ([ $($head:tt)* ] # $($tail:tt)*) => { + Value::PartialExpr(ExprF::BinOp( + dhall_syntax::BinOp::ListAppend, + Value::NEListLit(vec![make_closure!($($head)*)]).into_thunk(), + make_closure!($($tail)*), + )).into_thunk() + }; +} + #[allow(clippy::cognitive_complexity)] pub fn apply_builtin(b: Builtin, args: Vec) -> Value { use dhall_syntax::Builtin::*; @@ -179,10 +221,15 @@ pub fn apply_builtin(b: Builtin, args: Vec) -> Value { _ => Ok(( r, f.app_val(Value::from_builtin(List).app_thunk(t.clone())) - .app_val(ListConsClosure( - TypedThunk::from_thunk(t.clone()), - None, - )) + .app_thunk({ + // Move `t` under new `x` variable + let t1 = t.under_binder(Label::from("x")); + make_closure!( + λ(x : #t) -> + λ(xs : List #t1) -> + [ var(x, 1) ] # var(xs, 0) + ) + }) .app_val(EmptyListLit(TypedThunk::from_thunk(t.clone()))), )), }, @@ -214,9 +261,7 @@ pub fn apply_builtin(b: Builtin, args: Vec) -> Value { _ => Ok(( r, f.app_val(Value::from_builtin(Optional).app_thunk(t.clone())) - .app_val(OptionalSomeClosure(TypedThunk::from_thunk( - t.clone(), - ))) + .app_thunk(make_closure!(λ(x: #t) -> Some var(x, 0))) .app_val(EmptyOptionalLit(TypedThunk::from_thunk( t.clone(), ))), @@ -240,7 +285,7 @@ pub fn apply_builtin(b: Builtin, args: Vec) -> Value { _ => Ok(( r, f.app_val(Value::from_builtin(Natural)) - .app_val(NaturalSuccClosure) + .app_thunk(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) .app_val(NaturalLit(0)), )), }, @@ -284,38 +329,6 @@ pub fn apply_any(f: Thunk, a: Thunk) -> Value { let args = args.iter().cloned().chain(once(a.clone())).collect(); apply_builtin(*b, args) } - Value::OptionalSomeClosure(_) => Value::NEOptionalLit(a), - Value::ListConsClosure(t, None) => { - Value::ListConsClosure(t.clone(), Some(a)) - } - Value::ListConsClosure(_, Some(x)) => { - let a_borrow = a.as_value(); - match &*a_borrow { - Value::EmptyListLit(_) => Value::NEListLit(vec![x.clone()]), - Value::NEListLit(xs) => { - use std::iter::once; - let xs = - once(x.clone()).chain(xs.iter().cloned()).collect(); - Value::NEListLit(xs) - } - _ => { - drop(f_borrow); - drop(a_borrow); - fallback(f, a) - } - } - } - Value::NaturalSuccClosure => { - let a_borrow = a.as_value(); - match &*a_borrow { - Value::NaturalLit(n) => Value::NaturalLit(n + 1), - _ => { - drop(f_borrow); - drop(a_borrow); - fallback(f, a) - } - } - } Value::UnionConstructor(l, kts) => { Value::UnionLit(l.clone(), a, kts.clone()) } -- cgit v1.2.3 From 816f616479cfa277e19b2e69be6c41bc8210e032 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 15 Aug 2019 22:12:06 +0200 Subject: Disable some unused unstable features --- dhall/src/phase/normalize.rs | 2 +- dhall/src/phase/resolve.rs | 3 +-- dhall/src/phase/typecheck.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index f11269e..02406f2 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -752,7 +752,7 @@ pub fn normalize_one_layer(expr: ExprF) -> Value { None => Ret::Expr(expr), }, - ExprF::Projection(_, ls) if ls.is_empty() => { + ExprF::Projection(_, ref ls) if ls.is_empty() => { Ret::Value(RecordLit(HashMap::new())) } ExprF::Projection(ref v, ref ls) => { diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs index 52353e4..dabecf2 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/phase/resolve.rs @@ -105,9 +105,8 @@ pub fn skip_resolve_expr( } #[cfg(test)] +#[rustfmt::skip] mod spec_tests { - #![rustfmt::skip] - macro_rules! import_success { ($name:ident, $path:expr) => { make_spec_test!(Import, Success, $name, &("../dhall-lang/tests/import/success/".to_owned() + $path)); diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 89e2da8..5eab8da 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -438,7 +438,7 @@ fn type_last_layer( } Assert(t) => { match t.to_value() { - Value::Equivalence(x, y) if x == y => {} + Value::Equivalence(ref x, ref y) if x == y => {} Value::Equivalence(x, y) => { return Err(mkerr(AssertMismatch( x.to_typed(), -- cgit v1.2.3 From 509743469035582d916e6a2f331fd5018c81447e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 11:11:28 +0200 Subject: Use `!` type instead of custom empty type --- dhall/src/phase/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index b73597c..2700e99 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::fmt::Display; use std::path::Path; -use dhall_syntax::{Const, SubExpr, Void}; +use dhall_syntax::{Const, SubExpr}; use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; @@ -17,8 +17,8 @@ pub(crate) mod parse; pub(crate) mod resolve; pub(crate) mod typecheck; -pub type ParsedSubExpr = SubExpr; -pub type DecodedSubExpr = SubExpr; +pub type ParsedSubExpr = SubExpr; +pub type DecodedSubExpr = SubExpr; pub type ResolvedSubExpr = SubExpr; pub type NormalizedSubExpr = SubExpr; -- cgit v1.2.3 From 88ebc0f9d561a2541aad84a3152511a0439db8b4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 17:56:19 +0200 Subject: Reduce api surface of dhall crate Helps detect unused code --- dhall/src/phase/binary.rs | 4 ++-- dhall/src/phase/mod.rs | 41 ++++++++++++++++++----------------------- dhall/src/phase/normalize.rs | 14 +++++++------- dhall/src/phase/parse.rs | 8 ++++---- dhall/src/phase/resolve.rs | 8 ++++---- dhall/src/phase/typecheck.rs | 12 ++++++------ 6 files changed, 41 insertions(+), 46 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index 36dd471..3746635 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -11,14 +11,14 @@ use dhall_syntax::{ use crate::error::{DecodeError, EncodeError}; use crate::phase::DecodedSubExpr; -pub fn decode(data: &[u8]) -> Result { +pub(crate) fn decode(data: &[u8]) -> Result { match serde_cbor::de::from_slice(data) { Ok(v) => cbor_value_to_dhall(&v), Err(e) => Err(DecodeError::CBORError(e)), } } -pub fn encode(expr: &SubExpr) -> Result, EncodeError> { +pub(crate) fn encode(expr: &SubExpr) -> Result, EncodeError> { serde_cbor::ser::to_vec(&Serialize::Expr(expr)) .map_err(|e| EncodeError::CBORError(e)) } diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 2700e99..778f990 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -50,11 +50,9 @@ impl Parsed { pub fn parse_str(s: &str) -> Result { parse::parse_str(s) } - #[allow(dead_code)] pub fn parse_binary_file(f: &Path) -> Result { parse::parse_binary_file(f) } - #[allow(dead_code)] pub fn parse_binary(data: &[u8]) -> Result { parse::parse_binary(data) } @@ -62,12 +60,10 @@ impl Parsed { pub fn resolve(self) -> Result { resolve::resolve(self) } - #[allow(dead_code)] pub fn skip_resolve(self) -> Result { resolve::skip_resolve_expr(self) } - #[allow(dead_code)] pub fn encode(&self) -> Result, EncodeError> { crate::phase::binary::encode(&self.0) } @@ -82,7 +78,7 @@ impl Resolved { } /// Pretends this expression has been typechecked. Use with care. #[allow(dead_code)] - pub fn skip_typecheck(self) -> Typed { + pub(crate) fn skip_typecheck(self) -> Typed { typecheck::skip_typecheck(self) } } @@ -101,29 +97,29 @@ impl Typed { Normalized(self) } - pub fn from_thunk_and_type(th: Thunk, t: Type) -> Self { + pub(crate) fn from_thunk_and_type(th: Thunk, t: Type) -> Self { Typed(TypedThunk::from_thunk_and_type(th, t)) } - pub fn from_thunk_untyped(th: Thunk) -> Self { + pub(crate) fn from_thunk_untyped(th: Thunk) -> Self { Typed(TypedThunk::from_thunk_untyped(th)) } - pub fn from_const(c: Const) -> Self { + pub(crate) fn from_const(c: Const) -> Self { Typed(TypedThunk::from_const(c)) } pub fn from_value_untyped(v: Value) -> Self { Typed(TypedThunk::from_value_untyped(v)) } - pub fn from_typethunk(th: TypedThunk) -> Self { + pub(crate) fn from_typethunk(th: TypedThunk) -> Self { Typed(th) } - pub fn to_value(&self) -> Value { + pub(crate) fn to_value(&self) -> Value { self.0.to_value() } pub fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() } - pub fn to_expr_alpha(&self) -> NormalizedSubExpr { + pub(crate) fn to_expr_alpha(&self) -> NormalizedSubExpr { self.0.to_expr_alpha() } pub fn to_thunk(&self) -> Thunk { @@ -134,24 +130,24 @@ impl Typed { self.clone() } // Deprecated - pub fn into_type(self) -> Type { + pub(crate) fn into_type(self) -> Type { self } - pub fn into_typethunk(self) -> TypedThunk { + pub(crate) fn into_typethunk(self) -> TypedThunk { self.0 } - pub fn to_normalized(&self) -> Normalized { + pub(crate) fn to_normalized(&self) -> Normalized { self.clone().normalize() } - pub fn as_const(&self) -> Option { + pub(crate) fn as_const(&self) -> Option { self.0.as_const() } - pub fn normalize_mut(&mut self) { + pub(crate) fn normalize_mut(&mut self) { self.0.normalize_mut() } - pub fn get_type(&self) -> Result, TypeError> { + pub(crate) fn get_type(&self) -> Result, TypeError> { self.0.get_type() } } @@ -161,22 +157,21 @@ impl Normalized { crate::phase::binary::encode(&self.to_expr()) } - #[allow(dead_code)] - pub fn to_expr(&self) -> NormalizedSubExpr { + pub(crate) fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() } #[allow(dead_code)] - pub fn to_expr_alpha(&self) -> NormalizedSubExpr { + pub(crate) fn to_expr_alpha(&self) -> NormalizedSubExpr { self.0.to_expr_alpha() } #[allow(dead_code)] - pub fn to_type(&self) -> Type { + pub(crate) fn to_type(&self) -> Type { self.0.to_type() } - pub fn to_value(&self) -> Value { + pub(crate) fn to_value(&self) -> Value { self.0.to_value() } - pub fn into_typed(self) -> Typed { + pub(crate) fn into_typed(self) -> Typed { self.0 } } diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 02406f2..fd0197d 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -11,8 +11,8 @@ use crate::core::value::Value; use crate::core::var::{Shift, Subst}; use crate::phase::{Normalized, NormalizedSubExpr, ResolvedSubExpr, Typed}; -pub type InputSubExpr = ResolvedSubExpr; -pub type OutputSubExpr = NormalizedSubExpr; +pub(crate) type InputSubExpr = ResolvedSubExpr; +pub(crate) type OutputSubExpr = NormalizedSubExpr; // Ad-hoc macro to help construct closures macro_rules! make_closure { @@ -57,7 +57,7 @@ macro_rules! make_closure { } #[allow(clippy::cognitive_complexity)] -pub fn apply_builtin(b: Builtin, args: Vec) -> Value { +pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { use dhall_syntax::Builtin::*; use Value::*; @@ -315,7 +315,7 @@ pub fn apply_builtin(b: Builtin, args: Vec) -> Value { } } -pub fn apply_any(f: Thunk, a: Thunk) -> Value { +pub(crate) fn apply_any(f: Thunk, a: Thunk) -> Value { let fallback = |f: Thunk, a: Thunk| Value::PartialExpr(ExprF::App(f, a)); let f_borrow = f.as_value(); @@ -339,7 +339,7 @@ pub fn apply_any(f: Thunk, a: Thunk) -> Value { } } -pub fn squash_textlit( +pub(crate) fn squash_textlit( elts: impl Iterator>, ) -> Vec> { use std::mem::replace; @@ -382,7 +382,7 @@ pub fn squash_textlit( } /// Reduces the imput expression to a Value. Evaluates as little as possible. -pub fn normalize_whnf(ctx: NormalizationContext, expr: InputSubExpr) -> Value { +pub(crate) fn normalize_whnf(ctx: NormalizationContext, expr: InputSubExpr) -> Value { match expr.as_ref() { ExprF::Embed(e) => return e.to_value(), ExprF::Var(v) => return ctx.lookup(v), @@ -649,7 +649,7 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { }) } -pub fn normalize_one_layer(expr: ExprF) -> Value { +pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { use Value::{ AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, Lam, NEListLit, NEOptionalLit, NaturalLit, Pi, RecordLit, RecordType, diff --git a/dhall/src/phase/parse.rs b/dhall/src/phase/parse.rs index 9f3f2f4..540ceea 100644 --- a/dhall/src/phase/parse.rs +++ b/dhall/src/phase/parse.rs @@ -8,7 +8,7 @@ use crate::error::Error; use crate::phase::resolve::ImportRoot; use crate::phase::Parsed; -pub fn parse_file(f: &Path) -> Result { +pub(crate) fn parse_file(f: &Path) -> Result { let mut buffer = String::new(); File::open(f)?.read_to_string(&mut buffer)?; let expr = parse_expr(&*buffer)?; @@ -16,19 +16,19 @@ pub fn parse_file(f: &Path) -> Result { Ok(Parsed(expr, root)) } -pub fn parse_str(s: &str) -> Result { +pub(crate) fn parse_str(s: &str) -> Result { let expr = parse_expr(s)?; let root = ImportRoot::LocalDir(std::env::current_dir()?); Ok(Parsed(expr, root)) } -pub fn parse_binary(data: &[u8]) -> Result { +pub(crate) fn parse_binary(data: &[u8]) -> Result { let expr = crate::phase::binary::decode(data)?; let root = ImportRoot::LocalDir(std::env::current_dir()?); Ok(Parsed(expr, root)) } -pub fn parse_binary_file(f: &Path) -> Result { +pub(crate) fn parse_binary_file(f: &Path) -> Result { let mut buffer = Vec::new(); File::open(f)?.read_to_end(&mut buffer)?; let expr = crate::phase::binary::decode(&buffer)?; diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs index dabecf2..27ae7a3 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/phase/resolve.rs @@ -8,13 +8,13 @@ type Import = dhall_syntax::Import; /// A root from which to resolve relative imports. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum ImportRoot { +pub(crate) enum ImportRoot { LocalDir(PathBuf), } type ImportCache = HashMap; -pub type ImportStack = Vec; +pub(crate) type ImportStack = Vec; fn resolve_import( import: &Import, @@ -90,11 +90,11 @@ fn do_resolve_expr( Ok(Resolved(expr)) } -pub fn resolve(e: Parsed) -> Result { +pub(crate) fn resolve(e: Parsed) -> Result { do_resolve_expr(e, &mut HashMap::new(), &Vec::new()) } -pub fn skip_resolve_expr( +pub(crate) fn skip_resolve_expr( Parsed(expr, _root): Parsed, ) -> Result { let resolve = |import: &Import| -> Result { diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 5eab8da..56fb5ed 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -147,7 +147,7 @@ fn function_check(a: Const, b: Const) -> Const { } } -pub fn type_of_const(c: Const) -> Result { +pub(crate) fn type_of_const(c: Const) -> Result { match c { Const::Type => Ok(Type::from_const(Const::Kind)), Const::Kind => Ok(Type::from_const(Const::Sort)), @@ -300,14 +300,14 @@ fn type_of_builtin(b: Builtin) -> Expr { /// Takes an expression that is meant to contain a Type /// and turn it into a type, typechecking it along the way. -pub fn mktype( +pub(crate) fn mktype( ctx: &TypecheckContext, e: SubExpr, ) -> Result { Ok(type_with(ctx, e)?.to_type()) } -pub fn builtin_to_type(b: Builtin) -> Result { +pub(crate) fn builtin_to_type(b: Builtin) -> Result { mktype(&TypecheckContext::new(), SubExpr::from_builtin(b)) } @@ -1009,15 +1009,15 @@ fn type_of(e: SubExpr) -> Result { Ok(e) } -pub fn typecheck(e: Resolved) -> Result { +pub(crate) fn typecheck(e: Resolved) -> Result { type_of(e.0) } -pub fn typecheck_with(e: Resolved, ty: &Type) -> Result { +pub(crate) fn typecheck_with(e: Resolved, ty: &Type) -> Result { let expr: SubExpr<_> = e.0; let ty: SubExpr<_> = ty.to_expr(); type_of(expr.rewrap(ExprF::Annot(expr.clone(), ty))) } -pub fn skip_typecheck(e: Resolved) -> Typed { +pub(crate) fn skip_typecheck(e: Resolved) -> Typed { Typed::from_thunk_untyped(Thunk::new(NormalizationContext::new(), e.0)) } -- cgit v1.2.3 From 664c925186ecd587f46577715254b74b6264e4fe Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 12:33:52 +0200 Subject: Avoid capture when typechecking union constructor --- dhall/src/phase/typecheck.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 56fb5ed..2030f21 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -564,13 +564,12 @@ fn type_last_layer( Value::UnionType(kts) => match kts.get(&x) { // Constructor has type T -> < x: T, ... > Some(Some(t)) => { - // TODO: avoid capture Ok(RetTypeOnly( tck_pi_type( ctx, "_".into(), t.to_type(), - r.clone(), + r.under_binder(Label::from("_")), )?.to_type() )) }, -- cgit v1.2.3 From 51bb1d2da8e5874129d4b5cc5d0c60e23eee9f11 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 12:35:34 +0200 Subject: Typecheck before normalizing in tests --- dhall/src/phase/typecheck.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 2030f21..7bbad38 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -1002,10 +1002,7 @@ fn type_last_layer( /// will fail. fn type_of(e: SubExpr) -> Result { let ctx = TypecheckContext::new(); - let e = type_with(&ctx, e)?; - // Ensure `e` has a type (i.e. `e` is not `Sort`) - e.get_type()?; - Ok(e) + type_with(&ctx, e) } pub(crate) fn typecheck(e: Resolved) -> Result { -- cgit v1.2.3 From 5f0d69671b44ba1dff6becb9ebc7f6e74241e3e2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 18:14:55 +0200 Subject: Remove dead code --- dhall/src/phase/mod.rs | 8 -------- dhall/src/phase/normalize.rs | 22 +--------------------- dhall/src/phase/typecheck.rs | 10 +++++----- 3 files changed, 6 insertions(+), 34 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 778f990..5a6d4db 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -76,11 +76,6 @@ impl Resolved { pub fn typecheck_with(self, ty: &Type) -> Result { typecheck::typecheck_with(self, ty) } - /// Pretends this expression has been typechecked. Use with care. - #[allow(dead_code)] - pub(crate) fn skip_typecheck(self) -> Typed { - typecheck::skip_typecheck(self) - } } impl Typed { @@ -168,9 +163,6 @@ impl Normalized { pub(crate) fn to_type(&self) -> Type { self.0.to_type() } - pub(crate) fn to_value(&self) -> Value { - self.0.to_value() - } pub(crate) fn into_typed(self) -> Typed { self.0 } diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index fd0197d..2a2bf3e 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -5,13 +5,11 @@ use dhall_syntax::{ NaiveDouble, }; -use crate::core::context::NormalizationContext; use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; use crate::core::var::{Shift, Subst}; -use crate::phase::{Normalized, NormalizedSubExpr, ResolvedSubExpr, Typed}; +use crate::phase::{Normalized, NormalizedSubExpr, Typed}; -pub(crate) type InputSubExpr = ResolvedSubExpr; pub(crate) type OutputSubExpr = NormalizedSubExpr; // Ad-hoc macro to help construct closures @@ -381,24 +379,6 @@ pub(crate) fn squash_textlit( ret } -/// Reduces the imput expression to a Value. Evaluates as little as possible. -pub(crate) fn normalize_whnf(ctx: NormalizationContext, expr: InputSubExpr) -> Value { - match expr.as_ref() { - ExprF::Embed(e) => return e.to_value(), - ExprF::Var(v) => return ctx.lookup(v), - _ => {} - } - - // Thunk subexpressions - let expr: ExprF = - expr.as_ref().map_ref_with_special_handling_of_binders( - |e| Thunk::new(ctx.clone(), e.clone()), - |x, e| Thunk::new(ctx.skip(x), e.clone()), - ); - - normalize_one_layer(expr) -} - // Small helper enum to avoid repetition enum Ret<'a> { Value(Value), diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 7bbad38..dd6da70 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -4,7 +4,7 @@ use dhall_syntax::{ rc, Builtin, Const, Expr, ExprF, InterpolatedTextContents, Label, SubExpr, }; -use crate::core::context::{NormalizationContext, TypecheckContext}; +use crate::core::context::TypecheckContext; use crate::core::thunk::{Thunk, TypedThunk}; use crate::core::value::Value; use crate::core::var::{Shift, Subst}; @@ -1009,11 +1009,11 @@ pub(crate) fn typecheck(e: Resolved) -> Result { type_of(e.0) } -pub(crate) fn typecheck_with(e: Resolved, ty: &Type) -> Result { +pub(crate) fn typecheck_with( + e: Resolved, + ty: &Type, +) -> Result { let expr: SubExpr<_> = e.0; let ty: SubExpr<_> = ty.to_expr(); type_of(expr.rewrap(ExprF::Annot(expr.clone(), ty))) } -pub(crate) fn skip_typecheck(e: Resolved) -> Typed { - Typed::from_thunk_untyped(Thunk::new(NormalizationContext::new(), e.0)) -} -- cgit v1.2.3 From 45fb07f74f19919f742be6fe7793dc72d4022f26 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 19:16:40 +0200 Subject: Try to minimize untyped TypedThunks --- dhall/src/phase/mod.rs | 7 ++++-- dhall/src/phase/normalize.rs | 54 +++++++++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 25 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 5a6d4db..adf749c 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -101,12 +101,15 @@ impl Typed { pub(crate) fn from_const(c: Const) -> Self { Typed(TypedThunk::from_const(c)) } - pub fn from_value_untyped(v: Value) -> Self { - Typed(TypedThunk::from_value_untyped(v)) + pub fn from_value_and_type(v: Value, t: Type) -> Self { + Typed(TypedThunk::from_value_and_type(v, t)) } pub(crate) fn from_typethunk(th: TypedThunk) -> Self { Typed(th) } + pub fn const_type() -> Self { + Typed::from_const(Const::Type) + } pub(crate) fn to_value(&self) -> Value { self.0.to_value() diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 2a2bf3e..02b705d 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -22,10 +22,13 @@ macro_rules! make_closure { ); Value::Var(var).into_thunk() }}; + // Warning: assumes that $ty, as a dhall value, has type `Type` (λ($var:ident : $($ty:tt)*) -> $($rest:tt)*) => { Value::Lam( Label::from(stringify!($var)).into(), - TypedThunk::from_thunk_untyped(make_closure!($($ty)*)), + TypedThunk::from_thunk_simple_type( + make_closure!($($ty)*), + ), make_closure!($($rest)*), ).into_thunk() }; @@ -61,9 +64,10 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { // Return Ok((unconsumed args, returned value)), or Err(()) if value could not be produced. let ret = match (b, args.as_slice()) { - (OptionalNone, [t, r..]) => { - Ok((r, EmptyOptionalLit(TypedThunk::from_thunk(t.clone())))) - } + (OptionalNone, [t, r..]) => Ok(( + r, + EmptyOptionalLit(TypedThunk::from_thunk_simple_type(t.clone())), + )), (NaturalIsZero, [n, r..]) => match &*n.as_value() { NaturalLit(n) => Ok((r, BoolLit(*n == 0))), _ => Err(()), @@ -228,7 +232,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { [ var(x, 1) ] # var(xs, 0) ) }) - .app_val(EmptyListLit(TypedThunk::from_thunk(t.clone()))), + .app_val(EmptyListLit(TypedThunk::from_thunk_simple_type( + t.clone(), + ))), )), }, (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_value() { @@ -260,9 +266,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { r, f.app_val(Value::from_builtin(Optional).app_thunk(t.clone())) .app_thunk(make_closure!(λ(x: #t) -> Some var(x, 0))) - .app_val(EmptyOptionalLit(TypedThunk::from_thunk( - t.clone(), - ))), + .app_val(EmptyOptionalLit( + TypedThunk::from_thunk_simple_type(t.clone()), + )), )), }, (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_value() { @@ -611,18 +617,20 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { } (RecursiveRecordTypeMerge, RecordType(kvs1), RecordType(kvs2)) => { let kvs = merge_maps(kvs1, kvs2, |v1, v2| { - TypedThunk::from_thunk(Thunk::from_partial_expr(ExprF::BinOp( - RecursiveRecordTypeMerge, - v1.to_thunk(), - v2.to_thunk(), - ))) + TypedThunk::from_thunk_untyped(Thunk::from_partial_expr( + ExprF::BinOp( + RecursiveRecordTypeMerge, + v1.to_thunk(), + v2.to_thunk(), + ), + )) }); Ret::Value(RecordType(kvs)) } (Equivalence, _, _) => Ret::Value(Value::Equivalence( - TypedThunk::from_thunk(x.clone()), - TypedThunk::from_thunk(y.clone()), + TypedThunk::from_thunk_simple_type(x.clone()), + TypedThunk::from_thunk_simple_type(y.clone()), )), _ => return None, @@ -645,12 +653,12 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { ExprF::Annot(x, _) => Ret::Thunk(x), ExprF::Assert(_) => Ret::Expr(expr), ExprF::Lam(x, t, e) => { - Ret::Value(Lam(x.into(), TypedThunk::from_thunk(t), e)) + Ret::Value(Lam(x.into(), TypedThunk::from_thunk_untyped(t), e)) } ExprF::Pi(x, t, e) => Ret::Value(Pi( x.into(), - TypedThunk::from_thunk(t), - TypedThunk::from_thunk(e), + TypedThunk::from_thunk_untyped(t), + TypedThunk::from_thunk_untyped(e), )), ExprF::Let(x, _, v, b) => { let v = Typed::from_thunk_untyped(v); @@ -669,9 +677,9 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { let t_borrow = t.as_value(); match &*t_borrow { AppliedBuiltin(Builtin::List, args) if args.len() == 1 => { - Ret::Value(EmptyListLit(TypedThunk::from_thunk( - args[0].clone(), - ))) + Ret::Value(EmptyListLit( + TypedThunk::from_thunk_simple_type(args[0].clone()), + )) } _ => { drop(t_borrow); @@ -687,12 +695,12 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { } ExprF::RecordType(kts) => Ret::Value(RecordType( kts.into_iter() - .map(|(k, t)| (k, TypedThunk::from_thunk(t))) + .map(|(k, t)| (k, TypedThunk::from_thunk_untyped(t))) .collect(), )), ExprF::UnionType(kts) => Ret::Value(UnionType( kts.into_iter() - .map(|(k, t)| (k, t.map(|t| TypedThunk::from_thunk(t)))) + .map(|(k, t)| (k, t.map(|t| TypedThunk::from_thunk_untyped(t)))) .collect(), )), ExprF::TextLit(elts) => { -- cgit v1.2.3 From e0f5216215ccb7a4df85d80e11dd265cdb52a44f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 19:47:36 +0200 Subject: s/Value/ValueF/ --- dhall/src/phase/mod.rs | 12 +-- dhall/src/phase/normalize.rs | 250 ++++++++++++++++++++++--------------------- dhall/src/phase/typecheck.rs | 110 +++++++++---------- 3 files changed, 188 insertions(+), 184 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index adf749c..7e74f95 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -5,7 +5,7 @@ use std::path::Path; use dhall_syntax::{Const, SubExpr}; use crate::core::thunk::{Thunk, TypedThunk}; -use crate::core::value::Value; +use crate::core::value::ValueF; use crate::core::var::{AlphaVar, Shift, Subst}; use crate::error::{EncodeError, Error, ImportError, TypeError}; @@ -101,8 +101,8 @@ impl Typed { pub(crate) fn from_const(c: Const) -> Self { Typed(TypedThunk::from_const(c)) } - pub fn from_value_and_type(v: Value, t: Type) -> Self { - Typed(TypedThunk::from_value_and_type(v, t)) + pub fn from_valuef_and_type(v: ValueF, t: Type) -> Self { + Typed(TypedThunk::from_valuef_and_type(v, t)) } pub(crate) fn from_typethunk(th: TypedThunk) -> Self { Typed(th) @@ -111,8 +111,8 @@ impl Typed { Typed::from_const(Const::Type) } - pub(crate) fn to_value(&self) -> Value { - self.0.to_value() + pub(crate) fn to_valuef(&self) -> ValueF { + self.0.to_valuef() } pub fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() @@ -229,7 +229,7 @@ impl std::hash::Hash for Normalized { impl Eq for Typed {} impl PartialEq for Typed { fn eq(&self, other: &Self) -> bool { - self.to_value() == other.to_value() + self.to_valuef() == other.to_valuef() } } diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 02b705d..da54726 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -6,7 +6,7 @@ use dhall_syntax::{ }; use crate::core::thunk::{Thunk, TypedThunk}; -use crate::core::value::Value; +use crate::core::value::ValueF; use crate::core::var::{Shift, Subst}; use crate::phase::{Normalized, NormalizedSubExpr, Typed}; @@ -20,11 +20,11 @@ macro_rules! make_closure { Label::from(stringify!($var)).into(), $n ); - Value::Var(var).into_thunk() + ValueF::Var(var).into_thunk() }}; // Warning: assumes that $ty, as a dhall value, has type `Type` (λ($var:ident : $($ty:tt)*) -> $($rest:tt)*) => { - Value::Lam( + ValueF::Lam( Label::from(stringify!($var)).into(), TypedThunk::from_thunk_simple_type( make_closure!($($ty)*), @@ -32,35 +32,35 @@ macro_rules! make_closure { make_closure!($($rest)*), ).into_thunk() }; - (Natural) => { Value::from_builtin(Builtin::Natural).into_thunk() }; + (Natural) => { ValueF::from_builtin(Builtin::Natural).into_thunk() }; (List $($rest:tt)*) => { - Value::from_builtin(Builtin::List) + ValueF::from_builtin(Builtin::List) .app_thunk(make_closure!($($rest)*)) .into_thunk() }; (Some $($rest:tt)*) => { - Value::NEOptionalLit(make_closure!($($rest)*)).into_thunk() + ValueF::NEOptionalLit(make_closure!($($rest)*)).into_thunk() }; (1 + $($rest:tt)*) => { - Value::PartialExpr(ExprF::BinOp( + ValueF::PartialExpr(ExprF::BinOp( dhall_syntax::BinOp::NaturalPlus, make_closure!($($rest)*), - Thunk::from_value(Value::NaturalLit(1)), + Thunk::from_valuef(ValueF::NaturalLit(1)), )).into_thunk() }; ([ $($head:tt)* ] # $($tail:tt)*) => { - Value::PartialExpr(ExprF::BinOp( + ValueF::PartialExpr(ExprF::BinOp( dhall_syntax::BinOp::ListAppend, - Value::NEListLit(vec![make_closure!($($head)*)]).into_thunk(), + ValueF::NEListLit(vec![make_closure!($($head)*)]).into_thunk(), make_closure!($($tail)*), )).into_thunk() }; } #[allow(clippy::cognitive_complexity)] -pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { +pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { use dhall_syntax::Builtin::*; - use Value::*; + use ValueF::*; // Return Ok((unconsumed args, returned value)), or Err(()) if value could not be produced. let ret = match (b, args.as_slice()) { @@ -68,23 +68,23 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { r, EmptyOptionalLit(TypedThunk::from_thunk_simple_type(t.clone())), )), - (NaturalIsZero, [n, r..]) => match &*n.as_value() { + (NaturalIsZero, [n, r..]) => match &*n.as_valuef() { NaturalLit(n) => Ok((r, BoolLit(*n == 0))), _ => Err(()), }, - (NaturalEven, [n, r..]) => match &*n.as_value() { + (NaturalEven, [n, r..]) => match &*n.as_valuef() { NaturalLit(n) => Ok((r, BoolLit(*n % 2 == 0))), _ => Err(()), }, - (NaturalOdd, [n, r..]) => match &*n.as_value() { + (NaturalOdd, [n, r..]) => match &*n.as_valuef() { NaturalLit(n) => Ok((r, BoolLit(*n % 2 != 0))), _ => Err(()), }, - (NaturalToInteger, [n, r..]) => match &*n.as_value() { + (NaturalToInteger, [n, r..]) => match &*n.as_valuef() { NaturalLit(n) => Ok((r, IntegerLit(*n as isize))), _ => Err(()), }, - (NaturalShow, [n, r..]) => match &*n.as_value() { + (NaturalShow, [n, r..]) => match &*n.as_valuef() { NaturalLit(n) => Ok(( r, TextLit(vec![InterpolatedTextContents::Text(n.to_string())]), @@ -92,7 +92,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { _ => Err(()), }, (NaturalSubtract, [a, b, r..]) => { - match (&*a.as_value(), &*b.as_value()) { + match (&*a.as_valuef(), &*b.as_valuef()) { (NaturalLit(a), NaturalLit(b)) => { Ok((r, NaturalLit(if b > a { b - a } else { 0 }))) } @@ -102,7 +102,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { _ => Err(()), } } - (IntegerShow, [n, r..]) => match &*n.as_value() { + (IntegerShow, [n, r..]) => match &*n.as_valuef() { IntegerLit(n) => { let s = if *n < 0 { n.to_string() @@ -113,18 +113,18 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { } _ => Err(()), }, - (IntegerToDouble, [n, r..]) => match &*n.as_value() { + (IntegerToDouble, [n, r..]) => match &*n.as_valuef() { IntegerLit(n) => Ok((r, DoubleLit(NaiveDouble::from(*n as f64)))), _ => Err(()), }, - (DoubleShow, [n, r..]) => match &*n.as_value() { + (DoubleShow, [n, r..]) => match &*n.as_valuef() { DoubleLit(n) => Ok(( r, TextLit(vec![InterpolatedTextContents::Text(n.to_string())]), )), _ => Err(()), }, - (TextShow, [v, r..]) => match &*v.as_value() { + (TextShow, [v, r..]) => match &*v.as_valuef() { TextLit(elts) => { match elts.as_slice() { // Empty string literal. @@ -158,41 +158,41 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { } _ => Err(()), }, - (ListLength, [_, l, r..]) => match &*l.as_value() { + (ListLength, [_, l, r..]) => match &*l.as_valuef() { EmptyListLit(_) => Ok((r, NaturalLit(0))), NEListLit(xs) => Ok((r, NaturalLit(xs.len()))), _ => Err(()), }, - (ListHead, [_, l, r..]) => match &*l.as_value() { + (ListHead, [_, l, r..]) => match &*l.as_valuef() { EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()))), NEListLit(xs) => { Ok((r, NEOptionalLit(xs.iter().next().unwrap().clone()))) } _ => Err(()), }, - (ListLast, [_, l, r..]) => match &*l.as_value() { + (ListLast, [_, l, r..]) => match &*l.as_valuef() { EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()))), NEListLit(xs) => { Ok((r, NEOptionalLit(xs.iter().rev().next().unwrap().clone()))) } _ => Err(()), }, - (ListReverse, [_, l, r..]) => match &*l.as_value() { + (ListReverse, [_, l, r..]) => match &*l.as_valuef() { EmptyListLit(n) => Ok((r, EmptyListLit(n.clone()))), NEListLit(xs) => { Ok((r, NEListLit(xs.iter().rev().cloned().collect()))) } _ => Err(()), }, - (ListIndexed, [_, l, r..]) => match &*l.as_value() { + (ListIndexed, [_, l, r..]) => match &*l.as_valuef() { EmptyListLit(t) => { let mut kts = HashMap::new(); kts.insert( "index".into(), - TypedThunk::from_value(Value::from_builtin(Natural)), + TypedThunk::from_valuef(ValueF::from_builtin(Natural)), ); kts.insert("value".into(), t.clone()); - Ok((r, EmptyListLit(TypedThunk::from_value(RecordType(kts))))) + Ok((r, EmptyListLit(TypedThunk::from_valuef(RecordType(kts))))) } NEListLit(xs) => { let xs = xs @@ -201,20 +201,20 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { .map(|(i, e)| { let i = NaturalLit(i); let mut kvs = HashMap::new(); - kvs.insert("index".into(), Thunk::from_value(i)); + kvs.insert("index".into(), Thunk::from_valuef(i)); kvs.insert("value".into(), e.clone()); - Thunk::from_value(RecordLit(kvs)) + Thunk::from_valuef(RecordLit(kvs)) }) .collect(); Ok((r, NEListLit(xs))) } _ => Err(()), }, - (ListBuild, [t, f, r..]) => match &*f.as_value() { + (ListBuild, [t, f, r..]) => match &*f.as_valuef() { // fold/build fusion - Value::AppliedBuiltin(ListFold, args) => { + ValueF::AppliedBuiltin(ListFold, args) => { if args.len() >= 2 { - Ok((r, args[1].to_value())) + Ok((r, args[1].to_valuef())) } else { // Do we really need to handle this case ? unimplemented!() @@ -222,7 +222,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { } _ => Ok(( r, - f.app_val(Value::from_builtin(List).app_thunk(t.clone())) + f.app_val(ValueF::from_builtin(List).app_thunk(t.clone())) .app_thunk({ // Move `t` under new `x` variable let t1 = t.under_binder(Label::from("x")); @@ -237,8 +237,8 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { ))), )), }, - (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_value() { - EmptyListLit(_) => Ok((r, nil.to_value())), + (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_valuef() { + EmptyListLit(_) => Ok((r, nil.to_valuef())), NEListLit(xs) => { let mut v = nil.clone(); for x in xs.iter().rev() { @@ -248,15 +248,15 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { .app_thunk(v) .into_thunk(); } - Ok((r, v.to_value())) + Ok((r, v.to_valuef())) } _ => Err(()), }, - (OptionalBuild, [t, f, r..]) => match &*f.as_value() { + (OptionalBuild, [t, f, r..]) => match &*f.as_valuef() { // fold/build fusion - Value::AppliedBuiltin(OptionalFold, args) => { + ValueF::AppliedBuiltin(OptionalFold, args) => { if args.len() >= 2 { - Ok((r, args[1].to_value())) + Ok((r, args[1].to_valuef())) } else { // Do we really need to handle this case ? unimplemented!() @@ -264,23 +264,25 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { } _ => Ok(( r, - f.app_val(Value::from_builtin(Optional).app_thunk(t.clone())) + f.app_val(ValueF::from_builtin(Optional).app_thunk(t.clone())) .app_thunk(make_closure!(λ(x: #t) -> Some var(x, 0))) .app_val(EmptyOptionalLit( TypedThunk::from_thunk_simple_type(t.clone()), )), )), }, - (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_value() { - EmptyOptionalLit(_) => Ok((r, nothing.to_value())), - NEOptionalLit(x) => Ok((r, just.app_thunk(x.clone()))), - _ => Err(()), - }, - (NaturalBuild, [f, r..]) => match &*f.as_value() { + (OptionalFold, [_, v, _, just, nothing, r..]) => { + match &*v.as_valuef() { + EmptyOptionalLit(_) => Ok((r, nothing.to_valuef())), + NEOptionalLit(x) => Ok((r, just.app_thunk(x.clone()))), + _ => Err(()), + } + } + (NaturalBuild, [f, r..]) => match &*f.as_valuef() { // fold/build fusion - Value::AppliedBuiltin(NaturalFold, args) => { + ValueF::AppliedBuiltin(NaturalFold, args) => { if !args.is_empty() { - Ok((r, args[0].to_value())) + Ok((r, args[0].to_valuef())) } else { // Do we really need to handle this case ? unimplemented!() @@ -288,15 +290,15 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { } _ => Ok(( r, - f.app_val(Value::from_builtin(Natural)) + f.app_val(ValueF::from_builtin(Natural)) .app_thunk(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) .app_val(NaturalLit(0)), )), }, - (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_value() { - NaturalLit(0) => Ok((r, zero.to_value())), + (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_valuef() { + NaturalLit(0) => Ok((r, zero.to_valuef())), NaturalLit(n) => { - let fold = Value::from_builtin(NaturalFold) + let fold = ValueF::from_builtin(NaturalFold) .app(NaturalLit(n - 1)) .app_thunk(t.clone()) .app_thunk(succ.clone()) @@ -319,22 +321,22 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> Value { } } -pub(crate) fn apply_any(f: Thunk, a: Thunk) -> Value { - let fallback = |f: Thunk, a: Thunk| Value::PartialExpr(ExprF::App(f, a)); +pub(crate) fn apply_any(f: Thunk, a: Thunk) -> ValueF { + let fallback = |f: Thunk, a: Thunk| ValueF::PartialExpr(ExprF::App(f, a)); - let f_borrow = f.as_value(); + let f_borrow = f.as_valuef(); match &*f_borrow { - Value::Lam(x, _, e) => { + ValueF::Lam(x, _, e) => { let val = Typed::from_thunk_untyped(a); - e.subst_shift(&x.into(), &val).to_value() + e.subst_shift(&x.into(), &val).to_valuef() } - Value::AppliedBuiltin(b, args) => { + ValueF::AppliedBuiltin(b, args) => { use std::iter::once; let args = args.iter().cloned().chain(once(a.clone())).collect(); apply_builtin(*b, args) } - Value::UnionConstructor(l, kts) => { - Value::UnionLit(l.clone(), a, kts.clone()) + ValueF::UnionConstructor(l, kts) => { + ValueF::UnionLit(l.clone(), a, kts.clone()) } _ => { drop(f_borrow); @@ -358,9 +360,9 @@ pub(crate) fn squash_textlit( match contents { Text(s) => crnt_str.push_str(&s), Expr(e) => { - let e_borrow = e.as_value(); + let e_borrow = e.as_valuef(); match &*e_borrow { - Value::TextLit(elts2) => { + ValueF::TextLit(elts2) => { inner(elts2.iter().cloned(), crnt_str, ret) } _ => { @@ -387,7 +389,7 @@ pub(crate) fn squash_textlit( // Small helper enum to avoid repetition enum Ret<'a> { - Value(Value), + ValueF(ValueF), Thunk(Thunk), ThunkRef(&'a Thunk), Expr(ExprF), @@ -512,67 +514,67 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { NaturalTimes, RecursiveRecordMerge, RecursiveRecordTypeMerge, RightBiasedRecordMerge, TextAppend, }; - use Value::{ + use ValueF::{ BoolLit, EmptyListLit, NEListLit, NaturalLit, RecordLit, RecordType, TextLit, }; - let x_borrow = x.as_value(); - let y_borrow = y.as_value(); + let x_borrow = x.as_valuef(); + let y_borrow = y.as_valuef(); Some(match (o, &*x_borrow, &*y_borrow) { (BoolAnd, BoolLit(true), _) => Ret::ThunkRef(y), (BoolAnd, _, BoolLit(true)) => Ret::ThunkRef(x), - (BoolAnd, BoolLit(false), _) => Ret::Value(BoolLit(false)), - (BoolAnd, _, BoolLit(false)) => Ret::Value(BoolLit(false)), + (BoolAnd, BoolLit(false), _) => Ret::ValueF(BoolLit(false)), + (BoolAnd, _, BoolLit(false)) => Ret::ValueF(BoolLit(false)), (BoolAnd, _, _) if x == y => Ret::ThunkRef(x), - (BoolOr, BoolLit(true), _) => Ret::Value(BoolLit(true)), - (BoolOr, _, BoolLit(true)) => Ret::Value(BoolLit(true)), + (BoolOr, BoolLit(true), _) => Ret::ValueF(BoolLit(true)), + (BoolOr, _, BoolLit(true)) => Ret::ValueF(BoolLit(true)), (BoolOr, BoolLit(false), _) => Ret::ThunkRef(y), (BoolOr, _, BoolLit(false)) => Ret::ThunkRef(x), (BoolOr, _, _) if x == y => Ret::ThunkRef(x), (BoolEQ, BoolLit(true), _) => Ret::ThunkRef(y), (BoolEQ, _, BoolLit(true)) => Ret::ThunkRef(x), - (BoolEQ, BoolLit(x), BoolLit(y)) => Ret::Value(BoolLit(x == y)), - (BoolEQ, _, _) if x == y => Ret::Value(BoolLit(true)), + (BoolEQ, BoolLit(x), BoolLit(y)) => Ret::ValueF(BoolLit(x == y)), + (BoolEQ, _, _) if x == y => Ret::ValueF(BoolLit(true)), (BoolNE, BoolLit(false), _) => Ret::ThunkRef(y), (BoolNE, _, BoolLit(false)) => Ret::ThunkRef(x), - (BoolNE, BoolLit(x), BoolLit(y)) => Ret::Value(BoolLit(x != y)), - (BoolNE, _, _) if x == y => Ret::Value(BoolLit(false)), + (BoolNE, BoolLit(x), BoolLit(y)) => Ret::ValueF(BoolLit(x != y)), + (BoolNE, _, _) if x == y => Ret::ValueF(BoolLit(false)), (NaturalPlus, NaturalLit(0), _) => Ret::ThunkRef(y), (NaturalPlus, _, NaturalLit(0)) => Ret::ThunkRef(x), (NaturalPlus, NaturalLit(x), NaturalLit(y)) => { - Ret::Value(NaturalLit(x + y)) + Ret::ValueF(NaturalLit(x + y)) } - (NaturalTimes, NaturalLit(0), _) => Ret::Value(NaturalLit(0)), - (NaturalTimes, _, NaturalLit(0)) => Ret::Value(NaturalLit(0)), + (NaturalTimes, NaturalLit(0), _) => Ret::ValueF(NaturalLit(0)), + (NaturalTimes, _, NaturalLit(0)) => Ret::ValueF(NaturalLit(0)), (NaturalTimes, NaturalLit(1), _) => Ret::ThunkRef(y), (NaturalTimes, _, NaturalLit(1)) => Ret::ThunkRef(x), (NaturalTimes, NaturalLit(x), NaturalLit(y)) => { - Ret::Value(NaturalLit(x * y)) + Ret::ValueF(NaturalLit(x * y)) } (ListAppend, EmptyListLit(_), _) => Ret::ThunkRef(y), (ListAppend, _, EmptyListLit(_)) => Ret::ThunkRef(x), - (ListAppend, NEListLit(xs), NEListLit(ys)) => { - Ret::Value(NEListLit(xs.iter().chain(ys.iter()).cloned().collect())) - } + (ListAppend, NEListLit(xs), NEListLit(ys)) => Ret::ValueF(NEListLit( + xs.iter().chain(ys.iter()).cloned().collect(), + )), (TextAppend, TextLit(x), _) if x.is_empty() => Ret::ThunkRef(y), (TextAppend, _, TextLit(y)) if y.is_empty() => Ret::ThunkRef(x), - (TextAppend, TextLit(x), TextLit(y)) => Ret::Value(TextLit( + (TextAppend, TextLit(x), TextLit(y)) => Ret::ValueF(TextLit( squash_textlit(x.iter().chain(y.iter()).cloned()), )), (TextAppend, TextLit(x), _) => { use std::iter::once; let y = InterpolatedTextContents::Expr(y.clone()); - Ret::Value(TextLit(squash_textlit( + Ret::ValueF(TextLit(squash_textlit( x.iter().cloned().chain(once(y)), ))) } (TextAppend, _, TextLit(y)) => { use std::iter::once; let x = InterpolatedTextContents::Expr(x.clone()); - Ret::Value(TextLit(squash_textlit( + Ret::ValueF(TextLit(squash_textlit( once(x).chain(y.iter().cloned()), ))) } @@ -589,7 +591,7 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { // Insert only if key not already present kvs.entry(x.clone()).or_insert_with(|| v.clone()); } - Ret::Value(RecordLit(kvs)) + Ret::ValueF(RecordLit(kvs)) } (RecursiveRecordMerge, _, RecordLit(kvs)) if kvs.is_empty() => { @@ -606,7 +608,7 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { v2.clone(), )) }); - Ret::Value(RecordLit(kvs)) + Ret::ValueF(RecordLit(kvs)) } (RecursiveRecordTypeMerge, _, RecordType(kvs)) if kvs.is_empty() => { @@ -625,10 +627,10 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { ), )) }); - Ret::Value(RecordType(kvs)) + Ret::ValueF(RecordType(kvs)) } - (Equivalence, _, _) => Ret::Value(Value::Equivalence( + (Equivalence, _, _) => Ret::ValueF(ValueF::Equivalence( TypedThunk::from_thunk_simple_type(x.clone()), TypedThunk::from_thunk_simple_type(y.clone()), )), @@ -637,8 +639,8 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { }) } -pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { - use Value::{ +pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { + use ValueF::{ AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, Lam, NEListLit, NEOptionalLit, NaturalLit, Pi, RecordLit, RecordType, TextLit, UnionConstructor, UnionLit, UnionType, @@ -653,9 +655,9 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { ExprF::Annot(x, _) => Ret::Thunk(x), ExprF::Assert(_) => Ret::Expr(expr), ExprF::Lam(x, t, e) => { - Ret::Value(Lam(x.into(), TypedThunk::from_thunk_untyped(t), e)) + Ret::ValueF(Lam(x.into(), TypedThunk::from_thunk_untyped(t), e)) } - ExprF::Pi(x, t, e) => Ret::Value(Pi( + ExprF::Pi(x, t, e) => Ret::ValueF(Pi( x.into(), TypedThunk::from_thunk_untyped(t), TypedThunk::from_thunk_untyped(e), @@ -664,20 +666,20 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { let v = Typed::from_thunk_untyped(v); Ret::Thunk(b.subst_shift(&x.into(), &v)) } - ExprF::App(v, a) => Ret::Value(v.app_thunk(a)), - ExprF::Builtin(b) => Ret::Value(Value::from_builtin(b)), - ExprF::Const(c) => Ret::Value(Value::Const(c)), - ExprF::BoolLit(b) => Ret::Value(BoolLit(b)), - ExprF::NaturalLit(n) => Ret::Value(NaturalLit(n)), - ExprF::IntegerLit(n) => Ret::Value(IntegerLit(n)), - ExprF::DoubleLit(n) => Ret::Value(DoubleLit(n)), - ExprF::SomeLit(e) => Ret::Value(NEOptionalLit(e)), + ExprF::App(v, a) => Ret::ValueF(v.app_thunk(a)), + ExprF::Builtin(b) => Ret::ValueF(ValueF::from_builtin(b)), + ExprF::Const(c) => Ret::ValueF(ValueF::Const(c)), + ExprF::BoolLit(b) => Ret::ValueF(BoolLit(b)), + ExprF::NaturalLit(n) => Ret::ValueF(NaturalLit(n)), + ExprF::IntegerLit(n) => Ret::ValueF(IntegerLit(n)), + ExprF::DoubleLit(n) => Ret::ValueF(DoubleLit(n)), + ExprF::SomeLit(e) => Ret::ValueF(NEOptionalLit(e)), ExprF::EmptyListLit(ref t) => { // Check if the type is of the form `List x` - let t_borrow = t.as_value(); + let t_borrow = t.as_valuef(); match &*t_borrow { AppliedBuiltin(Builtin::List, args) if args.len() == 1 => { - Ret::Value(EmptyListLit( + Ret::ValueF(EmptyListLit( TypedThunk::from_thunk_simple_type(args[0].clone()), )) } @@ -688,17 +690,17 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { } } ExprF::NEListLit(elts) => { - Ret::Value(NEListLit(elts.into_iter().collect())) + Ret::ValueF(NEListLit(elts.into_iter().collect())) } ExprF::RecordLit(kvs) => { - Ret::Value(RecordLit(kvs.into_iter().collect())) + Ret::ValueF(RecordLit(kvs.into_iter().collect())) } - ExprF::RecordType(kts) => Ret::Value(RecordType( + ExprF::RecordType(kts) => Ret::ValueF(RecordType( kts.into_iter() .map(|(k, t)| (k, TypedThunk::from_thunk_untyped(t))) .collect(), )), - ExprF::UnionType(kts) => Ret::Value(UnionType( + ExprF::UnionType(kts) => Ret::ValueF(UnionType( kts.into_iter() .map(|(k, t)| (k, t.map(|t| TypedThunk::from_thunk_untyped(t)))) .collect(), @@ -710,17 +712,17 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { if let [Expr(th)] = elts.as_slice() { Ret::Thunk(th.clone()) } else { - Ret::Value(TextLit(elts)) + Ret::ValueF(TextLit(elts)) } } ExprF::BoolIf(ref b, ref e1, ref e2) => { - let b_borrow = b.as_value(); + let b_borrow = b.as_valuef(); match &*b_borrow { BoolLit(true) => Ret::ThunkRef(e1), BoolLit(false) => Ret::ThunkRef(e2), _ => { - let e1_borrow = e1.as_value(); - let e2_borrow = e2.as_value(); + let e1_borrow = e1.as_valuef(); + let e2_borrow = e2.as_valuef(); match (&*e1_borrow, &*e2_borrow) { // Simplify `if b then True else False` (BoolLit(true), BoolLit(false)) => Ret::ThunkRef(b), @@ -741,12 +743,12 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { }, ExprF::Projection(_, ref ls) if ls.is_empty() => { - Ret::Value(RecordLit(HashMap::new())) + Ret::ValueF(RecordLit(HashMap::new())) } ExprF::Projection(ref v, ref ls) => { - let v_borrow = v.as_value(); + let v_borrow = v.as_valuef(); match &*v_borrow { - RecordLit(kvs) => Ret::Value(RecordLit( + RecordLit(kvs) => Ret::ValueF(RecordLit( ls.iter() .filter_map(|l| { kvs.get(l).map(|x| (l.clone(), x.clone())) @@ -760,7 +762,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { } } ExprF::Field(ref v, ref l) => { - let v_borrow = v.as_value(); + let v_borrow = v.as_valuef(); match &*v_borrow { RecordLit(kvs) => match kvs.get(l) { Some(r) => Ret::Thunk(r.clone()), @@ -770,7 +772,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { } }, UnionType(kts) => { - Ret::Value(UnionConstructor(l.clone(), kts.clone())) + Ret::ValueF(UnionConstructor(l.clone(), kts.clone())) } _ => { drop(v_borrow); @@ -780,8 +782,8 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { } ExprF::Merge(ref handlers, ref variant, _) => { - let handlers_borrow = handlers.as_value(); - let variant_borrow = variant.as_value(); + let handlers_borrow = handlers.as_valuef(); + let variant_borrow = variant.as_valuef(); match (&*handlers_borrow, &*variant_borrow) { (RecordLit(kvs), UnionConstructor(l, _)) => match kvs.get(l) { Some(h) => Ret::Thunk(h.clone()), @@ -792,7 +794,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { } }, (RecordLit(kvs), UnionLit(l, v, _)) => match kvs.get(l) { - Some(h) => Ret::Value(h.app_thunk(v.clone())), + Some(h) => Ret::ValueF(h.app_thunk(v.clone())), None => { drop(handlers_borrow); drop(variant_borrow); @@ -809,9 +811,9 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> Value { }; match ret { - Ret::Value(v) => v, - Ret::Thunk(th) => th.to_value(), - Ret::ThunkRef(th) => th.to_value(), - Ret::Expr(expr) => Value::PartialExpr(expr), + Ret::ValueF(v) => v, + Ret::Thunk(th) => th.to_valuef(), + Ret::ThunkRef(th) => th.to_valuef(), + Ret::Expr(expr) => ValueF::PartialExpr(expr), } } diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index dd6da70..8d7a3bc 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -6,7 +6,7 @@ use dhall_syntax::{ use crate::core::context::TypecheckContext; use crate::core::thunk::{Thunk, TypedThunk}; -use crate::core::value::Value; +use crate::core::value::ValueF; use crate::core::var::{Shift, Subst}; use crate::error::{TypeError, TypeMessage}; use crate::phase::{Normalized, Resolved, Type, Typed}; @@ -43,7 +43,7 @@ fn tck_pi_type( let k = function_check(ka, kb); Ok(Typed::from_thunk_and_type( - Value::Pi( + ValueF::Pi( x.into(), TypedThunk::from_type(tx), TypedThunk::from_type(te), @@ -88,7 +88,7 @@ fn tck_record_type( let k = k.unwrap_or(dhall_syntax::Const::Type); Ok(Typed::from_thunk_and_type( - Value::RecordType(new_kts).into_thunk(), + ValueF::RecordType(new_kts).into_thunk(), Type::from_const(k), )) } @@ -132,7 +132,7 @@ fn tck_union_type( let k = k.unwrap_or(dhall_syntax::Const::Type); Ok(Typed::from_thunk_and_type( - Value::UnionType(new_kts).into_thunk(), + ValueF::UnionType(new_kts).into_thunk(), Type::from_const(k), )) } @@ -335,14 +335,14 @@ fn type_with( let tx = mktype(ctx, t.clone())?; let ctx2 = ctx.insert_type(x, tx.clone()); let b = type_with(&ctx2, b.clone())?; - let v = Value::Lam( + let v = ValueF::Lam( x.clone().into(), TypedThunk::from_type(tx.clone()), b.to_thunk(), ); let tb = b.get_type()?.into_owned(); let t = tck_pi_type(ctx, x.clone(), tx, tb)?.to_type(); - Typed::from_thunk_and_type(Thunk::from_value(v), t) + Typed::from_thunk_and_type(Thunk::from_valuef(v), t) } Pi(x, ta, tb) => { let ta = mktype(ctx, ta.clone())?; @@ -415,8 +415,10 @@ fn type_last_layer( } App(f, a) => { let tf = f.get_type()?; - let (x, tx, tb) = match &tf.to_value() { - Value::Pi(x, tx, tb) => (x.clone(), tx.to_type(), tb.to_type()), + let (x, tx, tb) = match &tf.to_valuef() { + ValueF::Pi(x, tx, tb) => { + (x.clone(), tx.to_type(), tb.to_type()) + } _ => return Err(mkerr(NotAFunction(f.clone()))), }; if a.get_type()?.as_ref() != &tx { @@ -437,9 +439,9 @@ fn type_last_layer( Ok(RetTypeOnly(x.get_type()?.into_owned())) } Assert(t) => { - match t.to_value() { - Value::Equivalence(ref x, ref y) if x == y => {} - Value::Equivalence(x, y) => { + match t.to_valuef() { + ValueF::Equivalence(ref x, ref y) if x == y => {} + ValueF::Equivalence(x, y) => { return Err(mkerr(AssertMismatch( x.to_typed(), y.to_typed(), @@ -470,8 +472,8 @@ fn type_last_layer( } EmptyListLit(t) => { let t = t.to_type(); - match &t.to_value() { - Value::AppliedBuiltin(dhall_syntax::Builtin::List, args) + match &t.to_valuef() { + ValueF::AppliedBuiltin(dhall_syntax::Builtin::List, args) if args.len() == 1 => {} _ => { return Err(TypeError::new( @@ -504,8 +506,8 @@ fn type_last_layer( Ok(RetTypeOnly( Typed::from_thunk_and_type( - Value::from_builtin(dhall_syntax::Builtin::List) - .app(t.to_value()) + ValueF::from_builtin(dhall_syntax::Builtin::List) + .app(t.to_valuef()) .into_thunk(), Typed::from_const(Type), ) @@ -523,8 +525,8 @@ fn type_last_layer( Ok(RetTypeOnly( Typed::from_thunk_and_type( - Value::from_builtin(dhall_syntax::Builtin::Optional) - .app(t.to_value()) + ValueF::from_builtin(dhall_syntax::Builtin::Optional) + .app(t.to_valuef()) .into_thunk(), Typed::from_const(Type).into_type(), ) @@ -549,8 +551,8 @@ fn type_last_layer( .into_type(), )), Field(r, x) => { - match &r.get_type()?.to_value() { - Value::RecordType(kts) => match kts.get(&x) { + match &r.get_type()?.to_valuef() { + ValueF::RecordType(kts) => match kts.get(&x) { Some(tth) => { Ok(RetTypeOnly(tth.to_type())) }, @@ -560,8 +562,8 @@ fn type_last_layer( // TODO: branch here only when r.get_type() is a Const _ => { let r = r.to_type(); - match &r.to_value() { - Value::UnionType(kts) => match kts.get(&x) { + match &r.to_valuef() { + ValueF::UnionType(kts) => match kts.get(&x) { // Constructor has type T -> < x: T, ... > Some(Some(t)) => { Ok(RetTypeOnly( @@ -631,14 +633,14 @@ fn type_last_layer( } // Extract the LHS record type - let kts_x = match l_type.to_value() { - Value::RecordType(kts) => kts, + let kts_x = match l_type.to_valuef() { + ValueF::RecordType(kts) => kts, _ => return Err(mkerr(MustCombineRecord(l.clone()))), }; // Extract the RHS record type - let kts_y = match r_type.to_value() { - Value::RecordType(kts) => kts, + let kts_y = match r_type.to_valuef() { + ValueF::RecordType(kts) => kts, _ => return Err(mkerr(MustCombineRecord(r.clone()))), }; @@ -672,10 +674,10 @@ fn type_last_layer( inner_l: &TypedThunk, inner_r: &TypedThunk| -> Result { - match (inner_l.to_value(), inner_r.to_value()) { + match (inner_l.to_valuef(), inner_r.to_valuef()) { ( - Value::RecordType(inner_l_kvs), - Value::RecordType(inner_r_kvs), + ValueF::RecordType(inner_l_kvs), + ValueF::RecordType(inner_r_kvs), ) => { combine_record_types(ctx, inner_l_kvs, inner_r_kvs) } @@ -715,14 +717,14 @@ fn type_last_layer( } // Extract the LHS record type - let kts_x = match l_type.to_value() { - Value::RecordType(kts) => kts, + let kts_x = match l_type.to_valuef() { + ValueF::RecordType(kts) => kts, _ => return Err(mkerr(MustCombineRecord(l.clone()))), }; // Extract the RHS record type - let kts_y = match r_type.to_value() { - Value::RecordType(kts) => kts, + let kts_y = match r_type.to_valuef() { + ValueF::RecordType(kts) => kts, _ => return Err(mkerr(MustCombineRecord(r.clone()))), }; @@ -745,10 +747,10 @@ fn type_last_layer( kts_l_inner: &TypedThunk, kts_r_inner: &TypedThunk| -> Result { - match (kts_l_inner.to_value(), kts_r_inner.to_value()) { + match (kts_l_inner.to_valuef(), kts_r_inner.to_valuef()) { ( - Value::RecordType(kvs_l_inner), - Value::RecordType(kvs_r_inner), + ValueF::RecordType(kvs_l_inner), + ValueF::RecordType(kvs_r_inner), ) => { combine_record_types(ctx, kvs_l_inner, kvs_r_inner) } @@ -774,8 +776,8 @@ fn type_last_layer( }; // Extract the Const of the LHS - let k_l = match l.get_type()?.to_value() { - Value::Const(k) => k, + let k_l = match l.get_type()?.to_valuef() { + ValueF::Const(k) => k, _ => { return Err(mkerr(RecordTypeMergeRequiresRecordType( l.clone(), @@ -784,8 +786,8 @@ fn type_last_layer( }; // Extract the Const of the RHS - let k_r = match r.get_type()?.to_value() { - Value::Const(k) => k, + let k_r = match r.get_type()?.to_valuef() { + ValueF::Const(k) => k, _ => { return Err(mkerr(RecordTypeMergeRequiresRecordType( r.clone(), @@ -806,8 +808,8 @@ fn type_last_layer( }; // Extract the LHS record type - let kts_x = match l.to_value() { - Value::RecordType(kts) => kts, + let kts_x = match l.to_valuef() { + ValueF::RecordType(kts) => kts, _ => { return Err(mkerr(RecordTypeMergeRequiresRecordType( l.clone(), @@ -816,8 +818,8 @@ fn type_last_layer( }; // Extract the RHS record type - let kts_y = match r.to_value() { - Value::RecordType(kts) => kts, + let kts_y = match r.to_valuef() { + ValueF::RecordType(kts) => kts, _ => { return Err(mkerr(RecordTypeMergeRequiresRecordType( r.clone(), @@ -831,8 +833,8 @@ fn type_last_layer( .and(Ok(RetTypeOnly(Typed::from_const(k)))) } BinOp(o @ ListAppend, l, r) => { - match l.get_type()?.to_value() { - Value::AppliedBuiltin(List, _) => {} + match l.get_type()?.to_valuef() { + ValueF::AppliedBuiltin(List, _) => {} _ => return Err(mkerr(BinOpTypeMismatch(*o, l.clone()))), } @@ -893,13 +895,13 @@ fn type_last_layer( Ok(RetTypeOnly(t)) } Merge(record, union, type_annot) => { - let handlers = match record.get_type()?.to_value() { - Value::RecordType(kts) => kts, + let handlers = match record.get_type()?.to_valuef() { + ValueF::RecordType(kts) => kts, _ => return Err(mkerr(Merge1ArgMustBeRecord(record.clone()))), }; - let variants = match union.get_type()?.to_value() { - Value::UnionType(kts) => kts, + let variants = match union.get_type()?.to_valuef() { + ValueF::UnionType(kts) => kts, _ => return Err(mkerr(Merge2ArgMustBeUnion(union.clone()))), }; @@ -910,8 +912,8 @@ fn type_last_layer( Some(Some(variant_type)) => { let variant_type = variant_type.to_type(); let handler_type = handler.to_type(); - let (x, tx, tb) = match &handler_type.to_value() { - Value::Pi(x, tx, tb) => { + let (x, tx, tb) = match &handler_type.to_valuef() { + ValueF::Pi(x, tx, tb) => { (x.clone(), tx.to_type(), tb.to_type()) } _ => return Err(mkerr(NotAFunction(handler_type))), @@ -973,8 +975,8 @@ fn type_last_layer( } Projection(record, labels) => { let trecord = record.get_type()?; - let kts = match trecord.to_value() { - Value::RecordType(kts) => kts, + let kts = match trecord.to_valuef() { + ValueF::RecordType(kts) => kts, _ => return Err(mkerr(ProjectionMustBeRecord)), }; @@ -988,7 +990,7 @@ fn type_last_layer( Ok(RetTypeOnly( Typed::from_thunk_and_type( - Value::RecordType(new_kts).into_thunk(), + ValueF::RecordType(new_kts).into_thunk(), trecord.get_type()?.into_owned(), ) .to_type(), -- cgit v1.2.3 From 6753a1f97bb674d91dd4d42f2ddb25a8119e070d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 17 Aug 2019 19:00:43 +0200 Subject: s/Thunk/Value/ --- dhall/src/phase/mod.rs | 26 +++--- dhall/src/phase/normalize.rs | 208 ++++++++++++++++++++++--------------------- dhall/src/phase/typecheck.rs | 68 +++++++------- 3 files changed, 152 insertions(+), 150 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 7e74f95..c18f976 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -4,8 +4,8 @@ use std::path::Path; use dhall_syntax::{Const, SubExpr}; -use crate::core::thunk::{Thunk, TypedThunk}; -use crate::core::value::ValueF; +use crate::core::value::{TypedValue, Value}; +use crate::core::valuef::ValueF; use crate::core::var::{AlphaVar, Shift, Subst}; use crate::error::{EncodeError, Error, ImportError, TypeError}; @@ -33,7 +33,7 @@ pub struct Resolved(ResolvedSubExpr); /// A typed expression #[derive(Debug, Clone)] -pub struct Typed(TypedThunk); +pub struct Typed(TypedValue); /// A normalized expression. /// @@ -92,19 +92,19 @@ impl Typed { Normalized(self) } - pub(crate) fn from_thunk_and_type(th: Thunk, t: Type) -> Self { - Typed(TypedThunk::from_thunk_and_type(th, t)) + pub(crate) fn from_value_and_type(th: Value, t: Type) -> Self { + Typed(TypedValue::from_value_and_type(th, t)) } - pub(crate) fn from_thunk_untyped(th: Thunk) -> Self { - Typed(TypedThunk::from_thunk_untyped(th)) + pub(crate) fn from_value_untyped(th: Value) -> Self { + Typed(TypedValue::from_value_untyped(th)) } pub(crate) fn from_const(c: Const) -> Self { - Typed(TypedThunk::from_const(c)) + Typed(TypedValue::from_const(c)) } pub fn from_valuef_and_type(v: ValueF, t: Type) -> Self { - Typed(TypedThunk::from_valuef_and_type(v, t)) + Typed(TypedValue::from_valuef_and_type(v, t)) } - pub(crate) fn from_typethunk(th: TypedThunk) -> Self { + pub(crate) fn from_typedvalue(th: TypedValue) -> Self { Typed(th) } pub fn const_type() -> Self { @@ -120,8 +120,8 @@ impl Typed { pub(crate) fn to_expr_alpha(&self) -> NormalizedSubExpr { self.0.to_expr_alpha() } - pub fn to_thunk(&self) -> Thunk { - self.0.to_thunk() + pub fn to_value(&self) -> Value { + self.0.to_value() } // Deprecated pub fn to_type(&self) -> Type { @@ -131,7 +131,7 @@ impl Typed { pub(crate) fn into_type(self) -> Type { self } - pub(crate) fn into_typethunk(self) -> TypedThunk { + pub(crate) fn into_typedvalue(self) -> TypedValue { self.0 } pub(crate) fn to_normalized(&self) -> Normalized { diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index da54726..93f2528 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -5,8 +5,8 @@ use dhall_syntax::{ NaiveDouble, }; -use crate::core::thunk::{Thunk, TypedThunk}; -use crate::core::value::ValueF; +use crate::core::value::{TypedValue, Value}; +use crate::core::valuef::ValueF; use crate::core::var::{Shift, Subst}; use crate::phase::{Normalized, NormalizedSubExpr, Typed}; @@ -20,45 +20,45 @@ macro_rules! make_closure { Label::from(stringify!($var)).into(), $n ); - ValueF::Var(var).into_thunk() + ValueF::Var(var).into_value() }}; // Warning: assumes that $ty, as a dhall value, has type `Type` (λ($var:ident : $($ty:tt)*) -> $($rest:tt)*) => { ValueF::Lam( Label::from(stringify!($var)).into(), - TypedThunk::from_thunk_simple_type( + TypedValue::from_value_simple_type( make_closure!($($ty)*), ), make_closure!($($rest)*), - ).into_thunk() + ).into_value() }; - (Natural) => { ValueF::from_builtin(Builtin::Natural).into_thunk() }; + (Natural) => { ValueF::from_builtin(Builtin::Natural).into_value() }; (List $($rest:tt)*) => { ValueF::from_builtin(Builtin::List) - .app_thunk(make_closure!($($rest)*)) - .into_thunk() + .app_value(make_closure!($($rest)*)) + .into_value() }; (Some $($rest:tt)*) => { - ValueF::NEOptionalLit(make_closure!($($rest)*)).into_thunk() + ValueF::NEOptionalLit(make_closure!($($rest)*)).into_value() }; (1 + $($rest:tt)*) => { ValueF::PartialExpr(ExprF::BinOp( dhall_syntax::BinOp::NaturalPlus, make_closure!($($rest)*), - Thunk::from_valuef(ValueF::NaturalLit(1)), - )).into_thunk() + Value::from_valuef(ValueF::NaturalLit(1)), + )).into_value() }; ([ $($head:tt)* ] # $($tail:tt)*) => { ValueF::PartialExpr(ExprF::BinOp( dhall_syntax::BinOp::ListAppend, - ValueF::NEListLit(vec![make_closure!($($head)*)]).into_thunk(), + ValueF::NEListLit(vec![make_closure!($($head)*)]).into_value(), make_closure!($($tail)*), - )).into_thunk() + )).into_value() }; } #[allow(clippy::cognitive_complexity)] -pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { +pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { use dhall_syntax::Builtin::*; use ValueF::*; @@ -66,7 +66,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { let ret = match (b, args.as_slice()) { (OptionalNone, [t, r..]) => Ok(( r, - EmptyOptionalLit(TypedThunk::from_thunk_simple_type(t.clone())), + EmptyOptionalLit(TypedValue::from_value_simple_type(t.clone())), )), (NaturalIsZero, [n, r..]) => match &*n.as_valuef() { NaturalLit(n) => Ok((r, BoolLit(*n == 0))), @@ -189,10 +189,10 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { let mut kts = HashMap::new(); kts.insert( "index".into(), - TypedThunk::from_valuef(ValueF::from_builtin(Natural)), + TypedValue::from_valuef(ValueF::from_builtin(Natural)), ); kts.insert("value".into(), t.clone()); - Ok((r, EmptyListLit(TypedThunk::from_valuef(RecordType(kts))))) + Ok((r, EmptyListLit(TypedValue::from_valuef(RecordType(kts))))) } NEListLit(xs) => { let xs = xs @@ -201,9 +201,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { .map(|(i, e)| { let i = NaturalLit(i); let mut kvs = HashMap::new(); - kvs.insert("index".into(), Thunk::from_valuef(i)); + kvs.insert("index".into(), Value::from_valuef(i)); kvs.insert("value".into(), e.clone()); - Thunk::from_valuef(RecordLit(kvs)) + Value::from_valuef(RecordLit(kvs)) }) .collect(); Ok((r, NEListLit(xs))) @@ -222,8 +222,8 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } _ => Ok(( r, - f.app_val(ValueF::from_builtin(List).app_thunk(t.clone())) - .app_thunk({ + f.app_valuef(ValueF::from_builtin(List).app_value(t.clone())) + .app_value({ // Move `t` under new `x` variable let t1 = t.under_binder(Label::from("x")); make_closure!( @@ -232,9 +232,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { [ var(x, 1) ] # var(xs, 0) ) }) - .app_val(EmptyListLit(TypedThunk::from_thunk_simple_type( - t.clone(), - ))), + .app_valuef(EmptyListLit( + TypedValue::from_value_simple_type(t.clone()), + )), )), }, (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_valuef() { @@ -244,9 +244,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { for x in xs.iter().rev() { v = cons .clone() - .app_thunk(x.clone()) - .app_thunk(v) - .into_thunk(); + .app_value(x.clone()) + .app_value(v) + .into_value(); } Ok((r, v.to_valuef())) } @@ -264,17 +264,19 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } _ => Ok(( r, - f.app_val(ValueF::from_builtin(Optional).app_thunk(t.clone())) - .app_thunk(make_closure!(λ(x: #t) -> Some var(x, 0))) - .app_val(EmptyOptionalLit( - TypedThunk::from_thunk_simple_type(t.clone()), - )), + f.app_valuef( + ValueF::from_builtin(Optional).app_value(t.clone()), + ) + .app_value(make_closure!(λ(x: #t) -> Some var(x, 0))) + .app_valuef(EmptyOptionalLit( + TypedValue::from_value_simple_type(t.clone()), + )), )), }, (OptionalFold, [_, v, _, just, nothing, r..]) => { match &*v.as_valuef() { EmptyOptionalLit(_) => Ok((r, nothing.to_valuef())), - NEOptionalLit(x) => Ok((r, just.app_thunk(x.clone()))), + NEOptionalLit(x) => Ok((r, just.app_value(x.clone()))), _ => Err(()), } } @@ -290,9 +292,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } _ => Ok(( r, - f.app_val(ValueF::from_builtin(Natural)) - .app_thunk(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) - .app_val(NaturalLit(0)), + f.app_valuef(ValueF::from_builtin(Natural)) + .app_value(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) + .app_valuef(NaturalLit(0)), )), }, (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_valuef() { @@ -300,10 +302,10 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { NaturalLit(n) => { let fold = ValueF::from_builtin(NaturalFold) .app(NaturalLit(n - 1)) - .app_thunk(t.clone()) - .app_thunk(succ.clone()) - .app_thunk(zero.clone()); - Ok((r, succ.app_val(fold))) + .app_value(t.clone()) + .app_value(succ.clone()) + .app_value(zero.clone()); + Ok((r, succ.app_valuef(fold))) } _ => Err(()), }, @@ -313,7 +315,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { Ok((unconsumed_args, mut v)) => { let n_consumed_args = args.len() - unconsumed_args.len(); for x in args.into_iter().skip(n_consumed_args) { - v = v.app_thunk(x); + v = v.app_value(x); } v } @@ -321,13 +323,13 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } } -pub(crate) fn apply_any(f: Thunk, a: Thunk) -> ValueF { - let fallback = |f: Thunk, a: Thunk| ValueF::PartialExpr(ExprF::App(f, a)); +pub(crate) fn apply_any(f: Value, a: Value) -> ValueF { + let fallback = |f: Value, a: Value| ValueF::PartialExpr(ExprF::App(f, a)); let f_borrow = f.as_valuef(); match &*f_borrow { ValueF::Lam(x, _, e) => { - let val = Typed::from_thunk_untyped(a); + let val = Typed::from_value_untyped(a); e.subst_shift(&x.into(), &val).to_valuef() } ValueF::AppliedBuiltin(b, args) => { @@ -346,15 +348,15 @@ pub(crate) fn apply_any(f: Thunk, a: Thunk) -> ValueF { } pub(crate) fn squash_textlit( - elts: impl Iterator>, -) -> Vec> { + elts: impl Iterator>, +) -> Vec> { use std::mem::replace; use InterpolatedTextContents::{Expr, Text}; fn inner( - elts: impl Iterator>, + elts: impl Iterator>, crnt_str: &mut String, - ret: &mut Vec>, + ret: &mut Vec>, ) { for contents in elts { match contents { @@ -390,9 +392,9 @@ pub(crate) fn squash_textlit( // Small helper enum to avoid repetition enum Ret<'a> { ValueF(ValueF), - Thunk(Thunk), - ThunkRef(&'a Thunk), - Expr(ExprF), + Value(Value), + ValueRef(&'a Value), + Expr(ExprF), } /// Performs an intersection of two HashMaps. @@ -508,7 +510,7 @@ where kvs } -fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { +fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { use BinOp::{ BoolAnd, BoolEQ, BoolNE, BoolOr, Equivalence, ListAppend, NaturalPlus, NaturalTimes, RecursiveRecordMerge, RecursiveRecordTypeMerge, @@ -521,46 +523,46 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { let x_borrow = x.as_valuef(); let y_borrow = y.as_valuef(); Some(match (o, &*x_borrow, &*y_borrow) { - (BoolAnd, BoolLit(true), _) => Ret::ThunkRef(y), - (BoolAnd, _, BoolLit(true)) => Ret::ThunkRef(x), + (BoolAnd, BoolLit(true), _) => Ret::ValueRef(y), + (BoolAnd, _, BoolLit(true)) => Ret::ValueRef(x), (BoolAnd, BoolLit(false), _) => Ret::ValueF(BoolLit(false)), (BoolAnd, _, BoolLit(false)) => Ret::ValueF(BoolLit(false)), - (BoolAnd, _, _) if x == y => Ret::ThunkRef(x), + (BoolAnd, _, _) if x == y => Ret::ValueRef(x), (BoolOr, BoolLit(true), _) => Ret::ValueF(BoolLit(true)), (BoolOr, _, BoolLit(true)) => Ret::ValueF(BoolLit(true)), - (BoolOr, BoolLit(false), _) => Ret::ThunkRef(y), - (BoolOr, _, BoolLit(false)) => Ret::ThunkRef(x), - (BoolOr, _, _) if x == y => Ret::ThunkRef(x), - (BoolEQ, BoolLit(true), _) => Ret::ThunkRef(y), - (BoolEQ, _, BoolLit(true)) => Ret::ThunkRef(x), + (BoolOr, BoolLit(false), _) => Ret::ValueRef(y), + (BoolOr, _, BoolLit(false)) => Ret::ValueRef(x), + (BoolOr, _, _) if x == y => Ret::ValueRef(x), + (BoolEQ, BoolLit(true), _) => Ret::ValueRef(y), + (BoolEQ, _, BoolLit(true)) => Ret::ValueRef(x), (BoolEQ, BoolLit(x), BoolLit(y)) => Ret::ValueF(BoolLit(x == y)), (BoolEQ, _, _) if x == y => Ret::ValueF(BoolLit(true)), - (BoolNE, BoolLit(false), _) => Ret::ThunkRef(y), - (BoolNE, _, BoolLit(false)) => Ret::ThunkRef(x), + (BoolNE, BoolLit(false), _) => Ret::ValueRef(y), + (BoolNE, _, BoolLit(false)) => Ret::ValueRef(x), (BoolNE, BoolLit(x), BoolLit(y)) => Ret::ValueF(BoolLit(x != y)), (BoolNE, _, _) if x == y => Ret::ValueF(BoolLit(false)), - (NaturalPlus, NaturalLit(0), _) => Ret::ThunkRef(y), - (NaturalPlus, _, NaturalLit(0)) => Ret::ThunkRef(x), + (NaturalPlus, NaturalLit(0), _) => Ret::ValueRef(y), + (NaturalPlus, _, NaturalLit(0)) => Ret::ValueRef(x), (NaturalPlus, NaturalLit(x), NaturalLit(y)) => { Ret::ValueF(NaturalLit(x + y)) } (NaturalTimes, NaturalLit(0), _) => Ret::ValueF(NaturalLit(0)), (NaturalTimes, _, NaturalLit(0)) => Ret::ValueF(NaturalLit(0)), - (NaturalTimes, NaturalLit(1), _) => Ret::ThunkRef(y), - (NaturalTimes, _, NaturalLit(1)) => Ret::ThunkRef(x), + (NaturalTimes, NaturalLit(1), _) => Ret::ValueRef(y), + (NaturalTimes, _, NaturalLit(1)) => Ret::ValueRef(x), (NaturalTimes, NaturalLit(x), NaturalLit(y)) => { Ret::ValueF(NaturalLit(x * y)) } - (ListAppend, EmptyListLit(_), _) => Ret::ThunkRef(y), - (ListAppend, _, EmptyListLit(_)) => Ret::ThunkRef(x), + (ListAppend, EmptyListLit(_), _) => Ret::ValueRef(y), + (ListAppend, _, EmptyListLit(_)) => Ret::ValueRef(x), (ListAppend, NEListLit(xs), NEListLit(ys)) => Ret::ValueF(NEListLit( xs.iter().chain(ys.iter()).cloned().collect(), )), - (TextAppend, TextLit(x), _) if x.is_empty() => Ret::ThunkRef(y), - (TextAppend, _, TextLit(y)) if y.is_empty() => Ret::ThunkRef(x), + (TextAppend, TextLit(x), _) if x.is_empty() => Ret::ValueRef(y), + (TextAppend, _, TextLit(y)) if y.is_empty() => Ret::ValueRef(x), (TextAppend, TextLit(x), TextLit(y)) => Ret::ValueF(TextLit( squash_textlit(x.iter().chain(y.iter()).cloned()), )), @@ -580,10 +582,10 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { } (RightBiasedRecordMerge, _, RecordLit(kvs)) if kvs.is_empty() => { - Ret::ThunkRef(x) + Ret::ValueRef(x) } (RightBiasedRecordMerge, RecordLit(kvs), _) if kvs.is_empty() => { - Ret::ThunkRef(y) + Ret::ValueRef(y) } (RightBiasedRecordMerge, RecordLit(kvs1), RecordLit(kvs2)) => { let mut kvs = kvs2.clone(); @@ -595,14 +597,14 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { } (RecursiveRecordMerge, _, RecordLit(kvs)) if kvs.is_empty() => { - Ret::ThunkRef(x) + Ret::ValueRef(x) } (RecursiveRecordMerge, RecordLit(kvs), _) if kvs.is_empty() => { - Ret::ThunkRef(y) + Ret::ValueRef(y) } (RecursiveRecordMerge, RecordLit(kvs1), RecordLit(kvs2)) => { let kvs = merge_maps(kvs1, kvs2, |v1, v2| { - Thunk::from_partial_expr(ExprF::BinOp( + Value::from_partial_expr(ExprF::BinOp( RecursiveRecordMerge, v1.clone(), v2.clone(), @@ -612,18 +614,18 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { } (RecursiveRecordTypeMerge, _, RecordType(kvs)) if kvs.is_empty() => { - Ret::ThunkRef(x) + Ret::ValueRef(x) } (RecursiveRecordTypeMerge, RecordType(kvs), _) if kvs.is_empty() => { - Ret::ThunkRef(y) + Ret::ValueRef(y) } (RecursiveRecordTypeMerge, RecordType(kvs1), RecordType(kvs2)) => { let kvs = merge_maps(kvs1, kvs2, |v1, v2| { - TypedThunk::from_thunk_untyped(Thunk::from_partial_expr( + TypedValue::from_value_untyped(Value::from_partial_expr( ExprF::BinOp( RecursiveRecordTypeMerge, - v1.to_thunk(), - v2.to_thunk(), + v1.to_value(), + v2.to_value(), ), )) }); @@ -631,15 +633,15 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option> { } (Equivalence, _, _) => Ret::ValueF(ValueF::Equivalence( - TypedThunk::from_thunk_simple_type(x.clone()), - TypedThunk::from_thunk_simple_type(y.clone()), + TypedValue::from_value_simple_type(x.clone()), + TypedValue::from_value_simple_type(y.clone()), )), _ => return None, }) } -pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { +pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { use ValueF::{ AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, Lam, NEListLit, NEOptionalLit, NaturalLit, Pi, RecordLit, RecordType, @@ -652,21 +654,21 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { ), ExprF::Embed(_) => unreachable!(), ExprF::Var(_) => unreachable!(), - ExprF::Annot(x, _) => Ret::Thunk(x), + ExprF::Annot(x, _) => Ret::Value(x), ExprF::Assert(_) => Ret::Expr(expr), ExprF::Lam(x, t, e) => { - Ret::ValueF(Lam(x.into(), TypedThunk::from_thunk_untyped(t), e)) + Ret::ValueF(Lam(x.into(), TypedValue::from_value_untyped(t), e)) } ExprF::Pi(x, t, e) => Ret::ValueF(Pi( x.into(), - TypedThunk::from_thunk_untyped(t), - TypedThunk::from_thunk_untyped(e), + TypedValue::from_value_untyped(t), + TypedValue::from_value_untyped(e), )), ExprF::Let(x, _, v, b) => { - let v = Typed::from_thunk_untyped(v); - Ret::Thunk(b.subst_shift(&x.into(), &v)) + let v = Typed::from_value_untyped(v); + Ret::Value(b.subst_shift(&x.into(), &v)) } - ExprF::App(v, a) => Ret::ValueF(v.app_thunk(a)), + ExprF::App(v, a) => Ret::ValueF(v.app_value(a)), ExprF::Builtin(b) => Ret::ValueF(ValueF::from_builtin(b)), ExprF::Const(c) => Ret::ValueF(ValueF::Const(c)), ExprF::BoolLit(b) => Ret::ValueF(BoolLit(b)), @@ -680,7 +682,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { match &*t_borrow { AppliedBuiltin(Builtin::List, args) if args.len() == 1 => { Ret::ValueF(EmptyListLit( - TypedThunk::from_thunk_simple_type(args[0].clone()), + TypedValue::from_value_simple_type(args[0].clone()), )) } _ => { @@ -697,12 +699,12 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { } ExprF::RecordType(kts) => Ret::ValueF(RecordType( kts.into_iter() - .map(|(k, t)| (k, TypedThunk::from_thunk_untyped(t))) + .map(|(k, t)| (k, TypedValue::from_value_untyped(t))) .collect(), )), ExprF::UnionType(kts) => Ret::ValueF(UnionType( kts.into_iter() - .map(|(k, t)| (k, t.map(|t| TypedThunk::from_thunk_untyped(t)))) + .map(|(k, t)| (k, t.map(|t| TypedValue::from_value_untyped(t)))) .collect(), )), ExprF::TextLit(elts) => { @@ -710,7 +712,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { let elts: Vec<_> = squash_textlit(elts.into_iter()); // Simplify bare interpolation if let [Expr(th)] = elts.as_slice() { - Ret::Thunk(th.clone()) + Ret::Value(th.clone()) } else { Ret::ValueF(TextLit(elts)) } @@ -718,15 +720,15 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { ExprF::BoolIf(ref b, ref e1, ref e2) => { let b_borrow = b.as_valuef(); match &*b_borrow { - BoolLit(true) => Ret::ThunkRef(e1), - BoolLit(false) => Ret::ThunkRef(e2), + BoolLit(true) => Ret::ValueRef(e1), + BoolLit(false) => Ret::ValueRef(e2), _ => { let e1_borrow = e1.as_valuef(); let e2_borrow = e2.as_valuef(); match (&*e1_borrow, &*e2_borrow) { // Simplify `if b then True else False` - (BoolLit(true), BoolLit(false)) => Ret::ThunkRef(b), - _ if e1 == e2 => Ret::ThunkRef(e1), + (BoolLit(true), BoolLit(false)) => Ret::ValueRef(b), + _ if e1 == e2 => Ret::ValueRef(e1), _ => { drop(b_borrow); drop(e1_borrow); @@ -765,7 +767,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { let v_borrow = v.as_valuef(); match &*v_borrow { RecordLit(kvs) => match kvs.get(l) { - Some(r) => Ret::Thunk(r.clone()), + Some(r) => Ret::Value(r.clone()), None => { drop(v_borrow); Ret::Expr(expr) @@ -786,7 +788,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { let variant_borrow = variant.as_valuef(); match (&*handlers_borrow, &*variant_borrow) { (RecordLit(kvs), UnionConstructor(l, _)) => match kvs.get(l) { - Some(h) => Ret::Thunk(h.clone()), + Some(h) => Ret::Value(h.clone()), None => { drop(handlers_borrow); drop(variant_borrow); @@ -794,7 +796,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { } }, (RecordLit(kvs), UnionLit(l, v, _)) => match kvs.get(l) { - Some(h) => Ret::ValueF(h.app_thunk(v.clone())), + Some(h) => Ret::ValueF(h.app_value(v.clone())), None => { drop(handlers_borrow); drop(variant_borrow); @@ -812,8 +814,8 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { match ret { Ret::ValueF(v) => v, - Ret::Thunk(th) => th.to_valuef(), - Ret::ThunkRef(th) => th.to_valuef(), + Ret::Value(th) => th.to_valuef(), + Ret::ValueRef(th) => th.to_valuef(), Ret::Expr(expr) => ValueF::PartialExpr(expr), } } diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 8d7a3bc..4154afe 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -5,8 +5,8 @@ use dhall_syntax::{ }; use crate::core::context::TypecheckContext; -use crate::core::thunk::{Thunk, TypedThunk}; -use crate::core::value::ValueF; +use crate::core::value::{TypedValue, Value}; +use crate::core::valuef::ValueF; use crate::core::var::{Shift, Subst}; use crate::error::{TypeError, TypeMessage}; use crate::phase::{Normalized, Resolved, Type, Typed}; @@ -42,13 +42,13 @@ fn tck_pi_type( let k = function_check(ka, kb); - Ok(Typed::from_thunk_and_type( + Ok(Typed::from_value_and_type( ValueF::Pi( x.into(), - TypedThunk::from_type(tx), - TypedThunk::from_type(te), + TypedValue::from_type(tx), + TypedValue::from_type(te), ) - .into_thunk(), + .into_value(), Type::from_const(k), )) } @@ -80,15 +80,15 @@ fn tck_record_type( return Err(TypeError::new(ctx, RecordTypeDuplicateField)) } Entry::Vacant(_) => { - entry.or_insert_with(|| TypedThunk::from_type(t.clone())) + entry.or_insert_with(|| TypedValue::from_type(t.clone())) } }; } // An empty record type has type Type let k = k.unwrap_or(dhall_syntax::Const::Type); - Ok(Typed::from_thunk_and_type( - ValueF::RecordType(new_kts).into_thunk(), + Ok(Typed::from_value_and_type( + ValueF::RecordType(new_kts).into_value(), Type::from_const(k), )) } @@ -122,7 +122,7 @@ fn tck_union_type( return Err(TypeError::new(ctx, UnionTypeDuplicateField)) } Entry::Vacant(_) => entry.or_insert_with(|| { - t.as_ref().map(|t| TypedThunk::from_type(t.clone())) + t.as_ref().map(|t| TypedValue::from_type(t.clone())) }), }; } @@ -131,8 +131,8 @@ fn tck_union_type( // an union type with only unary variants also has type Type let k = k.unwrap_or(dhall_syntax::Const::Type); - Ok(Typed::from_thunk_and_type( - ValueF::UnionType(new_kts).into_thunk(), + Ok(Typed::from_value_and_type( + ValueF::UnionType(new_kts).into_value(), Type::from_const(k), )) } @@ -337,12 +337,12 @@ fn type_with( let b = type_with(&ctx2, b.clone())?; let v = ValueF::Lam( x.clone().into(), - TypedThunk::from_type(tx.clone()), - b.to_thunk(), + TypedValue::from_type(tx.clone()), + b.to_value(), ); let tb = b.get_type()?.into_owned(); let t = tck_pi_type(ctx, x.clone(), tx, tb)?.to_type(); - Typed::from_thunk_and_type(Thunk::from_valuef(v), t) + Typed::from_value_and_type(Value::from_valuef(v), t) } Pi(x, ta, tb) => { let ta = mktype(ctx, ta.clone())?; @@ -380,9 +380,9 @@ fn type_with( let ret = type_last_layer(ctx, &expr)?; match ret { RetTypeOnly(typ) => { - let expr = expr.map_ref(|typed| typed.to_thunk()); - Typed::from_thunk_and_type( - Thunk::from_partial_expr(expr), + let expr = expr.map_ref(|typed| typed.to_value()); + Typed::from_value_and_type( + Value::from_partial_expr(expr), typ, ) } @@ -505,10 +505,10 @@ fn type_last_layer( } Ok(RetTypeOnly( - Typed::from_thunk_and_type( + Typed::from_value_and_type( ValueF::from_builtin(dhall_syntax::Builtin::List) .app(t.to_valuef()) - .into_thunk(), + .into_value(), Typed::from_const(Type), ) .to_type(), @@ -524,10 +524,10 @@ fn type_last_layer( } Ok(RetTypeOnly( - Typed::from_thunk_and_type( + Typed::from_value_and_type( ValueF::from_builtin(dhall_syntax::Builtin::Optional) .app(t.to_valuef()) - .into_thunk(), + .into_value(), Typed::from_const(Type).into_type(), ) .to_type(), @@ -662,8 +662,8 @@ fn type_last_layer( // records of records when merging. fn combine_record_types( ctx: &TypecheckContext, - kts_l: HashMap, - kts_r: HashMap, + kts_l: HashMap, + kts_r: HashMap, ) -> Result { use crate::phase::normalize::outer_join; @@ -671,8 +671,8 @@ fn type_last_layer( // are records themselves, then we hit the recursive case. // Otherwise we have a field collision. let combine = |k: &Label, - inner_l: &TypedThunk, - inner_r: &TypedThunk| + inner_l: &TypedValue, + inner_r: &TypedValue| -> Result { match (inner_l.to_valuef(), inner_r.to_valuef()) { ( @@ -690,7 +690,7 @@ fn type_last_layer( let kts: HashMap> = outer_join( |l| Ok(l.to_type()), |r| Ok(r.to_type()), - |k: &Label, l: &TypedThunk, r: &TypedThunk| { + |k: &Label, l: &TypedValue, r: &TypedValue| { combine(k, l, r) }, &kts_l, @@ -735,8 +735,8 @@ fn type_last_layer( // records of records when merging. fn combine_record_types( ctx: &TypecheckContext, - kts_l: HashMap, - kts_r: HashMap, + kts_l: HashMap, + kts_r: HashMap, ) -> Result { use crate::phase::normalize::intersection_with_key; @@ -744,8 +744,8 @@ fn type_last_layer( // are records themselves, then we hit the recursive case. // Otherwise we have a field collision. let combine = |k: &Label, - kts_l_inner: &TypedThunk, - kts_r_inner: &TypedThunk| + kts_l_inner: &TypedValue, + kts_r_inner: &TypedValue| -> Result { match (kts_l_inner.to_valuef(), kts_r_inner.to_valuef()) { ( @@ -761,7 +761,7 @@ fn type_last_layer( }; let kts = intersection_with_key( - |k: &Label, l: &TypedThunk, r: &TypedThunk| { + |k: &Label, l: &TypedValue, r: &TypedValue| { combine(k, l, r) }, &kts_l, @@ -989,8 +989,8 @@ fn type_last_layer( } Ok(RetTypeOnly( - Typed::from_thunk_and_type( - ValueF::RecordType(new_kts).into_thunk(), + Typed::from_value_and_type( + ValueF::RecordType(new_kts).into_value(), trecord.get_type()?.into_owned(), ) .to_type(), -- cgit v1.2.3 From c7d9a8659214a228963ea40d76e361bbc08129bb Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 18 Aug 2019 15:24:13 +0200 Subject: Rework ValueInternal and clarify invariants around ValueF --- dhall/src/phase/normalize.rs | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 93f2528..6c65e43 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -389,14 +389,6 @@ pub(crate) fn squash_textlit( ret } -// Small helper enum to avoid repetition -enum Ret<'a> { - ValueF(ValueF), - Value(Value), - ValueRef(&'a Value), - Expr(ExprF), -} - /// Performs an intersection of two HashMaps. /// /// # Arguments @@ -510,6 +502,14 @@ where kvs } +// Small helper enum to avoid repetition +enum Ret<'a> { + ValueF(ValueF), + Value(Value), + ValueRef(&'a Value), + Expr(ExprF), +} + fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { use BinOp::{ BoolAnd, BoolEQ, BoolNE, BoolOr, Equivalence, ListAppend, NaturalPlus, @@ -819,3 +819,16 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { Ret::Expr(expr) => ValueF::PartialExpr(expr), } } + +/// Normalize a ValueF into WHNF +pub(crate) fn normalize_whnf(v: ValueF) -> ValueF { + match v { + ValueF::AppliedBuiltin(b, args) => apply_builtin(b, args), + ValueF::PartialExpr(e) => normalize_one_layer(e), + ValueF::TextLit(elts) => { + ValueF::TextLit(squash_textlit(elts.into_iter())) + } + // All other cases are already in WHNF + v => v, + } +} -- cgit v1.2.3 From 29016b78736dca857e4e7f7c4dc68ed5e30c28bb Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 19 Aug 2019 12:25:09 +0200 Subject: s/to_valuef/to_whnf/ and avoid cloning ValueFs when possible --- dhall/src/phase/mod.rs | 15 ++-- dhall/src/phase/normalize.rs | 94 ++++++++++---------- dhall/src/phase/typecheck.rs | 198 ++++++++++++++++++++----------------------- 3 files changed, 149 insertions(+), 158 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index c18f976..a38e9d3 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::cell::Ref; use std::fmt::Display; use std::path::Path; @@ -111,8 +112,13 @@ impl Typed { Typed::from_const(Const::Type) } - pub(crate) fn to_valuef(&self) -> ValueF { - self.0.to_valuef() + /// WARNING: drop this ref before normalizing the same value or you will run into BorrowMut + /// panics. + pub(crate) fn as_whnf(&self) -> Ref { + self.0.as_whnf() + } + pub(crate) fn to_whnf(&self) -> ValueF { + self.0.to_whnf() } pub fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() @@ -134,9 +140,6 @@ impl Typed { pub(crate) fn into_typedvalue(self) -> TypedValue { self.0 } - pub(crate) fn to_normalized(&self) -> Normalized { - self.clone().normalize() - } pub(crate) fn as_const(&self) -> Option { self.0.as_const() } @@ -229,7 +232,7 @@ impl std::hash::Hash for Normalized { impl Eq for Typed {} impl PartialEq for Typed { fn eq(&self, other: &Self) -> bool { - self.to_valuef() == other.to_valuef() + self.0 == other.0 } } diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 6c65e43..785a75f 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -68,23 +68,23 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { r, EmptyOptionalLit(TypedValue::from_value_simple_type(t.clone())), )), - (NaturalIsZero, [n, r..]) => match &*n.as_valuef() { + (NaturalIsZero, [n, r..]) => match &*n.as_whnf() { NaturalLit(n) => Ok((r, BoolLit(*n == 0))), _ => Err(()), }, - (NaturalEven, [n, r..]) => match &*n.as_valuef() { + (NaturalEven, [n, r..]) => match &*n.as_whnf() { NaturalLit(n) => Ok((r, BoolLit(*n % 2 == 0))), _ => Err(()), }, - (NaturalOdd, [n, r..]) => match &*n.as_valuef() { + (NaturalOdd, [n, r..]) => match &*n.as_whnf() { NaturalLit(n) => Ok((r, BoolLit(*n % 2 != 0))), _ => Err(()), }, - (NaturalToInteger, [n, r..]) => match &*n.as_valuef() { + (NaturalToInteger, [n, r..]) => match &*n.as_whnf() { NaturalLit(n) => Ok((r, IntegerLit(*n as isize))), _ => Err(()), }, - (NaturalShow, [n, r..]) => match &*n.as_valuef() { + (NaturalShow, [n, r..]) => match &*n.as_whnf() { NaturalLit(n) => Ok(( r, TextLit(vec![InterpolatedTextContents::Text(n.to_string())]), @@ -92,7 +92,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { _ => Err(()), }, (NaturalSubtract, [a, b, r..]) => { - match (&*a.as_valuef(), &*b.as_valuef()) { + match (&*a.as_whnf(), &*b.as_whnf()) { (NaturalLit(a), NaturalLit(b)) => { Ok((r, NaturalLit(if b > a { b - a } else { 0 }))) } @@ -102,7 +102,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { _ => Err(()), } } - (IntegerShow, [n, r..]) => match &*n.as_valuef() { + (IntegerShow, [n, r..]) => match &*n.as_whnf() { IntegerLit(n) => { let s = if *n < 0 { n.to_string() @@ -113,18 +113,18 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } _ => Err(()), }, - (IntegerToDouble, [n, r..]) => match &*n.as_valuef() { + (IntegerToDouble, [n, r..]) => match &*n.as_whnf() { IntegerLit(n) => Ok((r, DoubleLit(NaiveDouble::from(*n as f64)))), _ => Err(()), }, - (DoubleShow, [n, r..]) => match &*n.as_valuef() { + (DoubleShow, [n, r..]) => match &*n.as_whnf() { DoubleLit(n) => Ok(( r, TextLit(vec![InterpolatedTextContents::Text(n.to_string())]), )), _ => Err(()), }, - (TextShow, [v, r..]) => match &*v.as_valuef() { + (TextShow, [v, r..]) => match &*v.as_whnf() { TextLit(elts) => { match elts.as_slice() { // Empty string literal. @@ -158,33 +158,33 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } _ => Err(()), }, - (ListLength, [_, l, r..]) => match &*l.as_valuef() { + (ListLength, [_, l, r..]) => match &*l.as_whnf() { EmptyListLit(_) => Ok((r, NaturalLit(0))), NEListLit(xs) => Ok((r, NaturalLit(xs.len()))), _ => Err(()), }, - (ListHead, [_, l, r..]) => match &*l.as_valuef() { + (ListHead, [_, l, r..]) => match &*l.as_whnf() { EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()))), NEListLit(xs) => { Ok((r, NEOptionalLit(xs.iter().next().unwrap().clone()))) } _ => Err(()), }, - (ListLast, [_, l, r..]) => match &*l.as_valuef() { + (ListLast, [_, l, r..]) => match &*l.as_whnf() { EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()))), NEListLit(xs) => { Ok((r, NEOptionalLit(xs.iter().rev().next().unwrap().clone()))) } _ => Err(()), }, - (ListReverse, [_, l, r..]) => match &*l.as_valuef() { + (ListReverse, [_, l, r..]) => match &*l.as_whnf() { EmptyListLit(n) => Ok((r, EmptyListLit(n.clone()))), NEListLit(xs) => { Ok((r, NEListLit(xs.iter().rev().cloned().collect()))) } _ => Err(()), }, - (ListIndexed, [_, l, r..]) => match &*l.as_valuef() { + (ListIndexed, [_, l, r..]) => match &*l.as_whnf() { EmptyListLit(t) => { let mut kts = HashMap::new(); kts.insert( @@ -210,11 +210,11 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } _ => Err(()), }, - (ListBuild, [t, f, r..]) => match &*f.as_valuef() { + (ListBuild, [t, f, r..]) => match &*f.as_whnf() { // fold/build fusion ValueF::AppliedBuiltin(ListFold, args) => { if args.len() >= 2 { - Ok((r, args[1].to_valuef())) + Ok((r, args[1].to_whnf())) } else { // Do we really need to handle this case ? unimplemented!() @@ -237,8 +237,8 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { )), )), }, - (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_valuef() { - EmptyListLit(_) => Ok((r, nil.to_valuef())), + (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_whnf() { + EmptyListLit(_) => Ok((r, nil.to_whnf())), NEListLit(xs) => { let mut v = nil.clone(); for x in xs.iter().rev() { @@ -248,15 +248,15 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { .app_value(v) .into_value(); } - Ok((r, v.to_valuef())) + Ok((r, v.to_whnf())) } _ => Err(()), }, - (OptionalBuild, [t, f, r..]) => match &*f.as_valuef() { + (OptionalBuild, [t, f, r..]) => match &*f.as_whnf() { // fold/build fusion ValueF::AppliedBuiltin(OptionalFold, args) => { if args.len() >= 2 { - Ok((r, args[1].to_valuef())) + Ok((r, args[1].to_whnf())) } else { // Do we really need to handle this case ? unimplemented!() @@ -273,18 +273,16 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { )), )), }, - (OptionalFold, [_, v, _, just, nothing, r..]) => { - match &*v.as_valuef() { - EmptyOptionalLit(_) => Ok((r, nothing.to_valuef())), - NEOptionalLit(x) => Ok((r, just.app_value(x.clone()))), - _ => Err(()), - } - } - (NaturalBuild, [f, r..]) => match &*f.as_valuef() { + (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_whnf() { + EmptyOptionalLit(_) => Ok((r, nothing.to_whnf())), + NEOptionalLit(x) => Ok((r, just.app_value(x.clone()))), + _ => Err(()), + }, + (NaturalBuild, [f, r..]) => match &*f.as_whnf() { // fold/build fusion ValueF::AppliedBuiltin(NaturalFold, args) => { if !args.is_empty() { - Ok((r, args[0].to_valuef())) + Ok((r, args[0].to_whnf())) } else { // Do we really need to handle this case ? unimplemented!() @@ -297,8 +295,8 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { .app_valuef(NaturalLit(0)), )), }, - (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_valuef() { - NaturalLit(0) => Ok((r, zero.to_valuef())), + (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_whnf() { + NaturalLit(0) => Ok((r, zero.to_whnf())), NaturalLit(n) => { let fold = ValueF::from_builtin(NaturalFold) .app(NaturalLit(n - 1)) @@ -326,11 +324,11 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { pub(crate) fn apply_any(f: Value, a: Value) -> ValueF { let fallback = |f: Value, a: Value| ValueF::PartialExpr(ExprF::App(f, a)); - let f_borrow = f.as_valuef(); + let f_borrow = f.as_whnf(); match &*f_borrow { ValueF::Lam(x, _, e) => { let val = Typed::from_value_untyped(a); - e.subst_shift(&x.into(), &val).to_valuef() + e.subst_shift(&x.into(), &val).to_whnf() } ValueF::AppliedBuiltin(b, args) => { use std::iter::once; @@ -362,7 +360,7 @@ pub(crate) fn squash_textlit( match contents { Text(s) => crnt_str.push_str(&s), Expr(e) => { - let e_borrow = e.as_valuef(); + let e_borrow = e.as_whnf(); match &*e_borrow { ValueF::TextLit(elts2) => { inner(elts2.iter().cloned(), crnt_str, ret) @@ -520,8 +518,8 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { BoolLit, EmptyListLit, NEListLit, NaturalLit, RecordLit, RecordType, TextLit, }; - let x_borrow = x.as_valuef(); - let y_borrow = y.as_valuef(); + let x_borrow = x.as_whnf(); + let y_borrow = y.as_whnf(); Some(match (o, &*x_borrow, &*y_borrow) { (BoolAnd, BoolLit(true), _) => Ret::ValueRef(y), (BoolAnd, _, BoolLit(true)) => Ret::ValueRef(x), @@ -678,7 +676,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { ExprF::SomeLit(e) => Ret::ValueF(NEOptionalLit(e)), ExprF::EmptyListLit(ref t) => { // Check if the type is of the form `List x` - let t_borrow = t.as_valuef(); + let t_borrow = t.as_whnf(); match &*t_borrow { AppliedBuiltin(Builtin::List, args) if args.len() == 1 => { Ret::ValueF(EmptyListLit( @@ -718,13 +716,13 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { } } ExprF::BoolIf(ref b, ref e1, ref e2) => { - let b_borrow = b.as_valuef(); + let b_borrow = b.as_whnf(); match &*b_borrow { BoolLit(true) => Ret::ValueRef(e1), BoolLit(false) => Ret::ValueRef(e2), _ => { - let e1_borrow = e1.as_valuef(); - let e2_borrow = e2.as_valuef(); + let e1_borrow = e1.as_whnf(); + let e2_borrow = e2.as_whnf(); match (&*e1_borrow, &*e2_borrow) { // Simplify `if b then True else False` (BoolLit(true), BoolLit(false)) => Ret::ValueRef(b), @@ -748,7 +746,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { Ret::ValueF(RecordLit(HashMap::new())) } ExprF::Projection(ref v, ref ls) => { - let v_borrow = v.as_valuef(); + let v_borrow = v.as_whnf(); match &*v_borrow { RecordLit(kvs) => Ret::ValueF(RecordLit( ls.iter() @@ -764,7 +762,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { } } ExprF::Field(ref v, ref l) => { - let v_borrow = v.as_valuef(); + let v_borrow = v.as_whnf(); match &*v_borrow { RecordLit(kvs) => match kvs.get(l) { Some(r) => Ret::Value(r.clone()), @@ -784,8 +782,8 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { } ExprF::Merge(ref handlers, ref variant, _) => { - let handlers_borrow = handlers.as_valuef(); - let variant_borrow = variant.as_valuef(); + let handlers_borrow = handlers.as_whnf(); + let variant_borrow = variant.as_whnf(); match (&*handlers_borrow, &*variant_borrow) { (RecordLit(kvs), UnionConstructor(l, _)) => match kvs.get(l) { Some(h) => Ret::Value(h.clone()), @@ -814,8 +812,8 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { match ret { Ret::ValueF(v) => v, - Ret::Value(th) => th.to_valuef(), - Ret::ValueRef(th) => th.to_valuef(), + Ret::Value(th) => th.as_whnf().clone(), + Ret::ValueRef(th) => th.as_whnf().clone(), Ret::Expr(expr) => ValueF::PartialExpr(expr), } } diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 4154afe..c303ada 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -22,12 +22,7 @@ fn tck_pi_type( let ka = match tx.get_type()?.as_const() { Some(k) => k, - _ => { - return Err(TypeError::new( - ctx, - InvalidInputType(tx.to_normalized()), - )) - } + _ => return Err(TypeError::new(ctx, InvalidInputType(tx))), }; let kb = match te.get_type()?.as_const() { @@ -35,7 +30,7 @@ fn tck_pi_type( _ => { return Err(TypeError::new( &ctx2, - InvalidOutputType(te.get_type()?.to_normalized()), + InvalidOutputType(te.get_type()?.into_owned()), )) } }; @@ -415,18 +410,14 @@ fn type_last_layer( } App(f, a) => { let tf = f.get_type()?; - let (x, tx, tb) = match &tf.to_valuef() { + let (x, tx, tb) = match &*tf.as_whnf() { ValueF::Pi(x, tx, tb) => { (x.clone(), tx.to_type(), tb.to_type()) } _ => return Err(mkerr(NotAFunction(f.clone()))), }; if a.get_type()?.as_ref() != &tx { - return Err(mkerr(TypeMismatch( - f.clone(), - tx.to_normalized(), - a.clone(), - ))); + return Err(mkerr(TypeMismatch(f.clone(), tx, a.clone()))); } Ok(RetTypeOnly(tb.subst_shift(&x.into(), &a))) @@ -434,13 +425,13 @@ fn type_last_layer( Annot(x, t) => { let t = t.to_type(); if &t != x.get_type()?.as_ref() { - return Err(mkerr(AnnotMismatch(x.clone(), t.to_normalized()))); + return Err(mkerr(AnnotMismatch(x.clone(), t))); } Ok(RetTypeOnly(x.get_type()?.into_owned())) } Assert(t) => { - match t.to_valuef() { - ValueF::Equivalence(ref x, ref y) if x == y => {} + match &*t.as_whnf() { + ValueF::Equivalence(x, y) if x == y => {} ValueF::Equivalence(x, y) => { return Err(mkerr(AssertMismatch( x.to_typed(), @@ -472,14 +463,11 @@ fn type_last_layer( } EmptyListLit(t) => { let t = t.to_type(); - match &t.to_valuef() { + match &*t.as_whnf() { ValueF::AppliedBuiltin(dhall_syntax::Builtin::List, args) if args.len() == 1 => {} _ => { - return Err(TypeError::new( - ctx, - InvalidListType(t.to_normalized()), - )) + return Err(TypeError::new(ctx, InvalidListType(t.clone()))) } } Ok(RetTypeOnly(t)) @@ -491,7 +479,7 @@ fn type_last_layer( if x.get_type()? != y.get_type()? { return Err(mkerr(InvalidListElement( i, - x.get_type()?.to_normalized(), + x.get_type()?.into_owned(), y.clone(), ))); } @@ -500,14 +488,14 @@ fn type_last_layer( if t.get_type()?.as_const() != Some(Type) { return Err(TypeError::new( ctx, - InvalidListType(t.to_normalized()), + InvalidListType(t.into_owned()), )); } Ok(RetTypeOnly( Typed::from_value_and_type( ValueF::from_builtin(dhall_syntax::Builtin::List) - .app(t.to_valuef()) + .app_value(t.to_value()) .into_value(), Typed::from_const(Type), ) @@ -517,16 +505,13 @@ fn type_last_layer( SomeLit(x) => { let t = x.get_type()?.into_owned(); if t.get_type()?.as_const() != Some(Type) { - return Err(TypeError::new( - ctx, - InvalidOptionalType(t.to_normalized()), - )); + return Err(TypeError::new(ctx, InvalidOptionalType(t))); } Ok(RetTypeOnly( Typed::from_value_and_type( ValueF::from_builtin(dhall_syntax::Builtin::Optional) - .app(t.to_valuef()) + .app_value(t.to_value()) .into_value(), Typed::from_const(Type).into_type(), ) @@ -551,7 +536,7 @@ fn type_last_layer( .into_type(), )), Field(r, x) => { - match &r.get_type()?.to_valuef() { + match &*r.get_type()?.as_whnf() { ValueF::RecordType(kts) => match kts.get(&x) { Some(tth) => { Ok(RetTypeOnly(tth.to_type())) @@ -561,8 +546,7 @@ fn type_last_layer( }, // TODO: branch here only when r.get_type() is a Const _ => { - let r = r.to_type(); - match &r.to_valuef() { + match &*r.as_whnf() { ValueF::UnionType(kts) => match kts.get(&x) { // Constructor has type T -> < x: T, ... > Some(Some(t)) => { @@ -581,21 +565,21 @@ fn type_last_layer( None => { Err(mkerr(MissingUnionField( x.clone(), - r.to_normalized(), + r.clone(), ))) }, }, _ => { Err(mkerr(NotARecord( x.clone(), - r.to_normalized() + r.clone() ))) }, } } // _ => Err(mkerr(NotARecord( // x, - // r.to_type()?.to_normalized(), + // r.to_type()?, // ))), } } @@ -633,20 +617,22 @@ fn type_last_layer( } // Extract the LHS record type - let kts_x = match l_type.to_valuef() { + let l_type_borrow = l_type.as_whnf(); + let kts_x = match &*l_type_borrow { ValueF::RecordType(kts) => kts, _ => return Err(mkerr(MustCombineRecord(l.clone()))), }; // Extract the RHS record type - let kts_y = match r_type.to_valuef() { + let r_type_borrow = r_type.as_whnf(); + let kts_y = match &*r_type_borrow { ValueF::RecordType(kts) => kts, _ => return Err(mkerr(MustCombineRecord(r.clone()))), }; // Union the two records, prefering // the values found in the RHS. - let kts = merge_maps(&kts_x, &kts_y, |_, r_t| r_t.clone()); + let kts = merge_maps(kts_x, kts_y, |_, r_t| r_t.clone()); // Construct the final record type from the union Ok(RetTypeOnly( @@ -662,8 +648,8 @@ fn type_last_layer( // records of records when merging. fn combine_record_types( ctx: &TypecheckContext, - kts_l: HashMap, - kts_r: HashMap, + kts_l: &HashMap, + kts_r: &HashMap, ) -> Result { use crate::phase::normalize::outer_join; @@ -674,7 +660,7 @@ fn type_last_layer( inner_l: &TypedValue, inner_r: &TypedValue| -> Result { - match (inner_l.to_valuef(), inner_r.to_valuef()) { + match (&*inner_l.as_whnf(), &*inner_r.as_whnf()) { ( ValueF::RecordType(inner_l_kvs), ValueF::RecordType(inner_r_kvs), @@ -690,11 +676,9 @@ fn type_last_layer( let kts: HashMap> = outer_join( |l| Ok(l.to_type()), |r| Ok(r.to_type()), - |k: &Label, l: &TypedValue, r: &TypedValue| { - combine(k, l, r) - }, - &kts_l, - &kts_r, + combine, + kts_l, + kts_r, ); Ok(tck_record_type( @@ -717,13 +701,15 @@ fn type_last_layer( } // Extract the LHS record type - let kts_x = match l_type.to_valuef() { + let l_type_borrow = l_type.as_whnf(); + let kts_x = match &*l_type_borrow { ValueF::RecordType(kts) => kts, _ => return Err(mkerr(MustCombineRecord(l.clone()))), }; // Extract the RHS record type - let kts_y = match r_type.to_valuef() { + let r_type_borrow = r_type.as_whnf(); + let kts_y = match &*r_type_borrow { ValueF::RecordType(kts) => kts, _ => return Err(mkerr(MustCombineRecord(r.clone()))), }; @@ -735,8 +721,8 @@ fn type_last_layer( // records of records when merging. fn combine_record_types( ctx: &TypecheckContext, - kts_l: HashMap, - kts_r: HashMap, + kts_l: &HashMap, + kts_r: &HashMap, ) -> Result { use crate::phase::normalize::intersection_with_key; @@ -747,7 +733,7 @@ fn type_last_layer( kts_l_inner: &TypedValue, kts_r_inner: &TypedValue| -> Result { - match (kts_l_inner.to_valuef(), kts_r_inner.to_valuef()) { + match (&*kts_l_inner.as_whnf(), &*kts_r_inner.as_whnf()) { ( ValueF::RecordType(kvs_l_inner), ValueF::RecordType(kvs_r_inner), @@ -760,13 +746,7 @@ fn type_last_layer( } }; - let kts = intersection_with_key( - |k: &Label, l: &TypedValue, r: &TypedValue| { - combine(k, l, r) - }, - &kts_l, - &kts_r, - ); + let kts = intersection_with_key(combine, kts_l, kts_r); Ok(tck_record_type( ctx, @@ -776,8 +756,8 @@ fn type_last_layer( }; // Extract the Const of the LHS - let k_l = match l.get_type()?.to_valuef() { - ValueF::Const(k) => k, + let k_l = match l.get_type()?.as_const() { + Some(k) => k, _ => { return Err(mkerr(RecordTypeMergeRequiresRecordType( l.clone(), @@ -786,8 +766,8 @@ fn type_last_layer( }; // Extract the Const of the RHS - let k_r = match r.get_type()?.to_valuef() { - ValueF::Const(k) => k, + let k_r = match r.get_type()?.as_const() { + Some(k) => k, _ => { return Err(mkerr(RecordTypeMergeRequiresRecordType( r.clone(), @@ -808,7 +788,8 @@ fn type_last_layer( }; // Extract the LHS record type - let kts_x = match l.to_valuef() { + let borrow_l = l.as_whnf(); + let kts_x = match &*borrow_l { ValueF::RecordType(kts) => kts, _ => { return Err(mkerr(RecordTypeMergeRequiresRecordType( @@ -818,7 +799,8 @@ fn type_last_layer( }; // Extract the RHS record type - let kts_y = match r.to_valuef() { + let borrow_r = r.as_whnf(); + let kts_y = match &*borrow_r { ValueF::RecordType(kts) => kts, _ => { return Err(mkerr(RecordTypeMergeRequiresRecordType( @@ -833,7 +815,7 @@ fn type_last_layer( .and(Ok(RetTypeOnly(Typed::from_const(k)))) } BinOp(o @ ListAppend, l, r) => { - match l.get_type()?.to_valuef() { + match &*l.get_type()?.as_whnf() { ValueF::AppliedBuiltin(List, _) => {} _ => return Err(mkerr(BinOpTypeMismatch(*o, l.clone()))), } @@ -895,56 +877,63 @@ fn type_last_layer( Ok(RetTypeOnly(t)) } Merge(record, union, type_annot) => { - let handlers = match record.get_type()?.to_valuef() { + let record_type = record.get_type()?; + let record_borrow = record_type.as_whnf(); + let handlers = match &*record_borrow { ValueF::RecordType(kts) => kts, _ => return Err(mkerr(Merge1ArgMustBeRecord(record.clone()))), }; - let variants = match union.get_type()?.to_valuef() { + let union_type = union.get_type()?; + let union_borrow = union_type.as_whnf(); + let variants = match &*union_borrow { ValueF::UnionType(kts) => kts, _ => return Err(mkerr(Merge2ArgMustBeUnion(union.clone()))), }; let mut inferred_type = None; - for (x, handler) in handlers.iter() { - let handler_return_type = match variants.get(x) { - // Union alternative with type - Some(Some(variant_type)) => { - let variant_type = variant_type.to_type(); - let handler_type = handler.to_type(); - let (x, tx, tb) = match &handler_type.to_valuef() { - ValueF::Pi(x, tx, tb) => { - (x.clone(), tx.to_type(), tb.to_type()) + for (x, handler) in handlers { + let handler_return_type = + match variants.get(x) { + // Union alternative with type + Some(Some(variant_type)) => { + let variant_type = variant_type.to_type(); + let handler_type = handler.to_type(); + let (x, tx, tb) = match &*handler_type.as_whnf() { + ValueF::Pi(x, tx, tb) => { + (x.clone(), tx.to_type(), tb.to_type()) + } + _ => { + return Err(mkerr(NotAFunction( + handler_type.clone(), + ))) + } + }; + + if &variant_type != &tx { + return Err(mkerr(TypeMismatch( + handler_type, + tx, + variant_type, + ))); } - _ => return Err(mkerr(NotAFunction(handler_type))), - }; - - if &variant_type != &tx { - return Err(mkerr(TypeMismatch( - handler_type, - tx.to_normalized(), - variant_type, - ))); - } - // Extract `tb` from under the `x` binder. Fails is `x` was free in `tb`. - match tb.over_binder(x) { - Some(x) => x, - None => { - return Err(mkerr( + // Extract `tb` from under the `x` binder. Fails is `x` was free in `tb`. + match tb.over_binder(x) { + Some(x) => x, + None => return Err(mkerr( MergeHandlerReturnTypeMustNotBeDependent, - )) + )), } } - } - // Union alternative without type - Some(None) => handler.to_type(), - None => { - return Err(mkerr(MergeHandlerMissingVariant( - x.clone(), - ))) - } - }; + // Union alternative without type + Some(None) => handler.to_type(), + None => { + return Err(mkerr(MergeHandlerMissingVariant( + x.clone(), + ))) + } + }; match &inferred_type { None => inferred_type = Some(handler_return_type), Some(t) => { @@ -974,8 +963,9 @@ fn type_last_layer( } } Projection(record, labels) => { - let trecord = record.get_type()?; - let kts = match trecord.to_valuef() { + let record_type = record.get_type()?; + let record_borrow = record_type.as_whnf(); + let kts = match &*record_borrow { ValueF::RecordType(kts) => kts, _ => return Err(mkerr(ProjectionMustBeRecord)), }; @@ -991,7 +981,7 @@ fn type_last_layer( Ok(RetTypeOnly( Typed::from_value_and_type( ValueF::RecordType(new_kts).into_value(), - trecord.get_type()?.into_owned(), + record_type.get_type()?.into_owned(), ) .to_type(), )) -- cgit v1.2.3 From 26a1fd0f0861038a76a0f9b09eaef16d808d4139 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 19 Aug 2019 21:52:26 +0200 Subject: Use TypedValue instead of Typed in normalize and typecheck Now Typed is only used in dhall::phase, similarly to Parsed/Resolved/Normalized --- dhall/src/phase/mod.rs | 51 ++---- dhall/src/phase/normalize.rs | 6 +- dhall/src/phase/typecheck.rs | 392 +++++++++++++++++++------------------------ 3 files changed, 187 insertions(+), 262 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index a38e9d3..e58e689 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -1,5 +1,4 @@ use std::borrow::Cow; -use std::cell::Ref; use std::fmt::Display; use std::path::Path; @@ -42,8 +41,6 @@ pub struct Typed(TypedValue); #[derive(Debug, Clone)] pub struct Normalized(Typed); -pub type Type = Typed; - impl Parsed { pub fn parse_file(f: &Path) -> Result { parse::parse_file(f) @@ -72,10 +69,10 @@ impl Parsed { impl Resolved { pub fn typecheck(self) -> Result { - typecheck::typecheck(self) + Ok(typecheck::typecheck(self.0)?.into_typed()) } - pub fn typecheck_with(self, ty: &Type) -> Result { - typecheck::typecheck_with(self, ty) + pub fn typecheck_with(self, ty: &Typed) -> Result { + Ok(typecheck::typecheck_with(self.0, ty.to_expr())?.into_typed()) } } @@ -93,17 +90,11 @@ impl Typed { Normalized(self) } - pub(crate) fn from_value_and_type(th: Value, t: Type) -> Self { - Typed(TypedValue::from_value_and_type(th, t)) - } - pub(crate) fn from_value_untyped(th: Value) -> Self { - Typed(TypedValue::from_value_untyped(th)) - } pub(crate) fn from_const(c: Const) -> Self { Typed(TypedValue::from_const(c)) } - pub fn from_valuef_and_type(v: ValueF, t: Type) -> Self { - Typed(TypedValue::from_valuef_and_type(v, t)) + pub fn from_valuef_and_type(v: ValueF, t: Typed) -> Self { + Typed(TypedValue::from_valuef_and_type(v, t.into_typedvalue())) } pub(crate) fn from_typedvalue(th: TypedValue) -> Self { Typed(th) @@ -112,14 +103,6 @@ impl Typed { Typed::from_const(Const::Type) } - /// WARNING: drop this ref before normalizing the same value or you will run into BorrowMut - /// panics. - pub(crate) fn as_whnf(&self) -> Ref { - self.0.as_whnf() - } - pub(crate) fn to_whnf(&self) -> ValueF { - self.0.to_whnf() - } pub fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() } @@ -129,27 +112,17 @@ impl Typed { pub fn to_value(&self) -> Value { self.0.to_value() } - // Deprecated - pub fn to_type(&self) -> Type { - self.clone() - } - // Deprecated - pub(crate) fn into_type(self) -> Type { - self - } pub(crate) fn into_typedvalue(self) -> TypedValue { self.0 } - pub(crate) fn as_const(&self) -> Option { - self.0.as_const() - } pub(crate) fn normalize_mut(&mut self) { self.0.normalize_mut() } - pub(crate) fn get_type(&self) -> Result, TypeError> { - self.0.get_type() + #[allow(dead_code)] + pub(crate) fn get_type(&self) -> Result, TypeError> { + Ok(Cow::Owned(self.0.get_type()?.into_owned().into_typed())) } } @@ -165,10 +138,6 @@ impl Normalized { pub(crate) fn to_expr_alpha(&self) -> NormalizedSubExpr { self.0.to_expr_alpha() } - #[allow(dead_code)] - pub(crate) fn to_type(&self) -> Type { - self.0.to_type() - } pub(crate) fn into_typed(self) -> Typed { self.0 } @@ -186,8 +155,8 @@ impl Shift for Normalized { } } -impl Subst for Typed { - fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self { +impl Subst for Typed { + fn subst_shift(&self, var: &AlphaVar, val: &TypedValue) -> Self { Typed(self.0.subst_shift(var, val)) } } diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 785a75f..dabfe87 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -8,7 +8,7 @@ use dhall_syntax::{ use crate::core::value::{TypedValue, Value}; use crate::core::valuef::ValueF; use crate::core::var::{Shift, Subst}; -use crate::phase::{Normalized, NormalizedSubExpr, Typed}; +use crate::phase::{Normalized, NormalizedSubExpr}; pub(crate) type OutputSubExpr = NormalizedSubExpr; @@ -327,7 +327,7 @@ pub(crate) fn apply_any(f: Value, a: Value) -> ValueF { let f_borrow = f.as_whnf(); match &*f_borrow { ValueF::Lam(x, _, e) => { - let val = Typed::from_value_untyped(a); + let val = TypedValue::from_value_untyped(a); e.subst_shift(&x.into(), &val).to_whnf() } ValueF::AppliedBuiltin(b, args) => { @@ -663,7 +663,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { TypedValue::from_value_untyped(e), )), ExprF::Let(x, _, v, b) => { - let v = Typed::from_value_untyped(v); + let v = TypedValue::from_value_untyped(v); Ret::Value(b.subst_shift(&x.into(), &v)) } ExprF::App(v, a) => Ret::ValueF(v.app_value(a)), diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index c303ada..07c4ad8 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -9,14 +9,14 @@ use crate::core::value::{TypedValue, Value}; use crate::core::valuef::ValueF; use crate::core::var::{Shift, Subst}; use crate::error::{TypeError, TypeMessage}; -use crate::phase::{Normalized, Resolved, Type, Typed}; +use crate::phase::Normalized; fn tck_pi_type( ctx: &TypecheckContext, x: Label, - tx: Type, - te: Type, -) -> Result { + tx: TypedValue, + te: TypedValue, +) -> Result { use crate::error::TypeMessage::*; let ctx2 = ctx.insert_type(&x, tx.clone()); @@ -37,21 +37,16 @@ fn tck_pi_type( let k = function_check(ka, kb); - Ok(Typed::from_value_and_type( - ValueF::Pi( - x.into(), - TypedValue::from_type(tx), - TypedValue::from_type(te), - ) - .into_value(), - Type::from_const(k), + Ok(TypedValue::from_value_and_type( + ValueF::Pi(x.into(), tx, te).into_value(), + TypedValue::from_const(k), )) } fn tck_record_type( ctx: &TypecheckContext, - kts: impl IntoIterator>, -) -> Result { + kts: impl IntoIterator>, +) -> Result { use crate::error::TypeMessage::*; use std::collections::hash_map::Entry; let mut new_kts = HashMap::new(); @@ -62,36 +57,32 @@ fn tck_record_type( match (k, t.get_type()?.as_const()) { (None, Some(k2)) => k = Some(k2), (Some(k1), Some(k2)) if k1 == k2 => {} - _ => { - return Err(TypeError::new( - ctx, - InvalidFieldType(x.clone(), t.clone()), - )) - } + _ => return Err(TypeError::new(ctx, InvalidFieldType(x, t))), } - let entry = new_kts.entry(x.clone()); + let entry = new_kts.entry(x); match &entry { Entry::Occupied(_) => { return Err(TypeError::new(ctx, RecordTypeDuplicateField)) } - Entry::Vacant(_) => { - entry.or_insert_with(|| TypedValue::from_type(t.clone())) - } + Entry::Vacant(_) => entry.or_insert_with(|| t), }; } // An empty record type has type Type - let k = k.unwrap_or(dhall_syntax::Const::Type); + let k = k.unwrap_or(Const::Type); - Ok(Typed::from_value_and_type( + Ok(TypedValue::from_value_and_type( ValueF::RecordType(new_kts).into_value(), - Type::from_const(k), + TypedValue::from_const(k), )) } -fn tck_union_type( +fn tck_union_type( ctx: &TypecheckContext, - kts: impl IntoIterator), TypeError>>, -) -> Result { + kts: Iter, +) -> Result +where + Iter: IntoIterator), TypeError>>, +{ use crate::error::TypeMessage::*; use std::collections::hash_map::Entry; let mut new_kts = HashMap::new(); @@ -106,46 +97,43 @@ fn tck_union_type( _ => { return Err(TypeError::new( ctx, - InvalidFieldType(x.clone(), t.clone()), + InvalidFieldType(x, t.clone()), )) } } } - let entry = new_kts.entry(x.clone()); + let entry = new_kts.entry(x); match &entry { Entry::Occupied(_) => { return Err(TypeError::new(ctx, UnionTypeDuplicateField)) } - Entry::Vacant(_) => entry.or_insert_with(|| { - t.as_ref().map(|t| TypedValue::from_type(t.clone())) - }), + Entry::Vacant(_) => entry.or_insert_with(|| t), }; } // An empty union type has type Type; // an union type with only unary variants also has type Type - let k = k.unwrap_or(dhall_syntax::Const::Type); + let k = k.unwrap_or(Const::Type); - Ok(Typed::from_value_and_type( + Ok(TypedValue::from_value_and_type( ValueF::UnionType(new_kts).into_value(), - Type::from_const(k), + TypedValue::from_const(k), )) } fn function_check(a: Const, b: Const) -> Const { - use dhall_syntax::Const::Type; use std::cmp::max; - if b == Type { - Type + if b == Const::Type { + Const::Type } else { max(a, b) } } -pub(crate) fn type_of_const(c: Const) -> Result { +pub(crate) fn type_of_const(c: Const) -> Result { match c { - Const::Type => Ok(Type::from_const(Const::Kind)), - Const::Kind => Ok(Type::from_const(Const::Sort)), + Const::Type => Ok(TypedValue::from_const(Const::Kind)), + Const::Kind => Ok(TypedValue::from_const(Const::Sort)), Const::Sort => { Err(TypeError::new(&TypecheckContext::new(), TypeMessage::Sort)) } @@ -293,25 +281,16 @@ fn type_of_builtin(b: Builtin) -> Expr { } } -/// Takes an expression that is meant to contain a Type -/// and turn it into a type, typechecking it along the way. -pub(crate) fn mktype( - ctx: &TypecheckContext, - e: SubExpr, -) -> Result { - Ok(type_with(ctx, e)?.to_type()) -} - -pub(crate) fn builtin_to_type(b: Builtin) -> Result { - mktype(&TypecheckContext::new(), SubExpr::from_builtin(b)) +pub(crate) fn builtin_to_type(b: Builtin) -> Result { + type_with(&TypecheckContext::new(), SubExpr::from_builtin(b)) } /// Intermediary return type enum Ret { /// Returns the contained value as is - RetWhole(Typed), - /// Use the contained Type as the type of the input expression - RetTypeOnly(Type), + RetWhole(TypedValue), + /// Use the contained TypedValue as the type of the input expression + RetTypeOnly(TypedValue), } /// Type-check an expression and return the expression alongside its type if type-checking @@ -321,28 +300,24 @@ enum Ret { fn type_with( ctx: &TypecheckContext, e: SubExpr, -) -> Result { +) -> Result { use dhall_syntax::ExprF::{Annot, Embed, Lam, Let, Pi, Var}; use Ret::*; Ok(match e.as_ref() { Lam(x, t, b) => { - let tx = mktype(ctx, t.clone())?; + let tx = type_with(ctx, t.clone())?; let ctx2 = ctx.insert_type(x, tx.clone()); let b = type_with(&ctx2, b.clone())?; - let v = ValueF::Lam( - x.clone().into(), - TypedValue::from_type(tx.clone()), - b.to_value(), - ); + let v = ValueF::Lam(x.clone().into(), tx.clone(), b.to_value()); let tb = b.get_type()?.into_owned(); - let t = tck_pi_type(ctx, x.clone(), tx, tb)?.to_type(); - Typed::from_value_and_type(Value::from_valuef(v), t) + let t = tck_pi_type(ctx, x.clone(), tx, tb)?; + TypedValue::from_valuef_and_type(v, t) } Pi(x, ta, tb) => { - let ta = mktype(ctx, ta.clone())?; + let ta = type_with(ctx, ta.clone())?; let ctx2 = ctx.insert_type(x, ta.clone()); - let tb = mktype(&ctx2, tb.clone())?; + let tb = type_with(&ctx2, tb.clone())?; return tck_pi_type(ctx, x.clone(), ta, tb); } Let(x, t, v, e) => { @@ -355,9 +330,9 @@ fn type_with( let v = type_with(ctx, v)?; return type_with(&ctx.insert_value(x, v.clone())?, e.clone()); } - Embed(p) => p.clone().into_typed(), + Embed(p) => p.clone().into_typed().into_typedvalue(), Var(var) => match ctx.lookup(&var) { - Some(typed) => typed, + Some(typed) => typed.clone(), None => { return Err(TypeError::new( ctx, @@ -376,7 +351,7 @@ fn type_with( match ret { RetTypeOnly(typ) => { let expr = expr.map_ref(|typed| typed.to_value()); - Typed::from_value_and_type( + TypedValue::from_value_and_type( Value::from_partial_expr(expr), typ, ) @@ -391,7 +366,7 @@ fn type_with( /// layer. fn type_last_layer( ctx: &TypecheckContext, - e: &ExprF, + e: &ExprF, ) -> Result { use crate::error::TypeMessage::*; use dhall_syntax::BinOp::*; @@ -410,22 +385,24 @@ fn type_last_layer( } App(f, a) => { let tf = f.get_type()?; - let (x, tx, tb) = match &*tf.as_whnf() { - ValueF::Pi(x, tx, tb) => { - (x.clone(), tx.to_type(), tb.to_type()) - } + let tf_borrow = tf.as_whnf(); + let (x, tx, tb) = match &*tf_borrow { + ValueF::Pi(x, tx, tb) => (x, tx, tb), _ => return Err(mkerr(NotAFunction(f.clone()))), }; - if a.get_type()?.as_ref() != &tx { - return Err(mkerr(TypeMismatch(f.clone(), tx, a.clone()))); + if a.get_type()?.as_ref() != tx { + return Err(mkerr(TypeMismatch( + f.clone(), + tx.clone(), + a.clone(), + ))); } - Ok(RetTypeOnly(tb.subst_shift(&x.into(), &a))) + Ok(RetTypeOnly(tb.subst_shift(&x.into(), a))) } Annot(x, t) => { - let t = t.to_type(); - if &t != x.get_type()?.as_ref() { - return Err(mkerr(AnnotMismatch(x.clone(), t))); + if t != x.get_type()?.as_ref() { + return Err(mkerr(AnnotMismatch(x.clone(), t.clone()))); } Ok(RetTypeOnly(x.get_type()?.into_owned())) } @@ -433,14 +410,11 @@ fn type_last_layer( match &*t.as_whnf() { ValueF::Equivalence(x, y) if x == y => {} ValueF::Equivalence(x, y) => { - return Err(mkerr(AssertMismatch( - x.to_typed(), - y.to_typed(), - ))) + return Err(mkerr(AssertMismatch(x.clone(), y.clone()))) } _ => return Err(mkerr(AssertMustTakeEquivalence)), } - Ok(RetTypeOnly(t.to_type())) + Ok(RetTypeOnly(t.clone())) } BoolIf(x, y, z) => { if x.get_type()?.as_ref() != &builtin_to_type(Bool)? { @@ -462,7 +436,6 @@ fn type_last_layer( Ok(RetTypeOnly(y.get_type()?.into_owned())) } EmptyListLit(t) => { - let t = t.to_type(); match &*t.as_whnf() { ValueF::AppliedBuiltin(dhall_syntax::Builtin::List, args) if args.len() == 1 => {} @@ -470,7 +443,7 @@ fn type_last_layer( return Err(TypeError::new(ctx, InvalidListType(t.clone()))) } } - Ok(RetTypeOnly(t)) + Ok(RetTypeOnly(t.clone())) } NEListLit(xs) => { let mut iter = xs.iter().enumerate(); @@ -492,15 +465,12 @@ fn type_last_layer( )); } - Ok(RetTypeOnly( - Typed::from_value_and_type( - ValueF::from_builtin(dhall_syntax::Builtin::List) - .app_value(t.to_value()) - .into_value(), - Typed::from_const(Type), - ) - .to_type(), - )) + Ok(RetTypeOnly(TypedValue::from_value_and_type( + ValueF::from_builtin(dhall_syntax::Builtin::List) + .app_value(t.to_value()) + .into_value(), + TypedValue::from_const(Type), + ))) } SomeLit(x) => { let t = x.get_type()?.into_owned(); @@ -508,38 +478,31 @@ fn type_last_layer( return Err(TypeError::new(ctx, InvalidOptionalType(t))); } - Ok(RetTypeOnly( - Typed::from_value_and_type( - ValueF::from_builtin(dhall_syntax::Builtin::Optional) - .app_value(t.to_value()) - .into_value(), - Typed::from_const(Type).into_type(), - ) - .to_type(), - )) + Ok(RetTypeOnly(TypedValue::from_value_and_type( + ValueF::from_builtin(dhall_syntax::Builtin::Optional) + .app_value(t.to_value()) + .into_value(), + TypedValue::from_const(Type), + ))) } RecordType(kts) => Ok(RetWhole(tck_record_type( ctx, - kts.iter().map(|(x, t)| Ok((x.clone(), t.to_type()))), + kts.iter().map(|(x, t)| Ok((x.clone(), t.clone()))), )?)), UnionType(kts) => Ok(RetWhole(tck_union_type( ctx, - kts.iter() - .map(|(x, t)| Ok((x.clone(), t.as_ref().map(|t| t.to_type())))), + kts.iter().map(|(x, t)| Ok((x.clone(), t.clone()))), + )?)), + RecordLit(kvs) => Ok(RetTypeOnly(tck_record_type( + ctx, + kvs.iter() + .map(|(x, v)| Ok((x.clone(), v.get_type()?.into_owned()))), )?)), - RecordLit(kvs) => Ok(RetTypeOnly( - tck_record_type( - ctx, - kvs.iter() - .map(|(x, v)| Ok((x.clone(), v.get_type()?.into_owned()))), - )? - .into_type(), - )), Field(r, x) => { match &*r.get_type()?.as_whnf() { ValueF::RecordType(kts) => match kts.get(&x) { Some(tth) => { - Ok(RetTypeOnly(tth.to_type())) + Ok(RetTypeOnly(tth.clone())) }, None => Err(mkerr(MissingRecordField(x.clone(), r.clone()))), @@ -554,9 +517,9 @@ fn type_last_layer( tck_pi_type( ctx, "_".into(), - t.to_type(), + t.clone(), r.under_binder(Label::from("_")), - )?.to_type() + )? )) }, Some(None) => { @@ -579,12 +542,12 @@ fn type_last_layer( } // _ => Err(mkerr(NotARecord( // x, - // r.to_type()?, + // r?, // ))), } } - Const(c) => Ok(RetWhole(Typed::from_const(*c))), - Builtin(b) => Ok(RetTypeOnly(mktype(ctx, rc(type_of_builtin(*b)))?)), + Const(c) => Ok(RetWhole(TypedValue::from_const(*c))), + Builtin(b) => Ok(RetTypeOnly(type_with(ctx, rc(type_of_builtin(*b)))?)), BoolLit(_) => Ok(RetTypeOnly(builtin_to_type(Bool)?)), NaturalLit(_) => Ok(RetTypeOnly(builtin_to_type(Natural)?)), IntegerLit(_) => Ok(RetTypeOnly(builtin_to_type(Integer)?)), @@ -635,13 +598,10 @@ fn type_last_layer( let kts = merge_maps(kts_x, kts_y, |_, r_t| r_t.clone()); // Construct the final record type from the union - Ok(RetTypeOnly( - tck_record_type( - ctx, - kts.iter().map(|(x, v)| Ok((x.clone(), v.to_type()))), - )? - .into_type(), - )) + Ok(RetTypeOnly(tck_record_type( + ctx, + kts.into_iter().map(|(x, v)| Ok((x.clone(), v))), + )?)) } BinOp(RecursiveRecordMerge, l, r) => { // A recursive function to dig down into @@ -650,42 +610,46 @@ fn type_last_layer( ctx: &TypecheckContext, kts_l: &HashMap, kts_r: &HashMap, - ) -> Result { + ) -> Result { use crate::phase::normalize::outer_join; - // If the Label exists for both records and Type for the values + // If the Label exists for both records and the values // are records themselves, then we hit the recursive case. // Otherwise we have a field collision. - let combine = |k: &Label, - inner_l: &TypedValue, - inner_r: &TypedValue| - -> Result { - match (&*inner_l.as_whnf(), &*inner_r.as_whnf()) { - ( - ValueF::RecordType(inner_l_kvs), - ValueF::RecordType(inner_r_kvs), - ) => { - combine_record_types(ctx, inner_l_kvs, inner_r_kvs) + let combine = + |k: &Label, + inner_l: &TypedValue, + inner_r: &TypedValue| + -> Result { + match (&*inner_l.as_whnf(), &*inner_r.as_whnf()) { + ( + ValueF::RecordType(inner_l_kvs), + ValueF::RecordType(inner_r_kvs), + ) => combine_record_types( + ctx, + inner_l_kvs, + inner_r_kvs, + ), + (_, _) => Err(TypeError::new( + ctx, + FieldCollision(k.clone()), + )), } - (_, _) => { - Err(TypeError::new(ctx, FieldCollision(k.clone()))) - } - } - }; + }; - let kts: HashMap> = outer_join( - |l| Ok(l.to_type()), - |r| Ok(r.to_type()), - combine, - kts_l, - kts_r, - ); + let kts: HashMap> = + outer_join( + |l| Ok(l.clone()), + |r| Ok(r.clone()), + combine, + kts_l, + kts_r, + ); Ok(tck_record_type( ctx, kts.into_iter().map(|(x, v)| v.map(|r| (x.clone(), r))), - )? - .into_type()) + )?) }; let l_type = l.get_type()?; @@ -723,36 +687,40 @@ fn type_last_layer( ctx: &TypecheckContext, kts_l: &HashMap, kts_r: &HashMap, - ) -> Result { + ) -> Result { use crate::phase::normalize::intersection_with_key; - // If the Label exists for both records and Type for the values + // If the Label exists for both records and the values // are records themselves, then we hit the recursive case. // Otherwise we have a field collision. - let combine = |k: &Label, - kts_l_inner: &TypedValue, - kts_r_inner: &TypedValue| - -> Result { - match (&*kts_l_inner.as_whnf(), &*kts_r_inner.as_whnf()) { - ( - ValueF::RecordType(kvs_l_inner), - ValueF::RecordType(kvs_r_inner), - ) => { - combine_record_types(ctx, kvs_l_inner, kvs_r_inner) + let combine = + |k: &Label, + kts_l_inner: &TypedValue, + kts_r_inner: &TypedValue| + -> Result { + match (&*kts_l_inner.as_whnf(), &*kts_r_inner.as_whnf()) + { + ( + ValueF::RecordType(kvs_l_inner), + ValueF::RecordType(kvs_r_inner), + ) => combine_record_types( + ctx, + kvs_l_inner, + kvs_r_inner, + ), + (_, _) => Err(TypeError::new( + ctx, + FieldCollision(k.clone()), + )), } - (_, _) => { - Err(TypeError::new(ctx, FieldCollision(k.clone()))) - } - } - }; + }; let kts = intersection_with_key(combine, kts_l, kts_r); Ok(tck_record_type( ctx, kts.into_iter().map(|(x, v)| v.map(|r| (x.clone(), r))), - )? - .into_type()) + )?) }; // Extract the Const of the LHS @@ -780,8 +748,8 @@ fn type_last_layer( k_l } else { return Err(mkerr(RecordTypeMismatch( - Typed::from_const(k_l), - Typed::from_const(k_r), + TypedValue::from_const(k_l), + TypedValue::from_const(k_r), l.clone(), r.clone(), ))); @@ -812,7 +780,7 @@ fn type_last_layer( // Ensure that the records combine without a type error // and if not output the final Const value. combine_record_types(ctx, kts_x, kts_y) - .and(Ok(RetTypeOnly(Typed::from_const(k)))) + .and(Ok(RetTypeOnly(TypedValue::from_const(k)))) } BinOp(o @ ListAppend, l, r) => { match &*l.get_type()?.as_whnf() { @@ -847,7 +815,7 @@ fn type_last_layer( ))); } - Ok(RetTypeOnly(Typed::from_const(Type).into_type())) + Ok(RetTypeOnly(TypedValue::from_const(Type))) } BinOp(o, l, r) => { let t = builtin_to_type(match o { @@ -892,17 +860,14 @@ fn type_last_layer( }; let mut inferred_type = None; - for (x, handler) in handlers { + for (x, handler_type) in handlers { let handler_return_type = match variants.get(x) { // Union alternative with type Some(Some(variant_type)) => { - let variant_type = variant_type.to_type(); - let handler_type = handler.to_type(); - let (x, tx, tb) = match &*handler_type.as_whnf() { - ValueF::Pi(x, tx, tb) => { - (x.clone(), tx.to_type(), tb.to_type()) - } + let handler_type_borrow = handler_type.as_whnf(); + let (x, tx, tb) = match &*handler_type_borrow { + ValueF::Pi(x, tx, tb) => (x, tx, tb), _ => { return Err(mkerr(NotAFunction( handler_type.clone(), @@ -910,11 +875,11 @@ fn type_last_layer( } }; - if &variant_type != &tx { + if variant_type != tx { return Err(mkerr(TypeMismatch( - handler_type, - tx, - variant_type, + handler_type.clone(), + tx.clone(), + variant_type.clone(), ))); } @@ -927,7 +892,7 @@ fn type_last_layer( } } // Union alternative without type - Some(None) => handler.to_type(), + Some(None) => handler_type.clone(), None => { return Err(mkerr(MergeHandlerMissingVariant( x.clone(), @@ -951,14 +916,13 @@ fn type_last_layer( match (inferred_type, type_annot) { (Some(ref t1), Some(t2)) => { - let t2 = t2.to_type(); - if t1 != &t2 { + if t1 != t2 { return Err(mkerr(MergeAnnotMismatch)); } - Ok(RetTypeOnly(t2)) + Ok(RetTypeOnly(t2.clone())) } (Some(t), None) => Ok(RetTypeOnly(t)), - (None, Some(t)) => Ok(RetTypeOnly(t.to_type())), + (None, Some(t)) => Ok(RetTypeOnly(t.clone())), (None, None) => Err(mkerr(MergeEmptyNeedsAnnotation)), } } @@ -978,34 +942,26 @@ fn type_last_layer( }; } - Ok(RetTypeOnly( - Typed::from_value_and_type( - ValueF::RecordType(new_kts).into_value(), - record_type.get_type()?.into_owned(), - ) - .to_type(), - )) + Ok(RetTypeOnly(TypedValue::from_value_and_type( + ValueF::RecordType(new_kts).into_value(), + record_type.get_type()?.into_owned(), + ))) } } } -/// `typeOf` is the same as `type_with` with an empty context, meaning that the +/// `type_of` is the same as `type_with` with an empty context, meaning that the /// expression must be closed (i.e. no free variables), otherwise type-checking /// will fail. -fn type_of(e: SubExpr) -> Result { - let ctx = TypecheckContext::new(); - type_with(&ctx, e) -} - -pub(crate) fn typecheck(e: Resolved) -> Result { - type_of(e.0) +pub(crate) fn typecheck( + e: SubExpr, +) -> Result { + type_with(&TypecheckContext::new(), e) } pub(crate) fn typecheck_with( - e: Resolved, - ty: &Type, -) -> Result { - let expr: SubExpr<_> = e.0; - let ty: SubExpr<_> = ty.to_expr(); - type_of(expr.rewrap(ExprF::Annot(expr.clone(), ty))) + expr: SubExpr, + ty: SubExpr, +) -> Result { + typecheck(expr.rewrap(ExprF::Annot(expr.clone(), ty))) } -- cgit v1.2.3 From 07a276c1d6ee892b93abbd7a73c78c96d56f4fe7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 19 Aug 2019 22:26:17 +0200 Subject: Reduce untyped construction of Values --- dhall/src/phase/normalize.rs | 72 ++++++++++++++++++++++++++++---------------- dhall/src/phase/typecheck.rs | 33 ++++++++++---------- 2 files changed, 62 insertions(+), 43 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index dabfe87..27858d8 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -20,7 +20,7 @@ macro_rules! make_closure { Label::from(stringify!($var)).into(), $n ); - ValueF::Var(var).into_value() + ValueF::Var(var).into_value_untyped() }}; // Warning: assumes that $ty, as a dhall value, has type `Type` (λ($var:ident : $($ty:tt)*) -> $($rest:tt)*) => { @@ -30,30 +30,40 @@ macro_rules! make_closure { make_closure!($($ty)*), ), make_closure!($($rest)*), - ).into_value() + ).into_value_untyped() + }; + (Natural) => { + ValueF::from_builtin(Builtin::Natural) + .into_value_simple_type() }; - (Natural) => { ValueF::from_builtin(Builtin::Natural).into_value() }; (List $($rest:tt)*) => { ValueF::from_builtin(Builtin::List) .app_value(make_closure!($($rest)*)) - .into_value() + .into_value_simple_type() }; - (Some $($rest:tt)*) => { - ValueF::NEOptionalLit(make_closure!($($rest)*)).into_value() + (Some($($rest:tt)*)) => { + ValueF::NEOptionalLit(make_closure!($($rest)*)) + .into_value_untyped() }; (1 + $($rest:tt)*) => { ValueF::PartialExpr(ExprF::BinOp( dhall_syntax::BinOp::NaturalPlus, make_closure!($($rest)*), - Value::from_valuef(ValueF::NaturalLit(1)), - )).into_value() + Value::from_valuef_and_type( + ValueF::NaturalLit(1), + TypedValue::from_value(make_closure!(Natural)) + ), + )).into_value_with_type( + TypedValue::from_value(make_closure!(Natural)) + ) }; ([ $($head:tt)* ] # $($tail:tt)*) => { ValueF::PartialExpr(ExprF::BinOp( dhall_syntax::BinOp::ListAppend, - ValueF::NEListLit(vec![make_closure!($($head)*)]).into_value(), + ValueF::NEListLit(vec![make_closure!($($head)*)]) + .into_value_untyped(), make_closure!($($tail)*), - )).into_value() + )).into_value_untyped() }; } @@ -189,10 +199,17 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { let mut kts = HashMap::new(); kts.insert( "index".into(), - TypedValue::from_valuef(ValueF::from_builtin(Natural)), + TypedValue::from_valuef_untyped(ValueF::from_builtin( + Natural, + )), ); kts.insert("value".into(), t.clone()); - Ok((r, EmptyListLit(TypedValue::from_valuef(RecordType(kts))))) + Ok(( + r, + EmptyListLit(TypedValue::from_valuef_untyped(RecordType( + kts, + ))), + )) } NEListLit(xs) => { let xs = xs @@ -201,9 +218,12 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { .map(|(i, e)| { let i = NaturalLit(i); let mut kvs = HashMap::new(); - kvs.insert("index".into(), Value::from_valuef(i)); + kvs.insert( + "index".into(), + Value::from_valuef_untyped(i), + ); kvs.insert("value".into(), e.clone()); - Value::from_valuef(RecordLit(kvs)) + Value::from_valuef_untyped(RecordLit(kvs)) }) .collect(); Ok((r, NEListLit(xs))) @@ -246,7 +266,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { .clone() .app_value(x.clone()) .app_value(v) - .into_value(); + .into_value_untyped(); } Ok((r, v.to_whnf())) } @@ -267,7 +287,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { f.app_valuef( ValueF::from_builtin(Optional).app_value(t.clone()), ) - .app_value(make_closure!(λ(x: #t) -> Some var(x, 0))) + .app_value(make_closure!(λ(x: #t) -> Some(var(x, 0)))) .app_valuef(EmptyOptionalLit( TypedValue::from_value_simple_type(t.clone()), )), @@ -327,7 +347,7 @@ pub(crate) fn apply_any(f: Value, a: Value) -> ValueF { let f_borrow = f.as_whnf(); match &*f_borrow { ValueF::Lam(x, _, e) => { - let val = TypedValue::from_value_untyped(a); + let val = TypedValue::from_value(a); e.subst_shift(&x.into(), &val).to_whnf() } ValueF::AppliedBuiltin(b, args) => { @@ -602,11 +622,11 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { } (RecursiveRecordMerge, RecordLit(kvs1), RecordLit(kvs2)) => { let kvs = merge_maps(kvs1, kvs2, |v1, v2| { - Value::from_partial_expr(ExprF::BinOp( + Value::from_valuef_untyped(ValueF::PartialExpr(ExprF::BinOp( RecursiveRecordMerge, v1.clone(), v2.clone(), - )) + ))) }); Ret::ValueF(RecordLit(kvs)) } @@ -619,7 +639,7 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { } (RecursiveRecordTypeMerge, RecordType(kvs1), RecordType(kvs2)) => { let kvs = merge_maps(kvs1, kvs2, |v1, v2| { - TypedValue::from_value_untyped(Value::from_partial_expr( + TypedValue::from_valuef_untyped(ValueF::PartialExpr( ExprF::BinOp( RecursiveRecordTypeMerge, v1.to_value(), @@ -655,15 +675,15 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { ExprF::Annot(x, _) => Ret::Value(x), ExprF::Assert(_) => Ret::Expr(expr), ExprF::Lam(x, t, e) => { - Ret::ValueF(Lam(x.into(), TypedValue::from_value_untyped(t), e)) + Ret::ValueF(Lam(x.into(), TypedValue::from_value(t), e)) } ExprF::Pi(x, t, e) => Ret::ValueF(Pi( x.into(), - TypedValue::from_value_untyped(t), - TypedValue::from_value_untyped(e), + TypedValue::from_value(t), + TypedValue::from_value(e), )), ExprF::Let(x, _, v, b) => { - let v = TypedValue::from_value_untyped(v); + let v = TypedValue::from_value(v); Ret::Value(b.subst_shift(&x.into(), &v)) } ExprF::App(v, a) => Ret::ValueF(v.app_value(a)), @@ -697,12 +717,12 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { } ExprF::RecordType(kts) => Ret::ValueF(RecordType( kts.into_iter() - .map(|(k, t)| (k, TypedValue::from_value_untyped(t))) + .map(|(k, t)| (k, TypedValue::from_value(t))) .collect(), )), ExprF::UnionType(kts) => Ret::ValueF(UnionType( kts.into_iter() - .map(|(k, t)| (k, t.map(|t| TypedValue::from_value_untyped(t)))) + .map(|(k, t)| (k, t.map(|t| TypedValue::from_value(t)))) .collect(), )), ExprF::TextLit(elts) => { diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 07c4ad8..e24f5a3 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -5,7 +5,7 @@ use dhall_syntax::{ }; use crate::core::context::TypecheckContext; -use crate::core::value::{TypedValue, Value}; +use crate::core::value::TypedValue; use crate::core::valuef::ValueF; use crate::core::var::{Shift, Subst}; use crate::error::{TypeError, TypeMessage}; @@ -37,8 +37,8 @@ fn tck_pi_type( let k = function_check(ka, kb); - Ok(TypedValue::from_value_and_type( - ValueF::Pi(x.into(), tx, te).into_value(), + Ok(TypedValue::from_valuef_and_type( + ValueF::Pi(x.into(), tx, te), TypedValue::from_const(k), )) } @@ -70,8 +70,8 @@ fn tck_record_type( // An empty record type has type Type let k = k.unwrap_or(Const::Type); - Ok(TypedValue::from_value_and_type( - ValueF::RecordType(new_kts).into_value(), + Ok(TypedValue::from_valuef_and_type( + ValueF::RecordType(new_kts), TypedValue::from_const(k), )) } @@ -115,8 +115,8 @@ where // an union type with only unary variants also has type Type let k = k.unwrap_or(Const::Type); - Ok(TypedValue::from_value_and_type( - ValueF::UnionType(new_kts).into_value(), + Ok(TypedValue::from_valuef_and_type( + ValueF::UnionType(new_kts), TypedValue::from_const(k), )) } @@ -281,6 +281,7 @@ fn type_of_builtin(b: Builtin) -> Expr { } } +// TODO: this can't fail in practise pub(crate) fn builtin_to_type(b: Builtin) -> Result { type_with(&TypecheckContext::new(), SubExpr::from_builtin(b)) } @@ -351,8 +352,8 @@ fn type_with( match ret { RetTypeOnly(typ) => { let expr = expr.map_ref(|typed| typed.to_value()); - TypedValue::from_value_and_type( - Value::from_partial_expr(expr), + TypedValue::from_valuef_and_type( + ValueF::PartialExpr(expr), typ, ) } @@ -465,10 +466,9 @@ fn type_last_layer( )); } - Ok(RetTypeOnly(TypedValue::from_value_and_type( + Ok(RetTypeOnly(TypedValue::from_valuef_and_type( ValueF::from_builtin(dhall_syntax::Builtin::List) - .app_value(t.to_value()) - .into_value(), + .app_value(t.to_value()), TypedValue::from_const(Type), ))) } @@ -478,10 +478,9 @@ fn type_last_layer( return Err(TypeError::new(ctx, InvalidOptionalType(t))); } - Ok(RetTypeOnly(TypedValue::from_value_and_type( + Ok(RetTypeOnly(TypedValue::from_valuef_and_type( ValueF::from_builtin(dhall_syntax::Builtin::Optional) - .app_value(t.to_value()) - .into_value(), + .app_value(t.to_value()), TypedValue::from_const(Type), ))) } @@ -942,8 +941,8 @@ fn type_last_layer( }; } - Ok(RetTypeOnly(TypedValue::from_value_and_type( - ValueF::RecordType(new_kts).into_value(), + Ok(RetTypeOnly(TypedValue::from_valuef_and_type( + ValueF::RecordType(new_kts), record_type.get_type()?.into_owned(), ))) } -- cgit v1.2.3 From 730f2ebb146792994c7492b6c05f7d09d42cbccf Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 19 Aug 2019 23:00:49 +0200 Subject: Merge TypedValue and Value --- dhall/src/phase/mod.rs | 16 ++-- dhall/src/phase/normalize.rs | 90 +++++++--------------- dhall/src/phase/typecheck.rs | 177 ++++++++++++++++++++----------------------- 3 files changed, 117 insertions(+), 166 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index e58e689..91d64c3 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -4,7 +4,7 @@ use std::path::Path; use dhall_syntax::{Const, SubExpr}; -use crate::core::value::{TypedValue, Value}; +use crate::core::value::Value; use crate::core::valuef::ValueF; use crate::core::var::{AlphaVar, Shift, Subst}; use crate::error::{EncodeError, Error, ImportError, TypeError}; @@ -33,7 +33,7 @@ pub struct Resolved(ResolvedSubExpr); /// A typed expression #[derive(Debug, Clone)] -pub struct Typed(TypedValue); +pub struct Typed(Value); /// A normalized expression. /// @@ -91,12 +91,12 @@ impl Typed { } pub(crate) fn from_const(c: Const) -> Self { - Typed(TypedValue::from_const(c)) + Typed(Value::from_const(c)) } pub fn from_valuef_and_type(v: ValueF, t: Typed) -> Self { - Typed(TypedValue::from_valuef_and_type(v, t.into_typedvalue())) + Typed(Value::from_valuef_and_type(v, t.into_value())) } - pub(crate) fn from_typedvalue(th: TypedValue) -> Self { + pub(crate) fn from_value(th: Value) -> Self { Typed(th) } pub fn const_type() -> Self { @@ -112,7 +112,7 @@ impl Typed { pub fn to_value(&self) -> Value { self.0.to_value() } - pub(crate) fn into_typedvalue(self) -> TypedValue { + pub(crate) fn into_value(self) -> Value { self.0 } @@ -155,8 +155,8 @@ impl Shift for Normalized { } } -impl Subst for Typed { - fn subst_shift(&self, var: &AlphaVar, val: &TypedValue) -> Self { +impl Subst for Typed { + fn subst_shift(&self, var: &AlphaVar, val: &Value) -> Self { Typed(self.0.subst_shift(var, val)) } } diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 27858d8..821c5fd 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -5,7 +5,7 @@ use dhall_syntax::{ NaiveDouble, }; -use crate::core::value::{TypedValue, Value}; +use crate::core::value::Value; use crate::core::valuef::ValueF; use crate::core::var::{Shift, Subst}; use crate::phase::{Normalized, NormalizedSubExpr}; @@ -26,9 +26,7 @@ macro_rules! make_closure { (λ($var:ident : $($ty:tt)*) -> $($rest:tt)*) => { ValueF::Lam( Label::from(stringify!($var)).into(), - TypedValue::from_value_simple_type( - make_closure!($($ty)*), - ), + make_closure!($($ty)*), make_closure!($($rest)*), ).into_value_untyped() }; @@ -51,10 +49,10 @@ macro_rules! make_closure { make_closure!($($rest)*), Value::from_valuef_and_type( ValueF::NaturalLit(1), - TypedValue::from_value(make_closure!(Natural)) + make_closure!(Natural) ), )).into_value_with_type( - TypedValue::from_value(make_closure!(Natural)) + make_closure!(Natural) ) }; ([ $($head:tt)* ] # $($tail:tt)*) => { @@ -74,10 +72,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { // Return Ok((unconsumed args, returned value)), or Err(()) if value could not be produced. let ret = match (b, args.as_slice()) { - (OptionalNone, [t, r..]) => Ok(( - r, - EmptyOptionalLit(TypedValue::from_value_simple_type(t.clone())), - )), + (OptionalNone, [t, r..]) => Ok((r, EmptyOptionalLit(t.clone()))), (NaturalIsZero, [n, r..]) => match &*n.as_whnf() { NaturalLit(n) => Ok((r, BoolLit(*n == 0))), _ => Err(()), @@ -199,16 +194,12 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { let mut kts = HashMap::new(); kts.insert( "index".into(), - TypedValue::from_valuef_untyped(ValueF::from_builtin( - Natural, - )), + Value::from_valuef_untyped(ValueF::from_builtin(Natural)), ); kts.insert("value".into(), t.clone()); Ok(( r, - EmptyListLit(TypedValue::from_valuef_untyped(RecordType( - kts, - ))), + EmptyListLit(Value::from_valuef_untyped(RecordType(kts))), )) } NEListLit(xs) => { @@ -252,9 +243,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { [ var(x, 1) ] # var(xs, 0) ) }) - .app_valuef(EmptyListLit( - TypedValue::from_value_simple_type(t.clone()), - )), + .app_valuef(EmptyListLit(t.clone())), )), }, (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_whnf() { @@ -288,9 +277,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { ValueF::from_builtin(Optional).app_value(t.clone()), ) .app_value(make_closure!(λ(x: #t) -> Some(var(x, 0)))) - .app_valuef(EmptyOptionalLit( - TypedValue::from_value_simple_type(t.clone()), - )), + .app_valuef(EmptyOptionalLit(t.clone())), )), }, (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_whnf() { @@ -346,10 +333,7 @@ pub(crate) fn apply_any(f: Value, a: Value) -> ValueF { let f_borrow = f.as_whnf(); match &*f_borrow { - ValueF::Lam(x, _, e) => { - let val = TypedValue::from_value(a); - e.subst_shift(&x.into(), &val).to_whnf() - } + ValueF::Lam(x, _, e) => e.subst_shift(&x.into(), &a).to_whnf(), ValueF::AppliedBuiltin(b, args) => { use std::iter::once; let args = args.iter().cloned().chain(once(a.clone())).collect(); @@ -639,21 +623,18 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { } (RecursiveRecordTypeMerge, RecordType(kvs1), RecordType(kvs2)) => { let kvs = merge_maps(kvs1, kvs2, |v1, v2| { - TypedValue::from_valuef_untyped(ValueF::PartialExpr( - ExprF::BinOp( - RecursiveRecordTypeMerge, - v1.to_value(), - v2.to_value(), - ), - )) + Value::from_valuef_untyped(ValueF::PartialExpr(ExprF::BinOp( + RecursiveRecordTypeMerge, + v1.to_value(), + v2.to_value(), + ))) }); Ret::ValueF(RecordType(kvs)) } - (Equivalence, _, _) => Ret::ValueF(ValueF::Equivalence( - TypedValue::from_value_simple_type(x.clone()), - TypedValue::from_value_simple_type(y.clone()), - )), + (Equivalence, _, _) => { + Ret::ValueF(ValueF::Equivalence(x.clone(), y.clone())) + } _ => return None, }) @@ -674,18 +655,9 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { ExprF::Var(_) => unreachable!(), ExprF::Annot(x, _) => Ret::Value(x), ExprF::Assert(_) => Ret::Expr(expr), - ExprF::Lam(x, t, e) => { - Ret::ValueF(Lam(x.into(), TypedValue::from_value(t), e)) - } - ExprF::Pi(x, t, e) => Ret::ValueF(Pi( - x.into(), - TypedValue::from_value(t), - TypedValue::from_value(e), - )), - ExprF::Let(x, _, v, b) => { - let v = TypedValue::from_value(v); - Ret::Value(b.subst_shift(&x.into(), &v)) - } + ExprF::Lam(x, t, e) => Ret::ValueF(Lam(x.into(), t, e)), + ExprF::Pi(x, t, e) => Ret::ValueF(Pi(x.into(), t, e)), + ExprF::Let(x, _, v, b) => Ret::Value(b.subst_shift(&x.into(), &v)), ExprF::App(v, a) => Ret::ValueF(v.app_value(a)), ExprF::Builtin(b) => Ret::ValueF(ValueF::from_builtin(b)), ExprF::Const(c) => Ret::ValueF(ValueF::Const(c)), @@ -699,9 +671,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { let t_borrow = t.as_whnf(); match &*t_borrow { AppliedBuiltin(Builtin::List, args) if args.len() == 1 => { - Ret::ValueF(EmptyListLit( - TypedValue::from_value_simple_type(args[0].clone()), - )) + Ret::ValueF(EmptyListLit(args[0].clone())) } _ => { drop(t_borrow); @@ -715,16 +685,12 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { ExprF::RecordLit(kvs) => { Ret::ValueF(RecordLit(kvs.into_iter().collect())) } - ExprF::RecordType(kts) => Ret::ValueF(RecordType( - kts.into_iter() - .map(|(k, t)| (k, TypedValue::from_value(t))) - .collect(), - )), - ExprF::UnionType(kts) => Ret::ValueF(UnionType( - kts.into_iter() - .map(|(k, t)| (k, t.map(|t| TypedValue::from_value(t)))) - .collect(), - )), + ExprF::RecordType(kts) => { + Ret::ValueF(RecordType(kts.into_iter().collect())) + } + ExprF::UnionType(kts) => { + Ret::ValueF(UnionType(kts.into_iter().collect())) + } ExprF::TextLit(elts) => { use InterpolatedTextContents::Expr; let elts: Vec<_> = squash_textlit(elts.into_iter()); diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index e24f5a3..e65881e 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -5,7 +5,7 @@ use dhall_syntax::{ }; use crate::core::context::TypecheckContext; -use crate::core::value::TypedValue; +use crate::core::value::Value; use crate::core::valuef::ValueF; use crate::core::var::{Shift, Subst}; use crate::error::{TypeError, TypeMessage}; @@ -14,9 +14,9 @@ use crate::phase::Normalized; fn tck_pi_type( ctx: &TypecheckContext, x: Label, - tx: TypedValue, - te: TypedValue, -) -> Result { + tx: Value, + te: Value, +) -> Result { use crate::error::TypeMessage::*; let ctx2 = ctx.insert_type(&x, tx.clone()); @@ -37,16 +37,16 @@ fn tck_pi_type( let k = function_check(ka, kb); - Ok(TypedValue::from_valuef_and_type( + Ok(Value::from_valuef_and_type( ValueF::Pi(x.into(), tx, te), - TypedValue::from_const(k), + Value::from_const(k), )) } fn tck_record_type( ctx: &TypecheckContext, - kts: impl IntoIterator>, -) -> Result { + kts: impl IntoIterator>, +) -> Result { use crate::error::TypeMessage::*; use std::collections::hash_map::Entry; let mut new_kts = HashMap::new(); @@ -70,18 +70,18 @@ fn tck_record_type( // An empty record type has type Type let k = k.unwrap_or(Const::Type); - Ok(TypedValue::from_valuef_and_type( + Ok(Value::from_valuef_and_type( ValueF::RecordType(new_kts), - TypedValue::from_const(k), + Value::from_const(k), )) } fn tck_union_type( ctx: &TypecheckContext, kts: Iter, -) -> Result +) -> Result where - Iter: IntoIterator), TypeError>>, + Iter: IntoIterator), TypeError>>, { use crate::error::TypeMessage::*; use std::collections::hash_map::Entry; @@ -115,9 +115,9 @@ where // an union type with only unary variants also has type Type let k = k.unwrap_or(Const::Type); - Ok(TypedValue::from_valuef_and_type( + Ok(Value::from_valuef_and_type( ValueF::UnionType(new_kts), - TypedValue::from_const(k), + Value::from_const(k), )) } @@ -130,10 +130,10 @@ fn function_check(a: Const, b: Const) -> Const { } } -pub(crate) fn type_of_const(c: Const) -> Result { +pub(crate) fn type_of_const(c: Const) -> Result { match c { - Const::Type => Ok(TypedValue::from_const(Const::Kind)), - Const::Kind => Ok(TypedValue::from_const(Const::Sort)), + Const::Type => Ok(Value::from_const(Const::Kind)), + Const::Kind => Ok(Value::from_const(Const::Sort)), Const::Sort => { Err(TypeError::new(&TypecheckContext::new(), TypeMessage::Sort)) } @@ -282,16 +282,16 @@ fn type_of_builtin(b: Builtin) -> Expr { } // TODO: this can't fail in practise -pub(crate) fn builtin_to_type(b: Builtin) -> Result { +pub(crate) fn builtin_to_type(b: Builtin) -> Result { type_with(&TypecheckContext::new(), SubExpr::from_builtin(b)) } /// Intermediary return type enum Ret { /// Returns the contained value as is - RetWhole(TypedValue), - /// Use the contained TypedValue as the type of the input expression - RetTypeOnly(TypedValue), + RetWhole(Value), + /// Use the contained Value as the type of the input expression + RetTypeOnly(Value), } /// Type-check an expression and return the expression alongside its type if type-checking @@ -301,7 +301,7 @@ enum Ret { fn type_with( ctx: &TypecheckContext, e: SubExpr, -) -> Result { +) -> Result { use dhall_syntax::ExprF::{Annot, Embed, Lam, Let, Pi, Var}; use Ret::*; @@ -313,7 +313,7 @@ fn type_with( let v = ValueF::Lam(x.clone().into(), tx.clone(), b.to_value()); let tb = b.get_type()?.into_owned(); let t = tck_pi_type(ctx, x.clone(), tx, tb)?; - TypedValue::from_valuef_and_type(v, t) + Value::from_valuef_and_type(v, t) } Pi(x, ta, tb) => { let ta = type_with(ctx, ta.clone())?; @@ -331,7 +331,7 @@ fn type_with( let v = type_with(ctx, v)?; return type_with(&ctx.insert_value(x, v.clone())?, e.clone()); } - Embed(p) => p.clone().into_typed().into_typedvalue(), + Embed(p) => p.clone().into_typed().into_value(), Var(var) => match ctx.lookup(&var) { Some(typed) => typed.clone(), None => { @@ -352,10 +352,7 @@ fn type_with( match ret { RetTypeOnly(typ) => { let expr = expr.map_ref(|typed| typed.to_value()); - TypedValue::from_valuef_and_type( - ValueF::PartialExpr(expr), - typ, - ) + Value::from_valuef_and_type(ValueF::PartialExpr(expr), typ) } RetWhole(tt) => tt, } @@ -367,7 +364,7 @@ fn type_with( /// layer. fn type_last_layer( ctx: &TypecheckContext, - e: &ExprF, + e: &ExprF, ) -> Result { use crate::error::TypeMessage::*; use dhall_syntax::BinOp::*; @@ -466,10 +463,10 @@ fn type_last_layer( )); } - Ok(RetTypeOnly(TypedValue::from_valuef_and_type( + Ok(RetTypeOnly(Value::from_valuef_and_type( ValueF::from_builtin(dhall_syntax::Builtin::List) .app_value(t.to_value()), - TypedValue::from_const(Type), + Value::from_const(Type), ))) } SomeLit(x) => { @@ -478,10 +475,10 @@ fn type_last_layer( return Err(TypeError::new(ctx, InvalidOptionalType(t))); } - Ok(RetTypeOnly(TypedValue::from_valuef_and_type( + Ok(RetTypeOnly(Value::from_valuef_and_type( ValueF::from_builtin(dhall_syntax::Builtin::Optional) .app_value(t.to_value()), - TypedValue::from_const(Type), + Value::from_const(Type), ))) } RecordType(kts) => Ok(RetWhole(tck_record_type( @@ -545,7 +542,7 @@ fn type_last_layer( // ))), } } - Const(c) => Ok(RetWhole(TypedValue::from_const(*c))), + Const(c) => Ok(RetWhole(Value::from_const(*c))), Builtin(b) => Ok(RetTypeOnly(type_with(ctx, rc(type_of_builtin(*b)))?)), BoolLit(_) => Ok(RetTypeOnly(builtin_to_type(Bool)?)), NaturalLit(_) => Ok(RetTypeOnly(builtin_to_type(Natural)?)), @@ -607,43 +604,38 @@ fn type_last_layer( // records of records when merging. fn combine_record_types( ctx: &TypecheckContext, - kts_l: &HashMap, - kts_r: &HashMap, - ) -> Result { + kts_l: &HashMap, + kts_r: &HashMap, + ) -> Result { use crate::phase::normalize::outer_join; // If the Label exists for both records and the values // are records themselves, then we hit the recursive case. // Otherwise we have a field collision. - let combine = - |k: &Label, - inner_l: &TypedValue, - inner_r: &TypedValue| - -> Result { - match (&*inner_l.as_whnf(), &*inner_r.as_whnf()) { - ( - ValueF::RecordType(inner_l_kvs), - ValueF::RecordType(inner_r_kvs), - ) => combine_record_types( - ctx, - inner_l_kvs, - inner_r_kvs, - ), - (_, _) => Err(TypeError::new( - ctx, - FieldCollision(k.clone()), - )), + let combine = |k: &Label, + inner_l: &Value, + inner_r: &Value| + -> Result { + match (&*inner_l.as_whnf(), &*inner_r.as_whnf()) { + ( + ValueF::RecordType(inner_l_kvs), + ValueF::RecordType(inner_r_kvs), + ) => { + combine_record_types(ctx, inner_l_kvs, inner_r_kvs) } - }; + (_, _) => { + Err(TypeError::new(ctx, FieldCollision(k.clone()))) + } + } + }; - let kts: HashMap> = - outer_join( - |l| Ok(l.clone()), - |r| Ok(r.clone()), - combine, - kts_l, - kts_r, - ); + let kts: HashMap> = outer_join( + |l| Ok(l.clone()), + |r| Ok(r.clone()), + combine, + kts_l, + kts_r, + ); Ok(tck_record_type( ctx, @@ -684,35 +676,30 @@ fn type_last_layer( // records of records when merging. fn combine_record_types( ctx: &TypecheckContext, - kts_l: &HashMap, - kts_r: &HashMap, - ) -> Result { + kts_l: &HashMap, + kts_r: &HashMap, + ) -> Result { use crate::phase::normalize::intersection_with_key; // If the Label exists for both records and the values // are records themselves, then we hit the recursive case. // Otherwise we have a field collision. - let combine = - |k: &Label, - kts_l_inner: &TypedValue, - kts_r_inner: &TypedValue| - -> Result { - match (&*kts_l_inner.as_whnf(), &*kts_r_inner.as_whnf()) - { - ( - ValueF::RecordType(kvs_l_inner), - ValueF::RecordType(kvs_r_inner), - ) => combine_record_types( - ctx, - kvs_l_inner, - kvs_r_inner, - ), - (_, _) => Err(TypeError::new( - ctx, - FieldCollision(k.clone()), - )), + let combine = |k: &Label, + kts_l_inner: &Value, + kts_r_inner: &Value| + -> Result { + match (&*kts_l_inner.as_whnf(), &*kts_r_inner.as_whnf()) { + ( + ValueF::RecordType(kvs_l_inner), + ValueF::RecordType(kvs_r_inner), + ) => { + combine_record_types(ctx, kvs_l_inner, kvs_r_inner) } - }; + (_, _) => { + Err(TypeError::new(ctx, FieldCollision(k.clone()))) + } + } + }; let kts = intersection_with_key(combine, kts_l, kts_r); @@ -747,8 +734,8 @@ fn type_last_layer( k_l } else { return Err(mkerr(RecordTypeMismatch( - TypedValue::from_const(k_l), - TypedValue::from_const(k_r), + Value::from_const(k_l), + Value::from_const(k_r), l.clone(), r.clone(), ))); @@ -779,7 +766,7 @@ fn type_last_layer( // Ensure that the records combine without a type error // and if not output the final Const value. combine_record_types(ctx, kts_x, kts_y) - .and(Ok(RetTypeOnly(TypedValue::from_const(k)))) + .and(Ok(RetTypeOnly(Value::from_const(k)))) } BinOp(o @ ListAppend, l, r) => { match &*l.get_type()?.as_whnf() { @@ -814,7 +801,7 @@ fn type_last_layer( ))); } - Ok(RetTypeOnly(TypedValue::from_const(Type))) + Ok(RetTypeOnly(Value::from_const(Type))) } BinOp(o, l, r) => { let t = builtin_to_type(match o { @@ -941,7 +928,7 @@ fn type_last_layer( }; } - Ok(RetTypeOnly(TypedValue::from_valuef_and_type( + Ok(RetTypeOnly(Value::from_valuef_and_type( ValueF::RecordType(new_kts), record_type.get_type()?.into_owned(), ))) @@ -952,15 +939,13 @@ fn type_last_layer( /// `type_of` is the same as `type_with` with an empty context, meaning that the /// expression must be closed (i.e. no free variables), otherwise type-checking /// will fail. -pub(crate) fn typecheck( - e: SubExpr, -) -> Result { +pub(crate) fn typecheck(e: SubExpr) -> Result { type_with(&TypecheckContext::new(), e) } pub(crate) fn typecheck_with( expr: SubExpr, ty: SubExpr, -) -> Result { +) -> Result { typecheck(expr.rewrap(ExprF::Annot(expr.clone(), ty))) } -- cgit v1.2.3 From 85cbed46aa6a5c76902576dcf2beb323bedb25b1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 11:11:03 +0200 Subject: Tweak Ok/Err handling in typecheck --- dhall/src/phase/typecheck.rs | 285 +++++++++++++++++++------------------------ 1 file changed, 128 insertions(+), 157 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index e65881e..40017ee 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -286,14 +286,6 @@ pub(crate) fn builtin_to_type(b: Builtin) -> Result { type_with(&TypecheckContext::new(), SubExpr::from_builtin(b)) } -/// Intermediary return type -enum Ret { - /// Returns the contained value as is - RetWhole(Value), - /// Use the contained Value as the type of the input expression - RetTypeOnly(Value), -} - /// Type-check an expression and return the expression alongside its type if type-checking /// succeeded, or an error if type-checking failed. /// Some normalization is done while typechecking, so the returned expression might be partially @@ -304,7 +296,6 @@ fn type_with( ) -> Result { use dhall_syntax::ExprF::{Annot, Embed, Lam, Let, Pi, Var}; - use Ret::*; Ok(match e.as_ref() { Lam(x, t, b) => { let tx = type_with(ctx, t.clone())?; @@ -341,21 +332,13 @@ fn type_with( )) } }, - _ => { + e => { // Typecheck recursively all subexpressions - let expr = - e.as_ref().traverse_ref_with_special_handling_of_binders( - |e| type_with(ctx, e.clone()), - |_, _| unreachable!(), - )?; - let ret = type_last_layer(ctx, &expr)?; - match ret { - RetTypeOnly(typ) => { - let expr = expr.map_ref(|typed| typed.to_value()); - Value::from_valuef_and_type(ValueF::PartialExpr(expr), typ) - } - RetWhole(tt) => tt, - } + let expr = e.traverse_ref_with_special_handling_of_binders( + |e| type_with(ctx, e.clone()), + |_, _| unreachable!(), + )?; + type_last_layer(ctx, expr)? } }) } @@ -364,17 +347,25 @@ fn type_with( /// layer. fn type_last_layer( ctx: &TypecheckContext, - e: &ExprF, -) -> Result { + e: ExprF, +) -> Result { use crate::error::TypeMessage::*; use dhall_syntax::BinOp::*; use dhall_syntax::Builtin::*; use dhall_syntax::Const::Type; use dhall_syntax::ExprF::*; + let mkerr = |msg: TypeMessage| Err(TypeError::new(ctx, msg)); + + /// Intermediary return type + enum Ret { + /// Returns the contained value as is + RetWhole(Value), + /// Returns the input expression `e` with the contained value as its type + RetTypeOnly(Value), + } use Ret::*; - let mkerr = |msg: TypeMessage| TypeError::new(ctx, msg); - match e { + let ret = match &e { Import(_) => unreachable!( "There should remain no imports in a resolved expression" ), @@ -386,122 +377,113 @@ fn type_last_layer( let tf_borrow = tf.as_whnf(); let (x, tx, tb) = match &*tf_borrow { ValueF::Pi(x, tx, tb) => (x, tx, tb), - _ => return Err(mkerr(NotAFunction(f.clone()))), + _ => return mkerr(NotAFunction(f.clone())), }; if a.get_type()?.as_ref() != tx { - return Err(mkerr(TypeMismatch( - f.clone(), - tx.clone(), - a.clone(), - ))); + return mkerr(TypeMismatch(f.clone(), tx.clone(), a.clone())); } - Ok(RetTypeOnly(tb.subst_shift(&x.into(), a))) + RetTypeOnly(tb.subst_shift(&x.into(), a)) } Annot(x, t) => { if t != x.get_type()?.as_ref() { - return Err(mkerr(AnnotMismatch(x.clone(), t.clone()))); + return mkerr(AnnotMismatch(x.clone(), t.clone())); } - Ok(RetTypeOnly(x.get_type()?.into_owned())) + RetTypeOnly(x.get_type()?.into_owned()) } Assert(t) => { match &*t.as_whnf() { ValueF::Equivalence(x, y) if x == y => {} ValueF::Equivalence(x, y) => { - return Err(mkerr(AssertMismatch(x.clone(), y.clone()))) + return mkerr(AssertMismatch(x.clone(), y.clone())) } - _ => return Err(mkerr(AssertMustTakeEquivalence)), + _ => return mkerr(AssertMustTakeEquivalence), } - Ok(RetTypeOnly(t.clone())) + RetTypeOnly(t.clone()) } BoolIf(x, y, z) => { if x.get_type()?.as_ref() != &builtin_to_type(Bool)? { - return Err(mkerr(InvalidPredicate(x.clone()))); + return mkerr(InvalidPredicate(x.clone())); } if y.get_type()?.get_type()?.as_const() != Some(Type) { - return Err(mkerr(IfBranchMustBeTerm(true, y.clone()))); + return mkerr(IfBranchMustBeTerm(true, y.clone())); } if z.get_type()?.get_type()?.as_const() != Some(Type) { - return Err(mkerr(IfBranchMustBeTerm(false, z.clone()))); + return mkerr(IfBranchMustBeTerm(false, z.clone())); } if y.get_type()? != z.get_type()? { - return Err(mkerr(IfBranchMismatch(y.clone(), z.clone()))); + return mkerr(IfBranchMismatch(y.clone(), z.clone())); } - Ok(RetTypeOnly(y.get_type()?.into_owned())) + RetTypeOnly(y.get_type()?.into_owned()) } EmptyListLit(t) => { match &*t.as_whnf() { ValueF::AppliedBuiltin(dhall_syntax::Builtin::List, args) if args.len() == 1 => {} - _ => { - return Err(TypeError::new(ctx, InvalidListType(t.clone()))) - } + _ => return mkerr(InvalidListType(t.clone())), } - Ok(RetTypeOnly(t.clone())) + RetTypeOnly(t.clone()) } NEListLit(xs) => { let mut iter = xs.iter().enumerate(); let (_, x) = iter.next().unwrap(); for (i, y) in iter { if x.get_type()? != y.get_type()? { - return Err(mkerr(InvalidListElement( + return mkerr(InvalidListElement( i, x.get_type()?.into_owned(), y.clone(), - ))); + )); } } let t = x.get_type()?; if t.get_type()?.as_const() != Some(Type) { - return Err(TypeError::new( - ctx, - InvalidListType(t.into_owned()), - )); + return mkerr(InvalidListType(t.into_owned())); } - Ok(RetTypeOnly(Value::from_valuef_and_type( + RetTypeOnly(Value::from_valuef_and_type( ValueF::from_builtin(dhall_syntax::Builtin::List) .app_value(t.to_value()), Value::from_const(Type), - ))) + )) } SomeLit(x) => { let t = x.get_type()?.into_owned(); if t.get_type()?.as_const() != Some(Type) { - return Err(TypeError::new(ctx, InvalidOptionalType(t))); + return mkerr(InvalidOptionalType(t)); } - Ok(RetTypeOnly(Value::from_valuef_and_type( + RetTypeOnly(Value::from_valuef_and_type( ValueF::from_builtin(dhall_syntax::Builtin::Optional) .app_value(t.to_value()), Value::from_const(Type), - ))) + )) } - RecordType(kts) => Ok(RetWhole(tck_record_type( + RecordType(kts) => RetWhole(tck_record_type( ctx, kts.iter().map(|(x, t)| Ok((x.clone(), t.clone()))), - )?)), - UnionType(kts) => Ok(RetWhole(tck_union_type( + )?), + UnionType(kts) => RetWhole(tck_union_type( ctx, kts.iter().map(|(x, t)| Ok((x.clone(), t.clone()))), - )?)), - RecordLit(kvs) => Ok(RetTypeOnly(tck_record_type( + )?), + RecordLit(kvs) => RetTypeOnly(tck_record_type( ctx, kvs.iter() .map(|(x, v)| Ok((x.clone(), v.get_type()?.into_owned()))), - )?)), + )?), Field(r, x) => { match &*r.get_type()?.as_whnf() { ValueF::RecordType(kts) => match kts.get(&x) { Some(tth) => { - Ok(RetTypeOnly(tth.clone())) + RetTypeOnly(tth.clone()) }, - None => Err(mkerr(MissingRecordField(x.clone(), - r.clone()))), + None => return mkerr(MissingRecordField(x.clone(), + r.clone())), }, // TODO: branch here only when r.get_type() is a Const _ => { @@ -509,56 +491,56 @@ fn type_last_layer( ValueF::UnionType(kts) => match kts.get(&x) { // Constructor has type T -> < x: T, ... > Some(Some(t)) => { - Ok(RetTypeOnly( + RetTypeOnly( tck_pi_type( ctx, "_".into(), t.clone(), r.under_binder(Label::from("_")), )? - )) + ) }, Some(None) => { - Ok(RetTypeOnly(r.clone())) + RetTypeOnly(r.clone()) }, None => { - Err(mkerr(MissingUnionField( + return mkerr(MissingUnionField( x.clone(), r.clone(), - ))) + )) }, }, _ => { - Err(mkerr(NotARecord( + return mkerr(NotARecord( x.clone(), r.clone() - ))) + )) }, } } - // _ => Err(mkerr(NotARecord( + // _ => mkerr(NotARecord( // x, // r?, - // ))), + // )), } } - Const(c) => Ok(RetWhole(Value::from_const(*c))), - Builtin(b) => Ok(RetTypeOnly(type_with(ctx, rc(type_of_builtin(*b)))?)), - BoolLit(_) => Ok(RetTypeOnly(builtin_to_type(Bool)?)), - NaturalLit(_) => Ok(RetTypeOnly(builtin_to_type(Natural)?)), - IntegerLit(_) => Ok(RetTypeOnly(builtin_to_type(Integer)?)), - DoubleLit(_) => Ok(RetTypeOnly(builtin_to_type(Double)?)), + Const(c) => RetWhole(Value::from_const(*c)), + Builtin(b) => RetTypeOnly(type_with(ctx, rc(type_of_builtin(*b)))?), + BoolLit(_) => RetTypeOnly(builtin_to_type(Bool)?), + NaturalLit(_) => RetTypeOnly(builtin_to_type(Natural)?), + IntegerLit(_) => RetTypeOnly(builtin_to_type(Integer)?), + DoubleLit(_) => RetTypeOnly(builtin_to_type(Double)?), TextLit(interpolated) => { let text_type = builtin_to_type(Text)?; for contents in interpolated.iter() { use InterpolatedTextContents::Expr; if let Expr(x) = contents { if x.get_type()?.as_ref() != &text_type { - return Err(mkerr(InvalidTextInterpolation(x.clone()))); + return mkerr(InvalidTextInterpolation(x.clone())); } } } - Ok(RetTypeOnly(text_type)) + RetTypeOnly(text_type) } BinOp(RightBiasedRecordMerge, l, r) => { use crate::phase::normalize::merge_maps; @@ -572,21 +554,21 @@ fn type_last_layer( // This is to disallow expression such as: // "{ x = Text } // { y = 1 }" if l_kind != r_kind { - return Err(mkerr(RecordMismatch(l.clone(), r.clone()))); + return mkerr(RecordMismatch(l.clone(), r.clone())); } // Extract the LHS record type let l_type_borrow = l_type.as_whnf(); let kts_x = match &*l_type_borrow { ValueF::RecordType(kts) => kts, - _ => return Err(mkerr(MustCombineRecord(l.clone()))), + _ => return mkerr(MustCombineRecord(l.clone())), }; // Extract the RHS record type let r_type_borrow = r_type.as_whnf(); let kts_y = match &*r_type_borrow { ValueF::RecordType(kts) => kts, - _ => return Err(mkerr(MustCombineRecord(r.clone()))), + _ => return mkerr(MustCombineRecord(r.clone())), }; // Union the two records, prefering @@ -594,10 +576,10 @@ fn type_last_layer( let kts = merge_maps(kts_x, kts_y, |_, r_t| r_t.clone()); // Construct the final record type from the union - Ok(RetTypeOnly(tck_record_type( + RetTypeOnly(tck_record_type( ctx, kts.into_iter().map(|(x, v)| Ok((x.clone(), v))), - )?)) + )?) } BinOp(RecursiveRecordMerge, l, r) => { // A recursive function to dig down into @@ -637,10 +619,10 @@ fn type_last_layer( kts_r, ); - Ok(tck_record_type( + tck_record_type( ctx, kts.into_iter().map(|(x, v)| v.map(|r| (x.clone(), r))), - )?) + ) }; let l_type = l.get_type()?; @@ -652,24 +634,25 @@ fn type_last_layer( // This is to disallow expression such as: // "{ x = Text } // { y = 1 }" if l_kind != r_kind { - return Err(mkerr(RecordMismatch(l.clone(), r.clone()))); + return mkerr(RecordMismatch(l.clone(), r.clone())); } // Extract the LHS record type let l_type_borrow = l_type.as_whnf(); let kts_x = match &*l_type_borrow { ValueF::RecordType(kts) => kts, - _ => return Err(mkerr(MustCombineRecord(l.clone()))), + _ => return mkerr(MustCombineRecord(l.clone())), }; // Extract the RHS record type let r_type_borrow = r_type.as_whnf(); let kts_y = match &*r_type_borrow { ValueF::RecordType(kts) => kts, - _ => return Err(mkerr(MustCombineRecord(r.clone()))), + _ => return mkerr(MustCombineRecord(r.clone())), }; - combine_record_types(ctx, kts_x, kts_y).map(|r| RetTypeOnly(r)) + let r = combine_record_types(ctx, kts_x, kts_y)?; + RetTypeOnly(r) } BinOp(RecursiveRecordTypeMerge, l, r) => { // A recursive function to dig down into @@ -703,19 +686,17 @@ fn type_last_layer( let kts = intersection_with_key(combine, kts_l, kts_r); - Ok(tck_record_type( + tck_record_type( ctx, kts.into_iter().map(|(x, v)| v.map(|r| (x.clone(), r))), - )?) + ) }; // Extract the Const of the LHS let k_l = match l.get_type()?.as_const() { Some(k) => k, _ => { - return Err(mkerr(RecordTypeMergeRequiresRecordType( - l.clone(), - ))) + return mkerr(RecordTypeMergeRequiresRecordType(l.clone())) } }; @@ -723,9 +704,7 @@ fn type_last_layer( let k_r = match r.get_type()?.as_const() { Some(k) => k, _ => { - return Err(mkerr(RecordTypeMergeRequiresRecordType( - r.clone(), - ))) + return mkerr(RecordTypeMergeRequiresRecordType(r.clone())) } }; @@ -733,12 +712,12 @@ fn type_last_layer( let k = if k_l == k_r { k_l } else { - return Err(mkerr(RecordTypeMismatch( + return mkerr(RecordTypeMismatch( Value::from_const(k_l), Value::from_const(k_r), l.clone(), r.clone(), - ))); + )); }; // Extract the LHS record type @@ -746,9 +725,7 @@ fn type_last_layer( let kts_x = match &*borrow_l { ValueF::RecordType(kts) => kts, _ => { - return Err(mkerr(RecordTypeMergeRequiresRecordType( - l.clone(), - ))) + return mkerr(RecordTypeMergeRequiresRecordType(l.clone())) } }; @@ -757,51 +734,40 @@ fn type_last_layer( let kts_y = match &*borrow_r { ValueF::RecordType(kts) => kts, _ => { - return Err(mkerr(RecordTypeMergeRequiresRecordType( - r.clone(), - ))) + return mkerr(RecordTypeMergeRequiresRecordType(r.clone())) } }; // Ensure that the records combine without a type error - // and if not output the final Const value. - combine_record_types(ctx, kts_x, kts_y) - .and(Ok(RetTypeOnly(Value::from_const(k)))) + combine_record_types(ctx, kts_x, kts_y)?; + + RetTypeOnly(Value::from_const(k)) } BinOp(o @ ListAppend, l, r) => { match &*l.get_type()?.as_whnf() { ValueF::AppliedBuiltin(List, _) => {} - _ => return Err(mkerr(BinOpTypeMismatch(*o, l.clone()))), + _ => return mkerr(BinOpTypeMismatch(*o, l.clone())), } if l.get_type()? != r.get_type()? { - return Err(mkerr(BinOpTypeMismatch(*o, r.clone()))); + return mkerr(BinOpTypeMismatch(*o, r.clone())); } - Ok(RetTypeOnly(l.get_type()?.into_owned())) + RetTypeOnly(l.get_type()?.into_owned()) } BinOp(Equivalence, l, r) => { if l.get_type()?.get_type()?.as_const() != Some(Type) { - return Err(mkerr(EquivalenceArgumentMustBeTerm( - true, - l.clone(), - ))); + return mkerr(EquivalenceArgumentMustBeTerm(true, l.clone())); } if r.get_type()?.get_type()?.as_const() != Some(Type) { - return Err(mkerr(EquivalenceArgumentMustBeTerm( - false, - r.clone(), - ))); + return mkerr(EquivalenceArgumentMustBeTerm(false, r.clone())); } if l.get_type()? != r.get_type()? { - return Err(mkerr(EquivalenceTypeMismatch( - r.clone(), - l.clone(), - ))); + return mkerr(EquivalenceTypeMismatch(r.clone(), l.clone())); } - Ok(RetTypeOnly(Value::from_const(Type))) + RetTypeOnly(Value::from_const(Type)) } BinOp(o, l, r) => { let t = builtin_to_type(match o { @@ -821,28 +787,28 @@ fn type_last_layer( })?; if l.get_type()?.as_ref() != &t { - return Err(mkerr(BinOpTypeMismatch(*o, l.clone()))); + return mkerr(BinOpTypeMismatch(*o, l.clone())); } if r.get_type()?.as_ref() != &t { - return Err(mkerr(BinOpTypeMismatch(*o, r.clone()))); + return mkerr(BinOpTypeMismatch(*o, r.clone())); } - Ok(RetTypeOnly(t)) + RetTypeOnly(t) } Merge(record, union, type_annot) => { let record_type = record.get_type()?; let record_borrow = record_type.as_whnf(); let handlers = match &*record_borrow { ValueF::RecordType(kts) => kts, - _ => return Err(mkerr(Merge1ArgMustBeRecord(record.clone()))), + _ => return mkerr(Merge1ArgMustBeRecord(record.clone())), }; let union_type = union.get_type()?; let union_borrow = union_type.as_whnf(); let variants = match &*union_borrow { ValueF::UnionType(kts) => kts, - _ => return Err(mkerr(Merge2ArgMustBeUnion(union.clone()))), + _ => return mkerr(Merge2ArgMustBeUnion(union.clone())), }; let mut inferred_type = None; @@ -855,61 +821,59 @@ fn type_last_layer( let (x, tx, tb) = match &*handler_type_borrow { ValueF::Pi(x, tx, tb) => (x, tx, tb), _ => { - return Err(mkerr(NotAFunction( + return mkerr(NotAFunction( handler_type.clone(), - ))) + )) } }; if variant_type != tx { - return Err(mkerr(TypeMismatch( + return mkerr(TypeMismatch( handler_type.clone(), tx.clone(), variant_type.clone(), - ))); + )); } // Extract `tb` from under the `x` binder. Fails is `x` was free in `tb`. match tb.over_binder(x) { Some(x) => x, - None => return Err(mkerr( + None => return mkerr( MergeHandlerReturnTypeMustNotBeDependent, - )), + ), } } // Union alternative without type Some(None) => handler_type.clone(), None => { - return Err(mkerr(MergeHandlerMissingVariant( - x.clone(), - ))) + return mkerr(MergeHandlerMissingVariant(x.clone())) } }; match &inferred_type { None => inferred_type = Some(handler_return_type), Some(t) => { if t != &handler_return_type { - return Err(mkerr(MergeHandlerTypeMismatch)); + return mkerr(MergeHandlerTypeMismatch); } } } } for x in variants.keys() { if !handlers.contains_key(x) { - return Err(mkerr(MergeVariantMissingHandler(x.clone()))); + return mkerr(MergeVariantMissingHandler(x.clone())); } } match (inferred_type, type_annot) { (Some(ref t1), Some(t2)) => { if t1 != t2 { - return Err(mkerr(MergeAnnotMismatch)); + return mkerr(MergeAnnotMismatch); } - Ok(RetTypeOnly(t2.clone())) + RetTypeOnly(t2.clone()) } - (Some(t), None) => Ok(RetTypeOnly(t)), - (None, Some(t)) => Ok(RetTypeOnly(t.clone())), - (None, None) => Err(mkerr(MergeEmptyNeedsAnnotation)), + (Some(t), None) => RetTypeOnly(t), + (None, Some(t)) => RetTypeOnly(t.clone()), + (None, None) => return mkerr(MergeEmptyNeedsAnnotation), } } Projection(record, labels) => { @@ -917,23 +881,30 @@ fn type_last_layer( let record_borrow = record_type.as_whnf(); let kts = match &*record_borrow { ValueF::RecordType(kts) => kts, - _ => return Err(mkerr(ProjectionMustBeRecord)), + _ => return mkerr(ProjectionMustBeRecord), }; let mut new_kts = HashMap::new(); for l in labels { match kts.get(l) { - None => return Err(mkerr(ProjectionMissingEntry)), + None => return mkerr(ProjectionMissingEntry), Some(t) => new_kts.insert(l.clone(), t.clone()), }; } - Ok(RetTypeOnly(Value::from_valuef_and_type( + RetTypeOnly(Value::from_valuef_and_type( ValueF::RecordType(new_kts), record_type.get_type()?.into_owned(), - ))) + )) } - } + }; + + Ok(match ret { + RetTypeOnly(typ) => { + Value::from_valuef_and_type(ValueF::PartialExpr(e), typ) + } + RetWhole(v) => v, + }) } /// `type_of` is the same as `type_with` with an empty context, meaning that the -- cgit v1.2.3 From f6d30f42bd3a6762b1f53b34a249c877260951bb Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 11:52:46 +0200 Subject: Reuse work to avoid complicated recursion in record merging --- dhall/src/phase/normalize.rs | 54 ------------------- dhall/src/phase/typecheck.rs | 121 +++++++++---------------------------------- 2 files changed, 25 insertions(+), 150 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 821c5fd..76349e4 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -425,60 +425,6 @@ where kvs } -/// Performs an outer join of two HashMaps. -/// -/// # Arguments -/// -/// * `ft` - Will convert the values of the first map -/// into the target value. -/// -/// * `fu` - Will convert the values of the second map -/// into the target value. -/// -/// * `fktu` - Will convert the key and values from both maps -/// into the target type. -/// -/// # Description -/// -/// If the key is present in both maps then the final value for -/// that key is computed via the `fktu` function. Otherwise, the -/// final value will be calculated by either the `ft` or `fu` value -/// depending on which map the key is present in. -/// -/// The final map will contain all keys from the two input maps with -/// also values computed as per above. -pub(crate) fn outer_join( - mut ft: impl FnMut(&T) -> V, - mut fu: impl FnMut(&U) -> V, - mut fktu: impl FnMut(&K, &T, &U) -> V, - map1: &HashMap, - map2: &HashMap, -) -> HashMap -where - K: std::hash::Hash + Eq + Clone, -{ - let mut kvs = HashMap::new(); - - for (k1, t) in map1 { - let v = if let Some(u) = map2.get(k1) { - // The key exists in both maps - // so use all values for computation - fktu(k1, t, u) - } else { - // Key only exists in map1 - ft(t) - }; - kvs.insert(k1.clone(), v); - } - - for (k1, u) in map2 { - // Insert if key was missing in map1 - kvs.entry(k1.clone()).or_insert(fu(u)); - } - - kvs -} - pub(crate) fn merge_maps( map1: &HashMap, map2: &HashMap, diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 40017ee..77ef689 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -582,49 +582,6 @@ fn type_last_layer( )?) } BinOp(RecursiveRecordMerge, l, r) => { - // A recursive function to dig down into - // records of records when merging. - fn combine_record_types( - ctx: &TypecheckContext, - kts_l: &HashMap, - kts_r: &HashMap, - ) -> Result { - use crate::phase::normalize::outer_join; - - // If the Label exists for both records and the values - // are records themselves, then we hit the recursive case. - // Otherwise we have a field collision. - let combine = |k: &Label, - inner_l: &Value, - inner_r: &Value| - -> Result { - match (&*inner_l.as_whnf(), &*inner_r.as_whnf()) { - ( - ValueF::RecordType(inner_l_kvs), - ValueF::RecordType(inner_r_kvs), - ) => { - combine_record_types(ctx, inner_l_kvs, inner_r_kvs) - } - (_, _) => { - Err(TypeError::new(ctx, FieldCollision(k.clone()))) - } - } - }; - - let kts: HashMap> = outer_join( - |l| Ok(l.clone()), - |r| Ok(r.clone()), - combine, - kts_l, - kts_r, - ); - - tck_record_type( - ctx, - kts.into_iter().map(|(x, v)| v.map(|r| (x.clone(), r))), - ) - }; - let l_type = l.get_type()?; let l_kind = l_type.get_type()?; let r_type = r.get_type()?; @@ -637,60 +594,17 @@ fn type_last_layer( return mkerr(RecordMismatch(l.clone(), r.clone())); } - // Extract the LHS record type - let l_type_borrow = l_type.as_whnf(); - let kts_x = match &*l_type_borrow { - ValueF::RecordType(kts) => kts, - _ => return mkerr(MustCombineRecord(l.clone())), - }; - - // Extract the RHS record type - let r_type_borrow = r_type.as_whnf(); - let kts_y = match &*r_type_borrow { - ValueF::RecordType(kts) => kts, - _ => return mkerr(MustCombineRecord(r.clone())), - }; - - let r = combine_record_types(ctx, kts_x, kts_y)?; - RetTypeOnly(r) + RetTypeOnly(type_last_layer( + ctx, + ExprF::BinOp( + RecursiveRecordTypeMerge, + l_type.into_owned(), + r_type.into_owned(), + ), + )?) } BinOp(RecursiveRecordTypeMerge, l, r) => { - // A recursive function to dig down into - // records of records when merging. - fn combine_record_types( - ctx: &TypecheckContext, - kts_l: &HashMap, - kts_r: &HashMap, - ) -> Result { - use crate::phase::normalize::intersection_with_key; - - // If the Label exists for both records and the values - // are records themselves, then we hit the recursive case. - // Otherwise we have a field collision. - let combine = |k: &Label, - kts_l_inner: &Value, - kts_r_inner: &Value| - -> Result { - match (&*kts_l_inner.as_whnf(), &*kts_r_inner.as_whnf()) { - ( - ValueF::RecordType(kvs_l_inner), - ValueF::RecordType(kvs_r_inner), - ) => { - combine_record_types(ctx, kvs_l_inner, kvs_r_inner) - } - (_, _) => { - Err(TypeError::new(ctx, FieldCollision(k.clone()))) - } - } - }; - - let kts = intersection_with_key(combine, kts_l, kts_r); - - tck_record_type( - ctx, - kts.into_iter().map(|(x, v)| v.map(|r| (x.clone(), r))), - ) - }; + use crate::phase::normalize::intersection_with_key; // Extract the Const of the LHS let k_l = match l.get_type()?.as_const() { @@ -739,7 +653,22 @@ fn type_last_layer( }; // Ensure that the records combine without a type error - combine_record_types(ctx, kts_x, kts_y)?; + let kts = intersection_with_key( + // If the Label exists for both records, then we hit the recursive case. + |_: &Label, l: &Value, r: &Value| { + type_last_layer( + ctx, + ExprF::BinOp( + RecursiveRecordTypeMerge, + l.clone(), + r.clone(), + ), + ) + }, + kts_x, + kts_y, + ); + tck_record_type(ctx, kts.into_iter().map(|(x, v)| Ok((x, v?))))?; RetTypeOnly(Value::from_const(k)) } -- cgit v1.2.3 From 7dd22d6f55e3885835c7fe58b876f26937d0e7a4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 12:02:54 +0200 Subject: Standardize records of mixed kinds --- dhall/src/phase/typecheck.rs | 68 +++++++++++--------------------------------- 1 file changed, 17 insertions(+), 51 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 77ef689..8a3b43a 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -1,3 +1,4 @@ +use std::cmp::max; use std::collections::HashMap; use dhall_syntax::{ @@ -50,15 +51,16 @@ fn tck_record_type( use crate::error::TypeMessage::*; use std::collections::hash_map::Entry; let mut new_kts = HashMap::new(); - // Check that all types are the same const - let mut k = None; + // An empty record type has type Type + let mut k = Const::Type; for e in kts { let (x, t) = e?; - match (k, t.get_type()?.as_const()) { - (None, Some(k2)) => k = Some(k2), - (Some(k1), Some(k2)) if k1 == k2 => {} - _ => return Err(TypeError::new(ctx, InvalidFieldType(x, t))), + // Construct the union of the contained `Const`s + match t.get_type()?.as_const() { + Some(k2) => k = max(k, k2), + None => return Err(TypeError::new(ctx, InvalidFieldType(x, t))), } + // Check for duplicated entries let entry = new_kts.entry(x); match &entry { Entry::Occupied(_) => { @@ -67,8 +69,6 @@ fn tck_record_type( Entry::Vacant(_) => entry.or_insert_with(|| t), }; } - // An empty record type has type Type - let k = k.unwrap_or(Const::Type); Ok(Value::from_valuef_and_type( ValueF::RecordType(new_kts), @@ -122,7 +122,6 @@ where } fn function_check(a: Const, b: Const) -> Const { - use std::cmp::max; if b == Const::Type { Const::Type } else { @@ -546,16 +545,7 @@ fn type_last_layer( use crate::phase::normalize::merge_maps; let l_type = l.get_type()?; - let l_kind = l_type.get_type()?; let r_type = r.get_type()?; - let r_kind = r_type.get_type()?; - - // Check the equality of kinds. - // This is to disallow expression such as: - // "{ x = Text } // { y = 1 }" - if l_kind != r_kind { - return mkerr(RecordMismatch(l.clone(), r.clone())); - } // Extract the LHS record type let l_type_borrow = l_type.as_whnf(); @@ -581,28 +571,14 @@ fn type_last_layer( kts.into_iter().map(|(x, v)| Ok((x.clone(), v))), )?) } - BinOp(RecursiveRecordMerge, l, r) => { - let l_type = l.get_type()?; - let l_kind = l_type.get_type()?; - let r_type = r.get_type()?; - let r_kind = r_type.get_type()?; - - // Check the equality of kinds. - // This is to disallow expression such as: - // "{ x = Text } // { y = 1 }" - if l_kind != r_kind { - return mkerr(RecordMismatch(l.clone(), r.clone())); - } - - RetTypeOnly(type_last_layer( - ctx, - ExprF::BinOp( - RecursiveRecordTypeMerge, - l_type.into_owned(), - r_type.into_owned(), - ), - )?) - } + BinOp(RecursiveRecordMerge, l, r) => RetTypeOnly(type_last_layer( + ctx, + ExprF::BinOp( + RecursiveRecordTypeMerge, + l.get_type()?.into_owned(), + r.get_type()?.into_owned(), + ), + )?), BinOp(RecursiveRecordTypeMerge, l, r) => { use crate::phase::normalize::intersection_with_key; @@ -622,17 +598,7 @@ fn type_last_layer( } }; - // Const values must match for the Records - let k = if k_l == k_r { - k_l - } else { - return mkerr(RecordTypeMismatch( - Value::from_const(k_l), - Value::from_const(k_r), - l.clone(), - r.clone(), - )); - }; + let k = max(k_l, k_r); // Extract the LHS record type let borrow_l = l.as_whnf(); -- cgit v1.2.3 From caf36246a517b884d7cfcf7c31e1b5d8fce60dfa Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 13:49:13 +0200 Subject: Cleanup --- dhall/src/phase/mod.rs | 2 +- dhall/src/phase/normalize.rs | 87 ++++++++++++++++++++++++++++---------------- dhall/src/phase/typecheck.rs | 6 +-- 3 files changed, 59 insertions(+), 36 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 91d64c3..1f7e5f0 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -110,7 +110,7 @@ impl Typed { self.0.to_expr_alpha() } pub fn to_value(&self) -> Value { - self.0.to_value() + self.0.clone() } pub(crate) fn into_value(self) -> Value { self.0 diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 76349e4..a379a4b 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -231,20 +231,28 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { unimplemented!() } } - _ => Ok(( - r, - f.app_valuef(ValueF::from_builtin(List).app_value(t.clone())) - .app_value({ - // Move `t` under new `x` variable - let t1 = t.under_binder(Label::from("x")); - make_closure!( - λ(x : #t) -> - λ(xs : List #t1) -> - [ var(x, 1) ] # var(xs, 0) - ) - }) - .app_valuef(EmptyListLit(t.clone())), - )), + _ => { + let list_t = ValueF::from_builtin(List) + .app_value(t.clone()) + .into_value_simple_type(); + Ok(( + r, + f.app_value(list_t.clone()) + .app_value({ + // Move `t` under new `x` variable + let t1 = t.under_binder(Label::from("x")); + make_closure!( + λ(x : #t) -> + λ(xs : List #t1) -> + [ var(x, 1) ] # var(xs, 0) + ) + }) + .app_value( + EmptyListLit(t.clone()) + .into_value_with_type(list_t), + ), + )) + } }, (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_whnf() { EmptyListLit(_) => Ok((r, nil.to_whnf())), @@ -271,14 +279,20 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { unimplemented!() } } - _ => Ok(( - r, - f.app_valuef( - ValueF::from_builtin(Optional).app_value(t.clone()), - ) - .app_value(make_closure!(λ(x: #t) -> Some(var(x, 0)))) - .app_valuef(EmptyOptionalLit(t.clone())), - )), + _ => { + let optional_t = ValueF::from_builtin(Optional) + .app_value(t.clone()) + .into_value_simple_type(); + Ok(( + r, + f.app_value(optional_t.clone()) + .app_value(make_closure!(λ(x: #t) -> Some(var(x, 0)))) + .app_value( + EmptyOptionalLit(t.clone()) + .into_value_with_type(optional_t), + ), + )) + } }, (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_whnf() { EmptyOptionalLit(_) => Ok((r, nothing.to_whnf())), @@ -295,12 +309,20 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { unimplemented!() } } - _ => Ok(( - r, - f.app_valuef(ValueF::from_builtin(Natural)) - .app_value(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) - .app_valuef(NaturalLit(0)), - )), + _ => { + let nat_type = + ValueF::from_builtin(Natural).into_value_simple_type(); + Ok(( + r, + f.app_value(nat_type.clone()) + .app_value( + make_closure!(λ(x : Natural) -> 1 + var(x, 0)), + ) + .app_value( + NaturalLit(0).into_value_with_type(nat_type), + ), + )) + } }, (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_whnf() { NaturalLit(0) => Ok((r, zero.to_whnf())), @@ -309,8 +331,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { .app(NaturalLit(n - 1)) .app_value(t.clone()) .app_value(succ.clone()) - .app_value(zero.clone()); - Ok((r, succ.app_valuef(fold))) + .app_value(zero.clone()) + .into_value_with_type(t.clone()); + Ok((r, succ.app_value(fold))) } _ => Err(()), }, @@ -571,8 +594,8 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { let kvs = merge_maps(kvs1, kvs2, |v1, v2| { Value::from_valuef_untyped(ValueF::PartialExpr(ExprF::BinOp( RecursiveRecordTypeMerge, - v1.to_value(), - v2.to_value(), + v1.clone(), + v2.clone(), ))) }); Ret::ValueF(RecordType(kvs)) diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 8a3b43a..c47eb78 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -300,7 +300,7 @@ fn type_with( let tx = type_with(ctx, t.clone())?; let ctx2 = ctx.insert_type(x, tx.clone()); let b = type_with(&ctx2, b.clone())?; - let v = ValueF::Lam(x.clone().into(), tx.clone(), b.to_value()); + let v = ValueF::Lam(x.clone().into(), tx.clone(), b.clone()); let tb = b.get_type()?.into_owned(); let t = tck_pi_type(ctx, x.clone(), tx, tb)?; Value::from_valuef_and_type(v, t) @@ -446,7 +446,7 @@ fn type_last_layer( RetTypeOnly(Value::from_valuef_and_type( ValueF::from_builtin(dhall_syntax::Builtin::List) - .app_value(t.to_value()), + .app_value(t.into_owned()), Value::from_const(Type), )) } @@ -458,7 +458,7 @@ fn type_last_layer( RetTypeOnly(Value::from_valuef_and_type( ValueF::from_builtin(dhall_syntax::Builtin::Optional) - .app_value(t.to_value()), + .app_value(t), Value::from_const(Type), )) } -- cgit v1.2.3 From 38a82c53ef45e802cf5816a8afcbf36a69c91174 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 14:12:27 +0200 Subject: Clarify conversion of Const/Builtin to Value --- dhall/src/phase/typecheck.rs | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index c47eb78..1ea87d1 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -129,16 +129,24 @@ fn function_check(a: Const, b: Const) -> Const { } } -pub(crate) fn type_of_const(c: Const) -> Result { +fn type_of_const(c: Const) -> Result { match c { - Const::Type => Ok(Value::from_const(Const::Kind)), - Const::Kind => Ok(Value::from_const(Const::Sort)), + Const::Type => Ok(const_to_value(Const::Kind)), + Const::Kind => Ok(const_to_value(Const::Sort)), Const::Sort => { Err(TypeError::new(&TypecheckContext::new(), TypeMessage::Sort)) } } } +pub(crate) fn const_to_value(c: Const) -> Value { + let v = ValueF::Const(c); + match type_of_const(c) { + Ok(t) => Value::from_valuef_and_type(v, t), + Err(_) => Value::from_valuef_untyped(v), + } +} + // Ad-hoc macro to help construct the types of builtins macro_rules! make_type { (Type) => { ExprF::Const(Const::Type) }; @@ -280,9 +288,12 @@ fn type_of_builtin(b: Builtin) -> Expr { } } -// TODO: this can't fail in practise -pub(crate) fn builtin_to_type(b: Builtin) -> Result { - type_with(&TypecheckContext::new(), SubExpr::from_builtin(b)) +pub(crate) fn builtin_to_value(b: Builtin) -> Value { + let ctx = TypecheckContext::new(); + Value::from_valuef_and_type( + ValueF::PartialExpr(ExprF::Builtin(b)), + type_with(&ctx, rc(type_of_builtin(b))).unwrap(), + ) } /// Type-check an expression and return the expression alongside its type if type-checking @@ -401,7 +412,7 @@ fn type_last_layer( RetTypeOnly(t.clone()) } BoolIf(x, y, z) => { - if x.get_type()?.as_ref() != &builtin_to_type(Bool)? { + if x.get_type()?.as_ref() != &builtin_to_value(Bool) { return mkerr(InvalidPredicate(x.clone())); } @@ -523,14 +534,14 @@ fn type_last_layer( // )), } } - Const(c) => RetWhole(Value::from_const(*c)), - Builtin(b) => RetTypeOnly(type_with(ctx, rc(type_of_builtin(*b)))?), - BoolLit(_) => RetTypeOnly(builtin_to_type(Bool)?), - NaturalLit(_) => RetTypeOnly(builtin_to_type(Natural)?), - IntegerLit(_) => RetTypeOnly(builtin_to_type(Integer)?), - DoubleLit(_) => RetTypeOnly(builtin_to_type(Double)?), + Const(c) => RetWhole(const_to_value(*c)), + Builtin(b) => RetWhole(builtin_to_value(*b)), + BoolLit(_) => RetTypeOnly(builtin_to_value(Bool)), + NaturalLit(_) => RetTypeOnly(builtin_to_value(Natural)), + IntegerLit(_) => RetTypeOnly(builtin_to_value(Integer)), + DoubleLit(_) => RetTypeOnly(builtin_to_value(Double)), TextLit(interpolated) => { - let text_type = builtin_to_type(Text)?; + let text_type = builtin_to_value(Text); for contents in interpolated.iter() { use InterpolatedTextContents::Expr; if let Expr(x) = contents { @@ -665,7 +676,7 @@ fn type_last_layer( RetTypeOnly(Value::from_const(Type)) } BinOp(o, l, r) => { - let t = builtin_to_type(match o { + let t = builtin_to_value(match o { BoolAnd => Bool, BoolOr => Bool, BoolEQ => Bool, @@ -679,7 +690,7 @@ fn type_last_layer( RecursiveRecordTypeMerge => unreachable!(), ImportAlt => unreachable!("There should remain no import alternatives in a resolved expression"), Equivalence => unreachable!(), - })?; + }); if l.get_type()?.as_ref() != &t { return mkerr(BinOpTypeMismatch(*o, l.clone())); -- cgit v1.2.3 From 04438824db21fb5d9d3a2abdb3fa167875bda892 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 16:39:27 +0200 Subject: Add Value::from_builtin --- dhall/src/phase/normalize.rs | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index a379a4b..f943171 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -31,11 +31,10 @@ macro_rules! make_closure { ).into_value_untyped() }; (Natural) => { - ValueF::from_builtin(Builtin::Natural) - .into_value_simple_type() + Value::from_builtin(Builtin::Natural) }; (List $($rest:tt)*) => { - ValueF::from_builtin(Builtin::List) + Value::from_builtin(Builtin::List) .app_value(make_closure!($($rest)*)) .into_value_simple_type() }; @@ -192,10 +191,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { (ListIndexed, [_, l, r..]) => match &*l.as_whnf() { EmptyListLit(t) => { let mut kts = HashMap::new(); - kts.insert( - "index".into(), - Value::from_valuef_untyped(ValueF::from_builtin(Natural)), - ); + kts.insert("index".into(), Value::from_builtin(Natural)); kts.insert("value".into(), t.clone()); Ok(( r, @@ -232,7 +228,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } } _ => { - let list_t = ValueF::from_builtin(List) + let list_t = Value::from_builtin(List) .app_value(t.clone()) .into_value_simple_type(); Ok(( @@ -280,7 +276,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } } _ => { - let optional_t = ValueF::from_builtin(Optional) + let optional_t = Value::from_builtin(Optional) .app_value(t.clone()) .into_value_simple_type(); Ok(( @@ -309,26 +305,24 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { unimplemented!() } } - _ => { - let nat_type = - ValueF::from_builtin(Natural).into_value_simple_type(); - Ok(( - r, - f.app_value(nat_type.clone()) - .app_value( - make_closure!(λ(x : Natural) -> 1 + var(x, 0)), - ) - .app_value( - NaturalLit(0).into_value_with_type(nat_type), - ), - )) - } + _ => Ok(( + r, + f.app_value(Value::from_builtin(Natural)) + .app_value(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) + .app_value( + NaturalLit(0) + .into_value_with_type(Value::from_builtin(Natural)), + ), + )), }, (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_whnf() { NaturalLit(0) => Ok((r, zero.to_whnf())), NaturalLit(n) => { - let fold = ValueF::from_builtin(NaturalFold) - .app(NaturalLit(n - 1)) + let fold = Value::from_builtin(NaturalFold) + .app_value( + NaturalLit(n - 1) + .into_value_with_type(Value::from_builtin(Natural)), + ) .app_value(t.clone()) .app_value(succ.clone()) .app_value(zero.clone()) -- cgit v1.2.3 From a506632b27b287d1bf898e2f77ae09a56902474c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 17:08:01 +0200 Subject: Naming tweaks --- dhall/src/phase/normalize.rs | 52 ++++++++++++++++++++------------------------ dhall/src/phase/typecheck.rs | 5 ++--- 2 files changed, 25 insertions(+), 32 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index f943171..afc2e7f 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -8,9 +8,7 @@ use dhall_syntax::{ use crate::core::value::Value; use crate::core::valuef::ValueF; use crate::core::var::{Shift, Subst}; -use crate::phase::{Normalized, NormalizedSubExpr}; - -pub(crate) type OutputSubExpr = NormalizedSubExpr; +use crate::phase::Normalized; // Ad-hoc macro to help construct closures macro_rules! make_closure { @@ -35,7 +33,7 @@ macro_rules! make_closure { }; (List $($rest:tt)*) => { Value::from_builtin(Builtin::List) - .app_value(make_closure!($($rest)*)) + .app(make_closure!($($rest)*)) .into_value_simple_type() }; (Some($($rest:tt)*)) => { @@ -229,12 +227,12 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } _ => { let list_t = Value::from_builtin(List) - .app_value(t.clone()) + .app(t.clone()) .into_value_simple_type(); Ok(( r, - f.app_value(list_t.clone()) - .app_value({ + f.app(list_t.clone()) + .app({ // Move `t` under new `x` variable let t1 = t.under_binder(Label::from("x")); make_closure!( @@ -243,7 +241,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { [ var(x, 1) ] # var(xs, 0) ) }) - .app_value( + .app( EmptyListLit(t.clone()) .into_value_with_type(list_t), ), @@ -255,11 +253,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { NEListLit(xs) => { let mut v = nil.clone(); for x in xs.iter().rev() { - v = cons - .clone() - .app_value(x.clone()) - .app_value(v) - .into_value_untyped(); + v = cons.clone().app(x.clone()).app(v).into_value_untyped(); } Ok((r, v.to_whnf())) } @@ -277,13 +271,13 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } _ => { let optional_t = Value::from_builtin(Optional) - .app_value(t.clone()) + .app(t.clone()) .into_value_simple_type(); Ok(( r, - f.app_value(optional_t.clone()) - .app_value(make_closure!(λ(x: #t) -> Some(var(x, 0)))) - .app_value( + f.app(optional_t.clone()) + .app(make_closure!(λ(x: #t) -> Some(var(x, 0)))) + .app( EmptyOptionalLit(t.clone()) .into_value_with_type(optional_t), ), @@ -292,7 +286,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { }, (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_whnf() { EmptyOptionalLit(_) => Ok((r, nothing.to_whnf())), - NEOptionalLit(x) => Ok((r, just.app_value(x.clone()))), + NEOptionalLit(x) => Ok((r, just.app(x.clone()))), _ => Err(()), }, (NaturalBuild, [f, r..]) => match &*f.as_whnf() { @@ -307,9 +301,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } _ => Ok(( r, - f.app_value(Value::from_builtin(Natural)) - .app_value(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) - .app_value( + f.app(Value::from_builtin(Natural)) + .app(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) + .app( NaturalLit(0) .into_value_with_type(Value::from_builtin(Natural)), ), @@ -319,15 +313,15 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { NaturalLit(0) => Ok((r, zero.to_whnf())), NaturalLit(n) => { let fold = Value::from_builtin(NaturalFold) - .app_value( + .app( NaturalLit(n - 1) .into_value_with_type(Value::from_builtin(Natural)), ) - .app_value(t.clone()) - .app_value(succ.clone()) - .app_value(zero.clone()) + .app(t.clone()) + .app(succ.clone()) + .app(zero.clone()) .into_value_with_type(t.clone()); - Ok((r, succ.app_value(fold))) + Ok((r, succ.app(fold))) } _ => Err(()), }, @@ -337,7 +331,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { Ok((unconsumed_args, mut v)) => { let n_consumed_args = args.len() - unconsumed_args.len(); for x in args.into_iter().skip(n_consumed_args) { - v = v.app_value(x); + v = v.app(x); } v } @@ -621,7 +615,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { ExprF::Lam(x, t, e) => Ret::ValueF(Lam(x.into(), t, e)), ExprF::Pi(x, t, e) => Ret::ValueF(Pi(x.into(), t, e)), ExprF::Let(x, _, v, b) => Ret::Value(b.subst_shift(&x.into(), &v)), - ExprF::App(v, a) => Ret::ValueF(v.app_value(a)), + ExprF::App(v, a) => Ret::ValueF(v.app(a)), ExprF::Builtin(b) => Ret::ValueF(ValueF::from_builtin(b)), ExprF::Const(c) => Ret::ValueF(ValueF::Const(c)), ExprF::BoolLit(b) => Ret::ValueF(BoolLit(b)), @@ -743,7 +737,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { } }, (RecordLit(kvs), UnionLit(l, v, _)) => match kvs.get(l) { - Some(h) => Ret::ValueF(h.app_value(v.clone())), + Some(h) => Ret::ValueF(h.app(v.clone())), None => { drop(handlers_borrow); drop(variant_borrow); diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 1ea87d1..440d694 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -457,7 +457,7 @@ fn type_last_layer( RetTypeOnly(Value::from_valuef_and_type( ValueF::from_builtin(dhall_syntax::Builtin::List) - .app_value(t.into_owned()), + .app(t.into_owned()), Value::from_const(Type), )) } @@ -468,8 +468,7 @@ fn type_last_layer( } RetTypeOnly(Value::from_valuef_and_type( - ValueF::from_builtin(dhall_syntax::Builtin::Optional) - .app_value(t), + ValueF::from_builtin(dhall_syntax::Builtin::Optional).app(t), Value::from_const(Type), )) } -- cgit v1.2.3 From 4f1f37cfc115510500e83d2dfbfa8ed7ddeae74a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 18:03:59 +0200 Subject: Introduce a new enum to store either a Value or a ValueF --- dhall/src/phase/normalize.rs | 141 +++++++++++++++++++++++++------------------ dhall/src/phase/typecheck.rs | 17 +++--- 2 files changed, 90 insertions(+), 68 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index afc2e7f..e044018 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -5,7 +5,7 @@ use dhall_syntax::{ NaiveDouble, }; -use crate::core::value::Value; +use crate::core::value::{Value, VoVF}; use crate::core::valuef::ValueF; use crate::core::var::{Shift, Subst}; use crate::phase::Normalized; @@ -63,44 +63,48 @@ macro_rules! make_closure { } #[allow(clippy::cognitive_complexity)] -pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { +pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { use dhall_syntax::Builtin::*; use ValueF::*; // Return Ok((unconsumed args, returned value)), or Err(()) if value could not be produced. let ret = match (b, args.as_slice()) { - (OptionalNone, [t, r..]) => Ok((r, EmptyOptionalLit(t.clone()))), + (OptionalNone, [t, r..]) => { + Ok((r, EmptyOptionalLit(t.clone()).into_vovf())) + } (NaturalIsZero, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, BoolLit(*n == 0))), + NaturalLit(n) => Ok((r, BoolLit(*n == 0).into_vovf())), _ => Err(()), }, (NaturalEven, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, BoolLit(*n % 2 == 0))), + NaturalLit(n) => Ok((r, BoolLit(*n % 2 == 0).into_vovf())), _ => Err(()), }, (NaturalOdd, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, BoolLit(*n % 2 != 0))), + NaturalLit(n) => Ok((r, BoolLit(*n % 2 != 0).into_vovf())), _ => Err(()), }, (NaturalToInteger, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, IntegerLit(*n as isize))), + NaturalLit(n) => Ok((r, IntegerLit(*n as isize).into_vovf())), _ => Err(()), }, (NaturalShow, [n, r..]) => match &*n.as_whnf() { NaturalLit(n) => Ok(( r, - TextLit(vec![InterpolatedTextContents::Text(n.to_string())]), + TextLit(vec![InterpolatedTextContents::Text(n.to_string())]) + .into_vovf(), )), _ => Err(()), }, (NaturalSubtract, [a, b, r..]) => { match (&*a.as_whnf(), &*b.as_whnf()) { - (NaturalLit(a), NaturalLit(b)) => { - Ok((r, NaturalLit(if b > a { b - a } else { 0 }))) - } - (NaturalLit(0), b) => Ok((r, b.clone())), - (_, NaturalLit(0)) => Ok((r, NaturalLit(0))), - _ if a == b => Ok((r, NaturalLit(0))), + (NaturalLit(a), NaturalLit(b)) => Ok(( + r, + NaturalLit(if b > a { b - a } else { 0 }).into_vovf(), + )), + (NaturalLit(0), _) => Ok((r, b.clone().into_vovf())), + (_, NaturalLit(0)) => Ok((r, NaturalLit(0).into_vovf())), + _ if a == b => Ok((r, NaturalLit(0).into_vovf())), _ => Err(()), } } @@ -111,18 +115,25 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } else { format!("+{}", n) }; - Ok((r, TextLit(vec![InterpolatedTextContents::Text(s)]))) + Ok(( + r, + TextLit(vec![InterpolatedTextContents::Text(s)]) + .into_vovf(), + )) } _ => Err(()), }, (IntegerToDouble, [n, r..]) => match &*n.as_whnf() { - IntegerLit(n) => Ok((r, DoubleLit(NaiveDouble::from(*n as f64)))), + IntegerLit(n) => { + Ok((r, DoubleLit(NaiveDouble::from(*n as f64)).into_vovf())) + } _ => Err(()), }, (DoubleShow, [n, r..]) => match &*n.as_whnf() { DoubleLit(n) => Ok(( r, - TextLit(vec![InterpolatedTextContents::Text(n.to_string())]), + TextLit(vec![InterpolatedTextContents::Text(n.to_string())]) + .into_vovf(), )), _ => Err(()), }, @@ -137,7 +148,8 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { let s = txt.to_string(); Ok(( r, - TextLit(vec![InterpolatedTextContents::Text(s)]), + TextLit(vec![InterpolatedTextContents::Text(s)]) + .into_vovf(), )) } // If there are no interpolations (invariants ensure that when there are no @@ -152,7 +164,8 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { let s = txt.to_string(); Ok(( r, - TextLit(vec![InterpolatedTextContents::Text(s)]), + TextLit(vec![InterpolatedTextContents::Text(s)]) + .into_vovf(), )) } _ => Err(()), @@ -161,29 +174,33 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { _ => Err(()), }, (ListLength, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(_) => Ok((r, NaturalLit(0))), - NEListLit(xs) => Ok((r, NaturalLit(xs.len()))), + EmptyListLit(_) => Ok((r, NaturalLit(0).into_vovf())), + NEListLit(xs) => Ok((r, NaturalLit(xs.len()).into_vovf())), _ => Err(()), }, (ListHead, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()))), - NEListLit(xs) => { - Ok((r, NEOptionalLit(xs.iter().next().unwrap().clone()))) - } + EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()).into_vovf())), + NEListLit(xs) => Ok(( + r, + NEOptionalLit(xs.iter().next().unwrap().clone()).into_vovf(), + )), _ => Err(()), }, (ListLast, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()))), - NEListLit(xs) => { - Ok((r, NEOptionalLit(xs.iter().rev().next().unwrap().clone()))) - } + EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()).into_vovf())), + NEListLit(xs) => Ok(( + r, + NEOptionalLit(xs.iter().rev().next().unwrap().clone()) + .into_vovf(), + )), _ => Err(()), }, (ListReverse, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(n) => Ok((r, EmptyListLit(n.clone()))), - NEListLit(xs) => { - Ok((r, NEListLit(xs.iter().rev().cloned().collect()))) - } + EmptyListLit(n) => Ok((r, EmptyListLit(n.clone()).into_vovf())), + NEListLit(xs) => Ok(( + r, + NEListLit(xs.iter().rev().cloned().collect()).into_vovf(), + )), _ => Err(()), }, (ListIndexed, [_, l, r..]) => match &*l.as_whnf() { @@ -193,7 +210,8 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { kts.insert("value".into(), t.clone()); Ok(( r, - EmptyListLit(Value::from_valuef_untyped(RecordType(kts))), + EmptyListLit(Value::from_valuef_untyped(RecordType(kts))) + .into_vovf(), )) } NEListLit(xs) => { @@ -211,7 +229,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { Value::from_valuef_untyped(RecordLit(kvs)) }) .collect(); - Ok((r, NEListLit(xs))) + Ok((r, NEListLit(xs).into_vovf())) } _ => Err(()), }, @@ -219,7 +237,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { // fold/build fusion ValueF::AppliedBuiltin(ListFold, args) => { if args.len() >= 2 { - Ok((r, args[1].to_whnf())) + Ok((r, args[1].clone().into_vovf())) } else { // Do we really need to handle this case ? unimplemented!() @@ -249,13 +267,13 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } }, (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_whnf() { - EmptyListLit(_) => Ok((r, nil.to_whnf())), + EmptyListLit(_) => Ok((r, nil.clone().into_vovf())), NEListLit(xs) => { - let mut v = nil.clone(); - for x in xs.iter().rev() { - v = cons.clone().app(x.clone()).app(v).into_value_untyped(); + let mut v = nil.clone().into_vovf(); + for x in xs.iter().cloned().rev() { + v = cons.app(x).app(v.into_value_untyped()); } - Ok((r, v.to_whnf())) + Ok((r, v)) } _ => Err(()), }, @@ -263,7 +281,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { // fold/build fusion ValueF::AppliedBuiltin(OptionalFold, args) => { if args.len() >= 2 { - Ok((r, args[1].to_whnf())) + Ok((r, args[1].clone().into_vovf())) } else { // Do we really need to handle this case ? unimplemented!() @@ -285,7 +303,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } }, (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_whnf() { - EmptyOptionalLit(_) => Ok((r, nothing.to_whnf())), + EmptyOptionalLit(_) => Ok((r, nothing.clone().into_vovf())), NEOptionalLit(x) => Ok((r, just.app(x.clone()))), _ => Err(()), }, @@ -293,7 +311,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { // fold/build fusion ValueF::AppliedBuiltin(NaturalFold, args) => { if !args.is_empty() { - Ok((r, args[0].to_whnf())) + Ok((r, args[0].clone().into_vovf())) } else { // Do we really need to handle this case ? unimplemented!() @@ -310,7 +328,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { )), }, (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_whnf() { - NaturalLit(0) => Ok((r, zero.to_whnf())), + NaturalLit(0) => Ok((r, zero.clone().into_vovf())), NaturalLit(n) => { let fold = Value::from_builtin(NaturalFold) .app( @@ -335,23 +353,24 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> ValueF { } v } - Err(()) => AppliedBuiltin(b, args), + Err(()) => AppliedBuiltin(b, args).into_vovf(), } } -pub(crate) fn apply_any(f: Value, a: Value) -> ValueF { - let fallback = |f: Value, a: Value| ValueF::PartialExpr(ExprF::App(f, a)); +pub(crate) fn apply_any(f: Value, a: Value) -> VoVF { + let fallback = + |f: Value, a: Value| ValueF::PartialExpr(ExprF::App(f, a)).into_vovf(); let f_borrow = f.as_whnf(); match &*f_borrow { - ValueF::Lam(x, _, e) => e.subst_shift(&x.into(), &a).to_whnf(), + ValueF::Lam(x, _, e) => e.subst_shift(&x.into(), &a).into_vovf(), ValueF::AppliedBuiltin(b, args) => { use std::iter::once; let args = args.iter().cloned().chain(once(a.clone())).collect(); apply_builtin(*b, args) } ValueF::UnionConstructor(l, kts) => { - ValueF::UnionLit(l.clone(), a, kts.clone()) + ValueF::UnionLit(l.clone(), a, kts.clone()).into_vovf() } _ => { drop(f_borrow); @@ -465,6 +484,7 @@ where enum Ret<'a> { ValueF(ValueF), Value(Value), + VoVF(VoVF), ValueRef(&'a Value), Expr(ExprF), } @@ -597,7 +617,7 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { }) } -pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { +pub(crate) fn normalize_one_layer(expr: ExprF) -> VoVF { use ValueF::{ AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, Lam, NEListLit, NEOptionalLit, NaturalLit, Pi, RecordLit, RecordType, @@ -615,7 +635,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { ExprF::Lam(x, t, e) => Ret::ValueF(Lam(x.into(), t, e)), ExprF::Pi(x, t, e) => Ret::ValueF(Pi(x.into(), t, e)), ExprF::Let(x, _, v, b) => Ret::Value(b.subst_shift(&x.into(), &v)), - ExprF::App(v, a) => Ret::ValueF(v.app(a)), + ExprF::App(v, a) => Ret::VoVF(v.app(a)), ExprF::Builtin(b) => Ret::ValueF(ValueF::from_builtin(b)), ExprF::Const(c) => Ret::ValueF(ValueF::Const(c)), ExprF::BoolLit(b) => Ret::ValueF(BoolLit(b)), @@ -737,7 +757,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { } }, (RecordLit(kvs), UnionLit(l, v, _)) => match kvs.get(l) { - Some(h) => Ret::ValueF(h.app(v.clone())), + Some(h) => Ret::VoVF(h.app(v.clone())), None => { drop(handlers_borrow); drop(variant_borrow); @@ -754,22 +774,23 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> ValueF { }; match ret { - Ret::ValueF(v) => v, - Ret::Value(th) => th.as_whnf().clone(), - Ret::ValueRef(th) => th.as_whnf().clone(), - Ret::Expr(expr) => ValueF::PartialExpr(expr), + Ret::ValueF(v) => v.into_vovf(), + Ret::Value(v) => v.into_vovf(), + Ret::VoVF(v) => v, + Ret::ValueRef(v) => v.clone().into_vovf(), + Ret::Expr(expr) => ValueF::PartialExpr(expr).into_vovf(), } } /// Normalize a ValueF into WHNF -pub(crate) fn normalize_whnf(v: ValueF) -> ValueF { +pub(crate) fn normalize_whnf(v: ValueF) -> VoVF { match v { ValueF::AppliedBuiltin(b, args) => apply_builtin(b, args), ValueF::PartialExpr(e) => normalize_one_layer(e), ValueF::TextLit(elts) => { - ValueF::TextLit(squash_textlit(elts.into_iter())) + ValueF::TextLit(squash_textlit(elts.into_iter())).into_vovf() } // All other cases are already in WHNF - v => v, + v => v.into_vovf(), } } diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 440d694..996c26c 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -455,11 +455,11 @@ fn type_last_layer( return mkerr(InvalidListType(t.into_owned())); } - RetTypeOnly(Value::from_valuef_and_type( + RetTypeOnly( ValueF::from_builtin(dhall_syntax::Builtin::List) - .app(t.into_owned()), - Value::from_const(Type), - )) + .app(t.into_owned()) + .into_value_simple_type(), + ) } SomeLit(x) => { let t = x.get_type()?.into_owned(); @@ -467,10 +467,11 @@ fn type_last_layer( return mkerr(InvalidOptionalType(t)); } - RetTypeOnly(Value::from_valuef_and_type( - ValueF::from_builtin(dhall_syntax::Builtin::Optional).app(t), - Value::from_const(Type), - )) + RetTypeOnly( + Value::from_builtin(dhall_syntax::Builtin::Optional) + .app(t) + .into_value_simple_type(), + ) } RecordType(kts) => RetWhole(tck_record_type( ctx, -- cgit v1.2.3 From c157df5e66fb80ff6184cb3934e5b0883f0fdbf0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 18:11:05 +0200 Subject: No need for Cow in return type of get_type --- dhall/src/phase/mod.rs | 5 ++--- dhall/src/phase/typecheck.rs | 39 +++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 23 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 1f7e5f0..1f80791 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -1,4 +1,3 @@ -use std::borrow::Cow; use std::fmt::Display; use std::path::Path; @@ -121,8 +120,8 @@ impl Typed { } #[allow(dead_code)] - pub(crate) fn get_type(&self) -> Result, TypeError> { - Ok(Cow::Owned(self.0.get_type()?.into_owned().into_typed())) + pub(crate) fn get_type(&self) -> Result { + Ok(self.0.get_type()?.into_typed()) } } diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 996c26c..4abc314 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -31,7 +31,7 @@ fn tck_pi_type( _ => { return Err(TypeError::new( &ctx2, - InvalidOutputType(te.get_type()?.into_owned()), + InvalidOutputType(te.get_type()?), )) } }; @@ -312,7 +312,7 @@ fn type_with( let ctx2 = ctx.insert_type(x, tx.clone()); let b = type_with(&ctx2, b.clone())?; let v = ValueF::Lam(x.clone().into(), tx.clone(), b.clone()); - let tb = b.get_type()?.into_owned(); + let tb = b.get_type()?; let t = tck_pi_type(ctx, x.clone(), tx, tb)?; Value::from_valuef_and_type(v, t) } @@ -389,17 +389,17 @@ fn type_last_layer( ValueF::Pi(x, tx, tb) => (x, tx, tb), _ => return mkerr(NotAFunction(f.clone())), }; - if a.get_type()?.as_ref() != tx { + if &a.get_type()? != tx { return mkerr(TypeMismatch(f.clone(), tx.clone(), a.clone())); } RetTypeOnly(tb.subst_shift(&x.into(), a)) } Annot(x, t) => { - if t != x.get_type()?.as_ref() { + if &x.get_type()? != t { return mkerr(AnnotMismatch(x.clone(), t.clone())); } - RetTypeOnly(x.get_type()?.into_owned()) + RetTypeOnly(x.get_type()?) } Assert(t) => { match &*t.as_whnf() { @@ -412,7 +412,7 @@ fn type_last_layer( RetTypeOnly(t.clone()) } BoolIf(x, y, z) => { - if x.get_type()?.as_ref() != &builtin_to_value(Bool) { + if &*x.get_type()?.as_whnf() != &ValueF::from_builtin(Bool) { return mkerr(InvalidPredicate(x.clone())); } @@ -428,7 +428,7 @@ fn type_last_layer( return mkerr(IfBranchMismatch(y.clone(), z.clone())); } - RetTypeOnly(y.get_type()?.into_owned()) + RetTypeOnly(y.get_type()?) } EmptyListLit(t) => { match &*t.as_whnf() { @@ -445,24 +445,24 @@ fn type_last_layer( if x.get_type()? != y.get_type()? { return mkerr(InvalidListElement( i, - x.get_type()?.into_owned(), + x.get_type()?, y.clone(), )); } } let t = x.get_type()?; if t.get_type()?.as_const() != Some(Type) { - return mkerr(InvalidListType(t.into_owned())); + return mkerr(InvalidListType(t)); } RetTypeOnly( ValueF::from_builtin(dhall_syntax::Builtin::List) - .app(t.into_owned()) + .app(t) .into_value_simple_type(), ) } SomeLit(x) => { - let t = x.get_type()?.into_owned(); + let t = x.get_type()?; if t.get_type()?.as_const() != Some(Type) { return mkerr(InvalidOptionalType(t)); } @@ -483,8 +483,7 @@ fn type_last_layer( )?), RecordLit(kvs) => RetTypeOnly(tck_record_type( ctx, - kvs.iter() - .map(|(x, v)| Ok((x.clone(), v.get_type()?.into_owned()))), + kvs.iter().map(|(x, v)| Ok((x.clone(), v.get_type()?))), )?), Field(r, x) => { match &*r.get_type()?.as_whnf() { @@ -545,7 +544,7 @@ fn type_last_layer( for contents in interpolated.iter() { use InterpolatedTextContents::Expr; if let Expr(x) = contents { - if x.get_type()?.as_ref() != &text_type { + if x.get_type()? != text_type { return mkerr(InvalidTextInterpolation(x.clone())); } } @@ -586,8 +585,8 @@ fn type_last_layer( ctx, ExprF::BinOp( RecursiveRecordTypeMerge, - l.get_type()?.into_owned(), - r.get_type()?.into_owned(), + l.get_type()?, + r.get_type()?, ), )?), BinOp(RecursiveRecordTypeMerge, l, r) => { @@ -659,7 +658,7 @@ fn type_last_layer( return mkerr(BinOpTypeMismatch(*o, r.clone())); } - RetTypeOnly(l.get_type()?.into_owned()) + RetTypeOnly(l.get_type()?) } BinOp(Equivalence, l, r) => { if l.get_type()?.get_type()?.as_const() != Some(Type) { @@ -692,11 +691,11 @@ fn type_last_layer( Equivalence => unreachable!(), }); - if l.get_type()?.as_ref() != &t { + if l.get_type()? != t { return mkerr(BinOpTypeMismatch(*o, l.clone())); } - if r.get_type()?.as_ref() != &t { + if r.get_type()? != t { return mkerr(BinOpTypeMismatch(*o, r.clone())); } @@ -800,7 +799,7 @@ fn type_last_layer( RetTypeOnly(Value::from_valuef_and_type( ValueF::RecordType(new_kts), - record_type.get_type()?.into_owned(), + record_type.get_type()?, )) } }; -- cgit v1.2.3 From f70e45daef2570259eccd227a0126493c015d7b0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 21:50:47 +0200 Subject: Track evaluation status alongside ValueF in VoVF --- dhall/src/phase/normalize.rs | 72 ++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 32 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index e044018..a146ec7 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -70,29 +70,29 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { // Return Ok((unconsumed args, returned value)), or Err(()) if value could not be produced. let ret = match (b, args.as_slice()) { (OptionalNone, [t, r..]) => { - Ok((r, EmptyOptionalLit(t.clone()).into_vovf())) + Ok((r, EmptyOptionalLit(t.clone()).into_vovf_whnf())) } (NaturalIsZero, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, BoolLit(*n == 0).into_vovf())), + NaturalLit(n) => Ok((r, BoolLit(*n == 0).into_vovf_nf())), _ => Err(()), }, (NaturalEven, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, BoolLit(*n % 2 == 0).into_vovf())), + NaturalLit(n) => Ok((r, BoolLit(*n % 2 == 0).into_vovf_nf())), _ => Err(()), }, (NaturalOdd, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, BoolLit(*n % 2 != 0).into_vovf())), + NaturalLit(n) => Ok((r, BoolLit(*n % 2 != 0).into_vovf_nf())), _ => Err(()), }, (NaturalToInteger, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, IntegerLit(*n as isize).into_vovf())), + NaturalLit(n) => Ok((r, IntegerLit(*n as isize).into_vovf_nf())), _ => Err(()), }, (NaturalShow, [n, r..]) => match &*n.as_whnf() { NaturalLit(n) => Ok(( r, TextLit(vec![InterpolatedTextContents::Text(n.to_string())]) - .into_vovf(), + .into_vovf_nf(), )), _ => Err(()), }, @@ -100,11 +100,11 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { match (&*a.as_whnf(), &*b.as_whnf()) { (NaturalLit(a), NaturalLit(b)) => Ok(( r, - NaturalLit(if b > a { b - a } else { 0 }).into_vovf(), + NaturalLit(if b > a { b - a } else { 0 }).into_vovf_nf(), )), (NaturalLit(0), _) => Ok((r, b.clone().into_vovf())), - (_, NaturalLit(0)) => Ok((r, NaturalLit(0).into_vovf())), - _ if a == b => Ok((r, NaturalLit(0).into_vovf())), + (_, NaturalLit(0)) => Ok((r, NaturalLit(0).into_vovf_nf())), + _ if a == b => Ok((r, NaturalLit(0).into_vovf_nf())), _ => Err(()), } } @@ -118,14 +118,14 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { Ok(( r, TextLit(vec![InterpolatedTextContents::Text(s)]) - .into_vovf(), + .into_vovf_nf(), )) } _ => Err(()), }, (IntegerToDouble, [n, r..]) => match &*n.as_whnf() { IntegerLit(n) => { - Ok((r, DoubleLit(NaiveDouble::from(*n as f64)).into_vovf())) + Ok((r, DoubleLit(NaiveDouble::from(*n as f64)).into_vovf_nf())) } _ => Err(()), }, @@ -133,7 +133,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { DoubleLit(n) => Ok(( r, TextLit(vec![InterpolatedTextContents::Text(n.to_string())]) - .into_vovf(), + .into_vovf_nf(), )), _ => Err(()), }, @@ -149,7 +149,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { Ok(( r, TextLit(vec![InterpolatedTextContents::Text(s)]) - .into_vovf(), + .into_vovf_nf(), )) } // If there are no interpolations (invariants ensure that when there are no @@ -165,7 +165,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { Ok(( r, TextLit(vec![InterpolatedTextContents::Text(s)]) - .into_vovf(), + .into_vovf_nf(), )) } _ => Err(()), @@ -174,32 +174,39 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { _ => Err(()), }, (ListLength, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(_) => Ok((r, NaturalLit(0).into_vovf())), - NEListLit(xs) => Ok((r, NaturalLit(xs.len()).into_vovf())), + EmptyListLit(_) => Ok((r, NaturalLit(0).into_vovf_nf())), + NEListLit(xs) => Ok((r, NaturalLit(xs.len()).into_vovf_nf())), _ => Err(()), }, (ListHead, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()).into_vovf())), + EmptyListLit(n) => { + Ok((r, EmptyOptionalLit(n.clone()).into_vovf_whnf())) + } NEListLit(xs) => Ok(( r, - NEOptionalLit(xs.iter().next().unwrap().clone()).into_vovf(), + NEOptionalLit(xs.iter().next().unwrap().clone()) + .into_vovf_whnf(), )), _ => Err(()), }, (ListLast, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()).into_vovf())), + EmptyListLit(n) => { + Ok((r, EmptyOptionalLit(n.clone()).into_vovf_whnf())) + } NEListLit(xs) => Ok(( r, NEOptionalLit(xs.iter().rev().next().unwrap().clone()) - .into_vovf(), + .into_vovf_whnf(), )), _ => Err(()), }, (ListReverse, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(n) => Ok((r, EmptyListLit(n.clone()).into_vovf())), + EmptyListLit(n) => { + Ok((r, EmptyListLit(n.clone()).into_vovf_whnf())) + } NEListLit(xs) => Ok(( r, - NEListLit(xs.iter().rev().cloned().collect()).into_vovf(), + NEListLit(xs.iter().rev().cloned().collect()).into_vovf_whnf(), )), _ => Err(()), }, @@ -211,7 +218,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { Ok(( r, EmptyListLit(Value::from_valuef_untyped(RecordType(kts))) - .into_vovf(), + .into_vovf_whnf(), )) } NEListLit(xs) => { @@ -229,7 +236,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { Value::from_valuef_untyped(RecordLit(kvs)) }) .collect(); - Ok((r, NEListLit(xs).into_vovf())) + Ok((r, NEListLit(xs).into_vovf_whnf())) } _ => Err(()), }, @@ -353,13 +360,14 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { } v } - Err(()) => AppliedBuiltin(b, args).into_vovf(), + Err(()) => AppliedBuiltin(b, args).into_vovf_whnf(), } } pub(crate) fn apply_any(f: Value, a: Value) -> VoVF { - let fallback = - |f: Value, a: Value| ValueF::PartialExpr(ExprF::App(f, a)).into_vovf(); + let fallback = |f: Value, a: Value| { + ValueF::PartialExpr(ExprF::App(f, a)).into_vovf_whnf() + }; let f_borrow = f.as_whnf(); match &*f_borrow { @@ -370,7 +378,7 @@ pub(crate) fn apply_any(f: Value, a: Value) -> VoVF { apply_builtin(*b, args) } ValueF::UnionConstructor(l, kts) => { - ValueF::UnionLit(l.clone(), a, kts.clone()).into_vovf() + ValueF::UnionLit(l.clone(), a, kts.clone()).into_vovf_whnf() } _ => { drop(f_borrow); @@ -774,11 +782,11 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> VoVF { }; match ret { - Ret::ValueF(v) => v.into_vovf(), + Ret::ValueF(v) => v.into_vovf_whnf(), Ret::Value(v) => v.into_vovf(), Ret::VoVF(v) => v, Ret::ValueRef(v) => v.clone().into_vovf(), - Ret::Expr(expr) => ValueF::PartialExpr(expr).into_vovf(), + Ret::Expr(expr) => ValueF::PartialExpr(expr).into_vovf_whnf(), } } @@ -788,9 +796,9 @@ pub(crate) fn normalize_whnf(v: ValueF) -> VoVF { ValueF::AppliedBuiltin(b, args) => apply_builtin(b, args), ValueF::PartialExpr(e) => normalize_one_layer(e), ValueF::TextLit(elts) => { - ValueF::TextLit(squash_textlit(elts.into_iter())).into_vovf() + ValueF::TextLit(squash_textlit(elts.into_iter())).into_vovf_whnf() } // All other cases are already in WHNF - v => v.into_vovf(), + v => v.into_vovf_whnf(), } } -- cgit v1.2.3 From ec349d42703a8a31715cf97b44845ba3dd7a6805 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 22:20:59 +0200 Subject: Propagate type information in Value::app() --- dhall/src/phase/normalize.rs | 35 ++++++++++++++++------------------- dhall/src/phase/typecheck.rs | 10 ++-------- 2 files changed, 18 insertions(+), 27 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index a146ec7..e4a0c5b 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -34,7 +34,6 @@ macro_rules! make_closure { (List $($rest:tt)*) => { Value::from_builtin(Builtin::List) .app(make_closure!($($rest)*)) - .into_value_simple_type() }; (Some($($rest:tt)*)) => { ValueF::NEOptionalLit(make_closure!($($rest)*)) @@ -251,9 +250,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { } } _ => { - let list_t = Value::from_builtin(List) - .app(t.clone()) - .into_value_simple_type(); + let list_t = Value::from_builtin(List).app(t.clone()); Ok(( r, f.app(list_t.clone()) @@ -269,18 +266,19 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { .app( EmptyListLit(t.clone()) .into_value_with_type(list_t), - ), + ) + .into_vovf(), )) } }, (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_whnf() { EmptyListLit(_) => Ok((r, nil.clone().into_vovf())), NEListLit(xs) => { - let mut v = nil.clone().into_vovf(); + let mut v = nil.clone(); for x in xs.iter().cloned().rev() { - v = cons.app(x).app(v.into_value_untyped()); + v = cons.app(x).app(v); } - Ok((r, v)) + Ok((r, v.into_vovf())) } _ => Err(()), }, @@ -295,9 +293,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { } } _ => { - let optional_t = Value::from_builtin(Optional) - .app(t.clone()) - .into_value_simple_type(); + let optional_t = Value::from_builtin(Optional).app(t.clone()); Ok(( r, f.app(optional_t.clone()) @@ -305,13 +301,14 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { .app( EmptyOptionalLit(t.clone()) .into_value_with_type(optional_t), - ), + ) + .into_vovf(), )) } }, (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_whnf() { EmptyOptionalLit(_) => Ok((r, nothing.clone().into_vovf())), - NEOptionalLit(x) => Ok((r, just.app(x.clone()))), + NEOptionalLit(x) => Ok((r, just.app(x.clone()).into_vovf())), _ => Err(()), }, (NaturalBuild, [f, r..]) => match &*f.as_whnf() { @@ -331,7 +328,8 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { .app( NaturalLit(0) .into_value_with_type(Value::from_builtin(Natural)), - ), + ) + .into_vovf(), )), }, (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_whnf() { @@ -344,9 +342,8 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { ) .app(t.clone()) .app(succ.clone()) - .app(zero.clone()) - .into_value_with_type(t.clone()); - Ok((r, succ.app(fold))) + .app(zero.clone()); + Ok((r, succ.app(fold).into_vovf())) } _ => Err(()), }, @@ -643,7 +640,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> VoVF { ExprF::Lam(x, t, e) => Ret::ValueF(Lam(x.into(), t, e)), ExprF::Pi(x, t, e) => Ret::ValueF(Pi(x.into(), t, e)), ExprF::Let(x, _, v, b) => Ret::Value(b.subst_shift(&x.into(), &v)), - ExprF::App(v, a) => Ret::VoVF(v.app(a)), + ExprF::App(v, a) => Ret::Value(v.app(a)), ExprF::Builtin(b) => Ret::ValueF(ValueF::from_builtin(b)), ExprF::Const(c) => Ret::ValueF(ValueF::Const(c)), ExprF::BoolLit(b) => Ret::ValueF(BoolLit(b)), @@ -765,7 +762,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> VoVF { } }, (RecordLit(kvs), UnionLit(l, v, _)) => match kvs.get(l) { - Some(h) => Ret::VoVF(h.app(v.clone())), + Some(h) => Ret::Value(h.app(v.clone())), None => { drop(handlers_borrow); drop(variant_borrow); diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 4abc314..abe05a3 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -455,11 +455,7 @@ fn type_last_layer( return mkerr(InvalidListType(t)); } - RetTypeOnly( - ValueF::from_builtin(dhall_syntax::Builtin::List) - .app(t) - .into_value_simple_type(), - ) + RetTypeOnly(Value::from_builtin(dhall_syntax::Builtin::List).app(t)) } SomeLit(x) => { let t = x.get_type()?; @@ -468,9 +464,7 @@ fn type_last_layer( } RetTypeOnly( - Value::from_builtin(dhall_syntax::Builtin::Optional) - .app(t) - .into_value_simple_type(), + Value::from_builtin(dhall_syntax::Builtin::Optional).app(t), ) } RecordType(kts) => RetWhole(tck_record_type( -- cgit v1.2.3 From 8e68396e9fe3751bcf8bcfd68301ca7fea836787 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 22:35:53 +0200 Subject: Use Ret in apply_builtin --- dhall/src/phase/normalize.rs | 191 +++++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 90 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index e4a0c5b..0c4e185 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -10,6 +10,25 @@ use crate::core::valuef::ValueF; use crate::core::var::{Shift, Subst}; use crate::phase::Normalized; +// Small helper enum to avoid repetition +enum Ret<'a> { + ValueF(ValueF), + Value(Value), + ValueRef(&'a Value), + Expr(ExprF), +} + +impl<'a> Ret<'a> { + fn into_vovf_whnf(self) -> VoVF { + match self { + Ret::ValueF(v) => v.into_vovf_whnf(), + Ret::Value(v) => v.into_vovf(), + Ret::ValueRef(v) => v.clone().into_vovf(), + Ret::Expr(expr) => ValueF::PartialExpr(expr).into_vovf_whnf(), + } + } +} + // Ad-hoc macro to help construct closures macro_rules! make_closure { (#$var:ident) => { $var.clone() }; @@ -69,29 +88,30 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { // Return Ok((unconsumed args, returned value)), or Err(()) if value could not be produced. let ret = match (b, args.as_slice()) { (OptionalNone, [t, r..]) => { - Ok((r, EmptyOptionalLit(t.clone()).into_vovf_whnf())) + Ok((r, Ret::ValueF(EmptyOptionalLit(t.clone())))) } (NaturalIsZero, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, BoolLit(*n == 0).into_vovf_nf())), + NaturalLit(n) => Ok((r, Ret::ValueF(BoolLit(*n == 0)))), _ => Err(()), }, (NaturalEven, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, BoolLit(*n % 2 == 0).into_vovf_nf())), + NaturalLit(n) => Ok((r, Ret::ValueF(BoolLit(*n % 2 == 0)))), _ => Err(()), }, (NaturalOdd, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, BoolLit(*n % 2 != 0).into_vovf_nf())), + NaturalLit(n) => Ok((r, Ret::ValueF(BoolLit(*n % 2 != 0)))), _ => Err(()), }, (NaturalToInteger, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, IntegerLit(*n as isize).into_vovf_nf())), + NaturalLit(n) => Ok((r, Ret::ValueF(IntegerLit(*n as isize)))), _ => Err(()), }, (NaturalShow, [n, r..]) => match &*n.as_whnf() { NaturalLit(n) => Ok(( r, - TextLit(vec![InterpolatedTextContents::Text(n.to_string())]) - .into_vovf_nf(), + Ret::ValueF(TextLit(vec![InterpolatedTextContents::Text( + n.to_string(), + )])), )), _ => Err(()), }, @@ -99,11 +119,11 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { match (&*a.as_whnf(), &*b.as_whnf()) { (NaturalLit(a), NaturalLit(b)) => Ok(( r, - NaturalLit(if b > a { b - a } else { 0 }).into_vovf_nf(), + Ret::ValueF(NaturalLit(if b > a { b - a } else { 0 })), )), - (NaturalLit(0), _) => Ok((r, b.clone().into_vovf())), - (_, NaturalLit(0)) => Ok((r, NaturalLit(0).into_vovf_nf())), - _ if a == b => Ok((r, NaturalLit(0).into_vovf_nf())), + (NaturalLit(0), _) => Ok((r, Ret::ValueRef(b))), + (_, NaturalLit(0)) => Ok((r, Ret::ValueF(NaturalLit(0)))), + _ if a == b => Ok((r, Ret::ValueF(NaturalLit(0)))), _ => Err(()), } } @@ -116,23 +136,25 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { }; Ok(( r, - TextLit(vec![InterpolatedTextContents::Text(s)]) - .into_vovf_nf(), + Ret::ValueF(TextLit(vec![InterpolatedTextContents::Text( + s, + )])), )) } _ => Err(()), }, (IntegerToDouble, [n, r..]) => match &*n.as_whnf() { IntegerLit(n) => { - Ok((r, DoubleLit(NaiveDouble::from(*n as f64)).into_vovf_nf())) + Ok((r, Ret::ValueF(DoubleLit(NaiveDouble::from(*n as f64))))) } _ => Err(()), }, (DoubleShow, [n, r..]) => match &*n.as_whnf() { DoubleLit(n) => Ok(( r, - TextLit(vec![InterpolatedTextContents::Text(n.to_string())]) - .into_vovf_nf(), + Ret::ValueF(TextLit(vec![InterpolatedTextContents::Text( + n.to_string(), + )])), )), _ => Err(()), }, @@ -147,8 +169,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { let s = txt.to_string(); Ok(( r, - TextLit(vec![InterpolatedTextContents::Text(s)]) - .into_vovf_nf(), + Ret::ValueF(TextLit(vec![ + InterpolatedTextContents::Text(s), + ])), )) } // If there are no interpolations (invariants ensure that when there are no @@ -163,8 +186,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { let s = txt.to_string(); Ok(( r, - TextLit(vec![InterpolatedTextContents::Text(s)]) - .into_vovf_nf(), + Ret::ValueF(TextLit(vec![ + InterpolatedTextContents::Text(s), + ])), )) } _ => Err(()), @@ -173,39 +197,37 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { _ => Err(()), }, (ListLength, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(_) => Ok((r, NaturalLit(0).into_vovf_nf())), - NEListLit(xs) => Ok((r, NaturalLit(xs.len()).into_vovf_nf())), + EmptyListLit(_) => Ok((r, Ret::ValueF(NaturalLit(0)))), + NEListLit(xs) => Ok((r, Ret::ValueF(NaturalLit(xs.len())))), _ => Err(()), }, (ListHead, [_, l, r..]) => match &*l.as_whnf() { EmptyListLit(n) => { - Ok((r, EmptyOptionalLit(n.clone()).into_vovf_whnf())) + Ok((r, Ret::ValueF(EmptyOptionalLit(n.clone())))) } NEListLit(xs) => Ok(( r, - NEOptionalLit(xs.iter().next().unwrap().clone()) - .into_vovf_whnf(), + Ret::ValueF(NEOptionalLit(xs.iter().next().unwrap().clone())), )), _ => Err(()), }, (ListLast, [_, l, r..]) => match &*l.as_whnf() { EmptyListLit(n) => { - Ok((r, EmptyOptionalLit(n.clone()).into_vovf_whnf())) + Ok((r, Ret::ValueF(EmptyOptionalLit(n.clone())))) } NEListLit(xs) => Ok(( r, - NEOptionalLit(xs.iter().rev().next().unwrap().clone()) - .into_vovf_whnf(), + Ret::ValueF(NEOptionalLit( + xs.iter().rev().next().unwrap().clone(), + )), )), _ => Err(()), }, (ListReverse, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(n) => { - Ok((r, EmptyListLit(n.clone()).into_vovf_whnf())) - } + EmptyListLit(n) => Ok((r, Ret::ValueF(EmptyListLit(n.clone())))), NEListLit(xs) => Ok(( r, - NEListLit(xs.iter().rev().cloned().collect()).into_vovf_whnf(), + Ret::ValueF(NEListLit(xs.iter().rev().cloned().collect())), )), _ => Err(()), }, @@ -216,8 +238,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { kts.insert("value".into(), t.clone()); Ok(( r, - EmptyListLit(Value::from_valuef_untyped(RecordType(kts))) - .into_vovf_whnf(), + Ret::ValueF(EmptyListLit(Value::from_valuef_untyped( + RecordType(kts), + ))), )) } NEListLit(xs) => { @@ -235,7 +258,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { Value::from_valuef_untyped(RecordLit(kvs)) }) .collect(); - Ok((r, NEListLit(xs).into_vovf_whnf())) + Ok((r, Ret::ValueF(NEListLit(xs)))) } _ => Err(()), }, @@ -243,7 +266,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { // fold/build fusion ValueF::AppliedBuiltin(ListFold, args) => { if args.len() >= 2 { - Ok((r, args[1].clone().into_vovf())) + Ok((r, Ret::Value(args[1].clone()))) } else { // Do we really need to handle this case ? unimplemented!() @@ -253,32 +276,33 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { let list_t = Value::from_builtin(List).app(t.clone()); Ok(( r, - f.app(list_t.clone()) - .app({ - // Move `t` under new `x` variable - let t1 = t.under_binder(Label::from("x")); - make_closure!( - λ(x : #t) -> - λ(xs : List #t1) -> - [ var(x, 1) ] # var(xs, 0) - ) - }) - .app( - EmptyListLit(t.clone()) - .into_value_with_type(list_t), - ) - .into_vovf(), + Ret::Value( + f.app(list_t.clone()) + .app({ + // Move `t` under new `x` variable + let t1 = t.under_binder(Label::from("x")); + make_closure!( + λ(x : #t) -> + λ(xs : List #t1) -> + [ var(x, 1) ] # var(xs, 0) + ) + }) + .app( + EmptyListLit(t.clone()) + .into_value_with_type(list_t), + ), + ), )) } }, (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_whnf() { - EmptyListLit(_) => Ok((r, nil.clone().into_vovf())), + EmptyListLit(_) => Ok((r, Ret::ValueRef(nil))), NEListLit(xs) => { let mut v = nil.clone(); for x in xs.iter().cloned().rev() { v = cons.app(x).app(v); } - Ok((r, v.into_vovf())) + Ok((r, Ret::Value(v))) } _ => Err(()), }, @@ -286,7 +310,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { // fold/build fusion ValueF::AppliedBuiltin(OptionalFold, args) => { if args.len() >= 2 { - Ok((r, args[1].clone().into_vovf())) + Ok((r, Ret::Value(args[1].clone()))) } else { // Do we really need to handle this case ? unimplemented!() @@ -296,26 +320,27 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { let optional_t = Value::from_builtin(Optional).app(t.clone()); Ok(( r, - f.app(optional_t.clone()) - .app(make_closure!(λ(x: #t) -> Some(var(x, 0)))) - .app( - EmptyOptionalLit(t.clone()) - .into_value_with_type(optional_t), - ) - .into_vovf(), + Ret::Value( + f.app(optional_t.clone()) + .app(make_closure!(λ(x: #t) -> Some(var(x, 0)))) + .app( + EmptyOptionalLit(t.clone()) + .into_value_with_type(optional_t), + ), + ), )) } }, (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_whnf() { - EmptyOptionalLit(_) => Ok((r, nothing.clone().into_vovf())), - NEOptionalLit(x) => Ok((r, just.app(x.clone()).into_vovf())), + EmptyOptionalLit(_) => Ok((r, Ret::ValueRef(nothing))), + NEOptionalLit(x) => Ok((r, Ret::Value(just.app(x.clone())))), _ => Err(()), }, (NaturalBuild, [f, r..]) => match &*f.as_whnf() { // fold/build fusion ValueF::AppliedBuiltin(NaturalFold, args) => { if !args.is_empty() { - Ok((r, args[0].clone().into_vovf())) + Ok((r, Ret::Value(args[0].clone()))) } else { // Do we really need to handle this case ? unimplemented!() @@ -323,17 +348,17 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { } _ => Ok(( r, - f.app(Value::from_builtin(Natural)) - .app(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) - .app( - NaturalLit(0) - .into_value_with_type(Value::from_builtin(Natural)), - ) - .into_vovf(), + Ret::Value( + f.app(Value::from_builtin(Natural)) + .app(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) + .app(NaturalLit(0).into_value_with_type( + Value::from_builtin(Natural), + )), + ), )), }, (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_whnf() { - NaturalLit(0) => Ok((r, zero.clone().into_vovf())), + NaturalLit(0) => Ok((r, Ret::ValueRef(zero))), NaturalLit(n) => { let fold = Value::from_builtin(NaturalFold) .app( @@ -343,14 +368,15 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { .app(t.clone()) .app(succ.clone()) .app(zero.clone()); - Ok((r, succ.app(fold).into_vovf())) + Ok((r, Ret::Value(succ.app(fold)))) } _ => Err(()), }, _ => Err(()), }; match ret { - Ok((unconsumed_args, mut v)) => { + Ok((unconsumed_args, ret)) => { + let mut v = ret.into_vovf_whnf(); let n_consumed_args = args.len() - unconsumed_args.len(); for x in args.into_iter().skip(n_consumed_args) { v = v.app(x); @@ -485,15 +511,6 @@ where kvs } -// Small helper enum to avoid repetition -enum Ret<'a> { - ValueF(ValueF), - Value(Value), - VoVF(VoVF), - ValueRef(&'a Value), - Expr(ExprF), -} - fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { use BinOp::{ BoolAnd, BoolEQ, BoolNE, BoolOr, Equivalence, ListAppend, NaturalPlus, @@ -778,13 +795,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> VoVF { } }; - match ret { - Ret::ValueF(v) => v.into_vovf_whnf(), - Ret::Value(v) => v.into_vovf(), - Ret::VoVF(v) => v, - Ret::ValueRef(v) => v.clone().into_vovf(), - Ret::Expr(expr) => ValueF::PartialExpr(expr).into_vovf_whnf(), - } + ret.into_vovf_whnf() } /// Normalize a ValueF into WHNF -- cgit v1.2.3 From 8c1ffc5b68489be4694fff922ca48afeb0d45fc4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 23:02:56 +0200 Subject: Move type construction fns from serde_dhall to dhall --- dhall/src/phase/mod.rs | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index 1f80791..b5b7b64 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -1,7 +1,7 @@ use std::fmt::Display; use std::path::Path; -use dhall_syntax::{Const, SubExpr}; +use dhall_syntax::{Builtin, Const, SubExpr}; use crate::core::value::Value; use crate::core::valuef::ValueF; @@ -123,6 +123,39 @@ impl Typed { pub(crate) fn get_type(&self) -> Result { Ok(self.0.get_type()?.into_typed()) } + + pub fn make_builtin_type(b: Builtin) -> Self { + Typed::from_value(Value::from_builtin(b)) + } + pub fn make_optional_type(t: Typed) -> Self { + Typed::from_value( + Value::from_builtin(Builtin::Optional).app(t.to_value()), + ) + } + pub fn make_list_type(t: Typed) -> Self { + Typed::from_value(Value::from_builtin(Builtin::List).app(t.to_value())) + } + pub fn make_record_type( + kts: impl Iterator, + ) -> Self { + Typed::from_valuef_and_type( + ValueF::RecordType( + kts.map(|(k, t)| (k.into(), t.into_value())).collect(), + ), + Typed::const_type(), + ) + } + pub fn make_union_type( + kts: impl Iterator)>, + ) -> Self { + Typed::from_valuef_and_type( + ValueF::UnionType( + kts.map(|(k, t)| (k.into(), t.map(|t| t.into_value()))) + .collect(), + ), + Typed::const_type(), + ) + } } impl Normalized { -- cgit v1.2.3 From 6c006e122a050ebbe76c8c566e559bbf9f2301a7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 23:06:14 +0200 Subject: Reduce API surface of dhall crate --- dhall/src/phase/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index b5b7b64..ecf04e9 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -92,13 +92,13 @@ impl Typed { pub(crate) fn from_const(c: Const) -> Self { Typed(Value::from_const(c)) } - pub fn from_valuef_and_type(v: ValueF, t: Typed) -> Self { + pub(crate) fn from_valuef_and_type(v: ValueF, t: Typed) -> Self { Typed(Value::from_valuef_and_type(v, t.into_value())) } pub(crate) fn from_value(th: Value) -> Self { Typed(th) } - pub fn const_type() -> Self { + pub(crate) fn const_type() -> Self { Typed::from_const(Const::Type) } @@ -108,7 +108,7 @@ impl Typed { pub(crate) fn to_expr_alpha(&self) -> NormalizedSubExpr { self.0.to_expr_alpha() } - pub fn to_value(&self) -> Value { + pub(crate) fn to_value(&self) -> Value { self.0.clone() } pub(crate) fn into_value(self) -> Value { -- cgit v1.2.3 From d9e3bcca9b4350cbc1db2545d7ed28dde4e12be4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 23 Aug 2019 18:34:43 +0200 Subject: Keep type information after RecursiveRecordTypeMerge --- dhall/src/phase/normalize.rs | 75 ++++++++------------------------------------ dhall/src/phase/typecheck.rs | 37 ++++++---------------- 2 files changed, 23 insertions(+), 89 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 0c4e185..28dc0f6 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -452,53 +452,20 @@ pub(crate) fn squash_textlit( ret } -/// Performs an intersection of two HashMaps. -/// -/// # Arguments -/// -/// * `f` - Will compute the final value from the intersecting -/// key and the values from both maps. -/// -/// # Description -/// -/// If the key is present in both maps then the final value for -/// that key is computed via the `f` function. -/// -/// The final map will contain the shared keys from the -/// two input maps with the final computed value from `f`. -pub(crate) fn intersection_with_key( - mut f: impl FnMut(&K, &T, &U) -> V, - map1: &HashMap, - map2: &HashMap, -) -> HashMap -where - K: std::hash::Hash + Eq + Clone, -{ - let mut kvs = HashMap::new(); - - for (k, t) in map1 { - // Only insert in the final map if the key exists in both - if let Some(u) = map2.get(k) { - kvs.insert(k.clone(), f(k, t, u)); - } - } - - kvs -} - -pub(crate) fn merge_maps( +pub(crate) fn merge_maps( map1: &HashMap, map2: &HashMap, - mut f: impl FnMut(&V, &V) -> V, -) -> HashMap + mut f: F, +) -> Result, Err> where + F: FnMut(&V, &V) -> Result, K: std::hash::Hash + Eq + Clone, V: Clone, { let mut kvs = HashMap::new(); for (x, v2) in map2 { let newv = if let Some(v1) = map1.get(x) { - f(v1, v2) + f(v1, v2)? } else { v2.clone() }; @@ -508,7 +475,7 @@ where // Insert only if key not already present kvs.entry(x.clone()).or_insert_with(|| v1.clone()); } - kvs + Ok(kvs) } fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { @@ -518,8 +485,7 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { RightBiasedRecordMerge, TextAppend, }; use ValueF::{ - BoolLit, EmptyListLit, NEListLit, NaturalLit, RecordLit, RecordType, - TextLit, + BoolLit, EmptyListLit, NEListLit, NaturalLit, RecordLit, TextLit, }; let x_borrow = x.as_whnf(); let y_borrow = y.as_whnf(); @@ -604,31 +570,16 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { Ret::ValueRef(y) } (RecursiveRecordMerge, RecordLit(kvs1), RecordLit(kvs2)) => { - let kvs = merge_maps(kvs1, kvs2, |v1, v2| { - Value::from_valuef_untyped(ValueF::PartialExpr(ExprF::BinOp( - RecursiveRecordMerge, - v1.clone(), - v2.clone(), + let kvs = merge_maps::<_, _, _, !>(kvs1, kvs2, |v1, v2| { + Ok(Value::from_valuef_untyped(ValueF::PartialExpr( + ExprF::BinOp(RecursiveRecordMerge, v1.clone(), v2.clone()), ))) - }); + })?; Ret::ValueF(RecordLit(kvs)) } - (RecursiveRecordTypeMerge, _, RecordType(kvs)) if kvs.is_empty() => { - Ret::ValueRef(x) - } - (RecursiveRecordTypeMerge, RecordType(kvs), _) if kvs.is_empty() => { - Ret::ValueRef(y) - } - (RecursiveRecordTypeMerge, RecordType(kvs1), RecordType(kvs2)) => { - let kvs = merge_maps(kvs1, kvs2, |v1, v2| { - Value::from_valuef_untyped(ValueF::PartialExpr(ExprF::BinOp( - RecursiveRecordTypeMerge, - v1.clone(), - v2.clone(), - ))) - }); - Ret::ValueF(RecordType(kvs)) + (RecursiveRecordTypeMerge, _, _) => { + unreachable!("This case should have been handled in typecheck") } (Equivalence, _, _) => { diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index abe05a3..363d733 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -567,7 +567,9 @@ fn type_last_layer( // Union the two records, prefering // the values found in the RHS. - let kts = merge_maps(kts_x, kts_y, |_, r_t| r_t.clone()); + let kts = merge_maps::<_, _, _, !>(kts_x, kts_y, |_, r_t| { + Ok(r_t.clone()) + })?; // Construct the final record type from the union RetTypeOnly(tck_record_type( @@ -584,25 +586,7 @@ fn type_last_layer( ), )?), BinOp(RecursiveRecordTypeMerge, l, r) => { - use crate::phase::normalize::intersection_with_key; - - // Extract the Const of the LHS - let k_l = match l.get_type()?.as_const() { - Some(k) => k, - _ => { - return mkerr(RecordTypeMergeRequiresRecordType(l.clone())) - } - }; - - // Extract the Const of the RHS - let k_r = match r.get_type()?.as_const() { - Some(k) => k, - _ => { - return mkerr(RecordTypeMergeRequiresRecordType(r.clone())) - } - }; - - let k = max(k_l, k_r); + use crate::phase::normalize::merge_maps; // Extract the LHS record type let borrow_l = l.as_whnf(); @@ -623,9 +607,11 @@ fn type_last_layer( }; // Ensure that the records combine without a type error - let kts = intersection_with_key( + let kts = merge_maps( + kts_x, + kts_y, // If the Label exists for both records, then we hit the recursive case. - |_: &Label, l: &Value, r: &Value| { + |l: &Value, r: &Value| { type_last_layer( ctx, ExprF::BinOp( @@ -635,12 +621,9 @@ fn type_last_layer( ), ) }, - kts_x, - kts_y, - ); - tck_record_type(ctx, kts.into_iter().map(|(x, v)| Ok((x, v?))))?; + )?; - RetTypeOnly(Value::from_const(k)) + RetWhole(tck_record_type(ctx, kts.into_iter().map(Ok))?) } BinOp(o @ ListAppend, l, r) => { match &*l.get_type()?.as_whnf() { -- cgit v1.2.3 From d5bdd48d4c34b4e213e3e2431936c160e4320a80 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 23 Aug 2019 18:53:46 +0200 Subject: Clarify which syntax elements are completely handled in the tck phase --- dhall/src/phase/normalize.rs | 40 ++++++++++++++++++---------------------- dhall/src/phase/typecheck.rs | 9 ++++++--- 2 files changed, 24 insertions(+), 25 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 28dc0f6..c8f5bc2 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -578,39 +578,41 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { Ret::ValueF(RecordLit(kvs)) } - (RecursiveRecordTypeMerge, _, _) => { + (RecursiveRecordTypeMerge, _, _) | (Equivalence, _, _) => { unreachable!("This case should have been handled in typecheck") } - (Equivalence, _, _) => { - Ret::ValueF(ValueF::Equivalence(x.clone(), y.clone())) - } - _ => return None, }) } pub(crate) fn normalize_one_layer(expr: ExprF) -> VoVF { use ValueF::{ - AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, Lam, - NEListLit, NEOptionalLit, NaturalLit, Pi, RecordLit, RecordType, - TextLit, UnionConstructor, UnionLit, UnionType, + AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, + NEListLit, NEOptionalLit, NaturalLit, RecordLit, TextLit, + UnionConstructor, UnionLit, UnionType, }; let ret = match expr { ExprF::Import(_) => unreachable!( "There should remain no imports in a resolved expression" ), - ExprF::Embed(_) => unreachable!(), - ExprF::Var(_) => unreachable!(), - ExprF::Annot(x, _) => Ret::Value(x), + // Those cases have already been completely handled in the typechecking phase (using + // `RetWhole`), so they won't appear here. + ExprF::Lam(_, _, _) + | ExprF::Pi(_, _, _) + | ExprF::Let(_, _, _, _) + | ExprF::Embed(_) + | ExprF::Const(_) + | ExprF::Builtin(_) + | ExprF::Var(_) + | ExprF::Annot(_, _) + | ExprF::RecordType(_) + | ExprF::UnionType(_) => { + unreachable!("This case should have been handled in typecheck") + } ExprF::Assert(_) => Ret::Expr(expr), - ExprF::Lam(x, t, e) => Ret::ValueF(Lam(x.into(), t, e)), - ExprF::Pi(x, t, e) => Ret::ValueF(Pi(x.into(), t, e)), - ExprF::Let(x, _, v, b) => Ret::Value(b.subst_shift(&x.into(), &v)), ExprF::App(v, a) => Ret::Value(v.app(a)), - ExprF::Builtin(b) => Ret::ValueF(ValueF::from_builtin(b)), - ExprF::Const(c) => Ret::ValueF(ValueF::Const(c)), ExprF::BoolLit(b) => Ret::ValueF(BoolLit(b)), ExprF::NaturalLit(n) => Ret::ValueF(NaturalLit(n)), ExprF::IntegerLit(n) => Ret::ValueF(IntegerLit(n)), @@ -635,12 +637,6 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> VoVF { ExprF::RecordLit(kvs) => { Ret::ValueF(RecordLit(kvs.into_iter().collect())) } - ExprF::RecordType(kts) => { - Ret::ValueF(RecordType(kts.into_iter().collect())) - } - ExprF::UnionType(kts) => { - Ret::ValueF(UnionType(kts.into_iter().collect())) - } ExprF::TextLit(elts) => { use InterpolatedTextContents::Expr; let elts: Vec<_> = squash_textlit(elts.into_iter()); diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 363d733..0268b80 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -291,7 +291,7 @@ fn type_of_builtin(b: Builtin) -> Expr { pub(crate) fn builtin_to_value(b: Builtin) -> Value { let ctx = TypecheckContext::new(); Value::from_valuef_and_type( - ValueF::PartialExpr(ExprF::Builtin(b)), + ValueF::from_builtin(b), type_with(&ctx, rc(type_of_builtin(b))).unwrap(), ) } @@ -399,7 +399,7 @@ fn type_last_layer( if &x.get_type()? != t { return mkerr(AnnotMismatch(x.clone(), t.clone())); } - RetTypeOnly(x.get_type()?) + RetWhole(x.clone()) } Assert(t) => { match &*t.as_whnf() { @@ -649,7 +649,10 @@ fn type_last_layer( return mkerr(EquivalenceTypeMismatch(r.clone(), l.clone())); } - RetTypeOnly(Value::from_const(Type)) + RetWhole(Value::from_valuef_and_type( + ValueF::Equivalence(l.clone(), r.clone()), + Value::from_const(Type), + )) } BinOp(o, l, r) => { let t = builtin_to_value(match o { -- cgit v1.2.3 From 98399997cf289d802fbed674558665547cf73d59 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 25 Aug 2019 16:09:55 +0200 Subject: Keep type information through normalization --- dhall/src/phase/normalize.rs | 200 ++++++++++++++++++++++++++++--------------- dhall/src/phase/typecheck.rs | 21 ++--- 2 files changed, 142 insertions(+), 79 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index c8f5bc2..5743b0d 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use dhall_syntax::Const::Type; use dhall_syntax::{ BinOp, Builtin, ExprF, InterpolatedText, InterpolatedTextContents, Label, NaiveDouble, @@ -7,7 +8,7 @@ use dhall_syntax::{ use crate::core::value::{Value, VoVF}; use crate::core::valuef::ValueF; -use crate::core::var::{Shift, Subst}; +use crate::core::var::{AlphaLabel, Shift, Subst}; use crate::phase::Normalized; // Small helper enum to avoid repetition @@ -32,21 +33,24 @@ impl<'a> Ret<'a> { // Ad-hoc macro to help construct closures macro_rules! make_closure { (#$var:ident) => { $var.clone() }; - (var($var:ident, $n:expr)) => {{ + (var($var:ident, $n:expr, $($ty:tt)*)) => {{ let var = crate::core::var::AlphaVar::from_var_and_alpha( Label::from(stringify!($var)).into(), $n ); - ValueF::Var(var).into_value_untyped() + ValueF::Var(var) + .into_value_with_type(make_closure!($($ty)*)) }}; // Warning: assumes that $ty, as a dhall value, has type `Type` - (λ($var:ident : $($ty:tt)*) -> $($rest:tt)*) => { - ValueF::Lam( - Label::from(stringify!($var)).into(), - make_closure!($($ty)*), - make_closure!($($rest)*), - ).into_value_untyped() - }; + (λ($var:ident : $($ty:tt)*) -> $($body:tt)*) => {{ + let var: AlphaLabel = Label::from(stringify!($var)).into(); + let ty = make_closure!($($ty)*); + let body = make_closure!($($body)*); + let body_ty = body.get_type().expect("Internal type error"); + let lam_ty = ValueF::Pi(var.clone(), ty.clone(), body_ty) + .into_value_with_type(Value::from_const(Type)); + ValueF::Lam(var, ty, body).into_value_with_type(lam_ty) + }}; (Natural) => { Value::from_builtin(Builtin::Natural) }; @@ -54,10 +58,12 @@ macro_rules! make_closure { Value::from_builtin(Builtin::List) .app(make_closure!($($rest)*)) }; - (Some($($rest:tt)*)) => { - ValueF::NEOptionalLit(make_closure!($($rest)*)) - .into_value_untyped() - }; + (Some($($rest:tt)*)) => {{ + let v = make_closure!($($rest)*); + let v_type = v.get_type().expect("Internal type error"); + ValueF::NEOptionalLit(v) + .into_value_with_type(v_type) + }}; (1 + $($rest:tt)*) => { ValueF::PartialExpr(ExprF::BinOp( dhall_syntax::BinOp::NaturalPlus, @@ -70,18 +76,25 @@ macro_rules! make_closure { make_closure!(Natural) ) }; - ([ $($head:tt)* ] # $($tail:tt)*) => { + ([ $($head:tt)* ] # $($tail:tt)*) => {{ + let head = make_closure!($($head)*); + let tail = make_closure!($($tail)*); + let list_type = tail.get_type().expect("Internal type error"); ValueF::PartialExpr(ExprF::BinOp( dhall_syntax::BinOp::ListAppend, - ValueF::NEListLit(vec![make_closure!($($head)*)]) - .into_value_untyped(), - make_closure!($($tail)*), - )).into_value_untyped() - }; + ValueF::NEListLit(vec![head]) + .into_value_with_type(list_type.clone()), + tail, + )).into_value_with_type(list_type) + }}; } #[allow(clippy::cognitive_complexity)] -pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { +pub(crate) fn apply_builtin( + b: Builtin, + args: Vec, + _ty: Option<&Value>, +) -> VoVF { use dhall_syntax::Builtin::*; use ValueF::*; @@ -231,37 +244,60 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { )), _ => Err(()), }, - (ListIndexed, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(t) => { - let mut kts = HashMap::new(); - kts.insert("index".into(), Value::from_builtin(Natural)); - kts.insert("value".into(), t.clone()); - Ok(( - r, - Ret::ValueF(EmptyListLit(Value::from_valuef_untyped( + (ListIndexed, [_, l, r..]) => { + let l_whnf = l.as_whnf(); + match &*l_whnf { + EmptyListLit(_) | NEListLit(_) => { + // Extract the type of the list elements + let t = match &*l_whnf { + EmptyListLit(t) => t.clone(), + NEListLit(xs) => { + xs[0].get_type().expect("Internal type error") + } + _ => unreachable!(), + }; + + // Construct the returned record type: { index: Natural, value: t } + let mut kts = HashMap::new(); + kts.insert("index".into(), Value::from_builtin(Natural)); + kts.insert("value".into(), t.clone()); + let t = Value::from_valuef_and_type( RecordType(kts), - ))), - )) - } - NEListLit(xs) => { - let xs = xs - .iter() - .enumerate() - .map(|(i, e)| { - let i = NaturalLit(i); - let mut kvs = HashMap::new(); - kvs.insert( - "index".into(), - Value::from_valuef_untyped(i), - ); - kvs.insert("value".into(), e.clone()); - Value::from_valuef_untyped(RecordLit(kvs)) - }) - .collect(); - Ok((r, Ret::ValueF(NEListLit(xs)))) + Value::from_const(Type), + ); + + // Construct the new list, with added indices + let list = match &*l_whnf { + EmptyListLit(_) => EmptyListLit(t), + NEListLit(xs) => NEListLit( + xs.iter() + .enumerate() + .map(|(i, e)| { + let mut kvs = HashMap::new(); + kvs.insert( + "index".into(), + Value::from_valuef_and_type( + NaturalLit(i), + Value::from_builtin( + Builtin::Natural, + ), + ), + ); + kvs.insert("value".into(), e.clone()); + Value::from_valuef_and_type( + RecordLit(kvs), + t.clone(), + ) + }) + .collect(), + ), + _ => unreachable!(), + }; + Ok((r, Ret::ValueF(list))) + } + _ => Err(()), } - _ => Err(()), - }, + } (ListBuild, [t, f, r..]) => match &*f.as_whnf() { // fold/build fusion ValueF::AppliedBuiltin(ListFold, args) => { @@ -279,12 +315,13 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { Ret::Value( f.app(list_t.clone()) .app({ - // Move `t` under new `x` variable + // Move `t` under new variables let t1 = t.under_binder(Label::from("x")); + let t2 = t1.under_binder(Label::from("xs")); make_closure!( λ(x : #t) -> λ(xs : List #t1) -> - [ var(x, 1) ] # var(xs, 0) + [ var(x, 1, #t2) ] # var(xs, 0, List #t2) ) }) .app( @@ -322,7 +359,10 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { r, Ret::Value( f.app(optional_t.clone()) - .app(make_closure!(λ(x: #t) -> Some(var(x, 0)))) + .app({ + let t1 = t.under_binder(Label::from("x")); + make_closure!(λ(x: #t) -> Some(var(x, 0, #t1))) + }) .app( EmptyOptionalLit(t.clone()) .into_value_with_type(optional_t), @@ -350,7 +390,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { r, Ret::Value( f.app(Value::from_builtin(Natural)) - .app(make_closure!(λ(x : Natural) -> 1 + var(x, 0))) + .app(make_closure!( + λ(x : Natural) -> 1 + var(x, 0, Natural) + )) .app(NaturalLit(0).into_value_with_type( Value::from_builtin(Natural), )), @@ -387,7 +429,7 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec) -> VoVF { } } -pub(crate) fn apply_any(f: Value, a: Value) -> VoVF { +pub(crate) fn apply_any(f: Value, a: Value, ty: Option<&Value>) -> VoVF { let fallback = |f: Value, a: Value| { ValueF::PartialExpr(ExprF::App(f, a)).into_vovf_whnf() }; @@ -398,7 +440,7 @@ pub(crate) fn apply_any(f: Value, a: Value) -> VoVF { ValueF::AppliedBuiltin(b, args) => { use std::iter::once; let args = args.iter().cloned().chain(once(a.clone())).collect(); - apply_builtin(*b, args) + apply_builtin(*b, args, ty) } ValueF::UnionConstructor(l, kts) => { ValueF::UnionLit(l.clone(), a, kts.clone()).into_vovf_whnf() @@ -458,14 +500,14 @@ pub(crate) fn merge_maps( mut f: F, ) -> Result, Err> where - F: FnMut(&V, &V) -> Result, + F: FnMut(&K, &V, &V) -> Result, K: std::hash::Hash + Eq + Clone, V: Clone, { let mut kvs = HashMap::new(); for (x, v2) in map2 { let newv = if let Some(v1) = map1.get(x) { - f(v1, v2)? + f(x, v1, v2)? } else { v2.clone() }; @@ -478,14 +520,20 @@ where Ok(kvs) } -fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { +fn apply_binop<'a>( + o: BinOp, + x: &'a Value, + y: &'a Value, + ty: Option<&Value>, +) -> Option> { use BinOp::{ BoolAnd, BoolEQ, BoolNE, BoolOr, Equivalence, ListAppend, NaturalPlus, NaturalTimes, RecursiveRecordMerge, RecursiveRecordTypeMerge, RightBiasedRecordMerge, TextAppend, }; use ValueF::{ - BoolLit, EmptyListLit, NEListLit, NaturalLit, RecordLit, TextLit, + BoolLit, EmptyListLit, NEListLit, NaturalLit, RecordLit, RecordType, + TextLit, }; let x_borrow = x.as_whnf(); let y_borrow = y.as_whnf(); @@ -570,10 +618,21 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { Ret::ValueRef(y) } (RecursiveRecordMerge, RecordLit(kvs1), RecordLit(kvs2)) => { - let kvs = merge_maps::<_, _, _, !>(kvs1, kvs2, |v1, v2| { - Ok(Value::from_valuef_untyped(ValueF::PartialExpr( - ExprF::BinOp(RecursiveRecordMerge, v1.clone(), v2.clone()), - ))) + let ty = ty.expect("Internal type error"); + let ty_borrow = ty.as_whnf(); + let kts = match &*ty_borrow { + RecordType(kts) => kts, + _ => unreachable!("Internal type error"), + }; + let kvs = merge_maps::<_, _, _, !>(kvs1, kvs2, |k, v1, v2| { + Ok(Value::from_valuef_and_type( + ValueF::PartialExpr(ExprF::BinOp( + RecursiveRecordMerge, + v1.clone(), + v2.clone(), + )), + kts.get(k).expect("Internal type error").clone(), + )) })?; Ret::ValueF(RecordLit(kvs)) } @@ -586,7 +645,10 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { }) } -pub(crate) fn normalize_one_layer(expr: ExprF) -> VoVF { +pub(crate) fn normalize_one_layer( + expr: ExprF, + ty: Option<&Value>, +) -> VoVF { use ValueF::{ AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, NEListLit, NEOptionalLit, NaturalLit, RecordLit, TextLit, @@ -669,7 +731,7 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> VoVF { } } } - ExprF::BinOp(o, ref x, ref y) => match apply_binop(o, x, y) { + ExprF::BinOp(o, ref x, ref y) => match apply_binop(o, x, y, ty) { Some(ret) => ret, None => Ret::Expr(expr), }, @@ -746,10 +808,10 @@ pub(crate) fn normalize_one_layer(expr: ExprF) -> VoVF { } /// Normalize a ValueF into WHNF -pub(crate) fn normalize_whnf(v: ValueF) -> VoVF { +pub(crate) fn normalize_whnf(v: ValueF, ty: Option<&Value>) -> VoVF { match v { - ValueF::AppliedBuiltin(b, args) => apply_builtin(b, args), - ValueF::PartialExpr(e) => normalize_one_layer(e), + ValueF::AppliedBuiltin(b, args) => apply_builtin(b, args, ty), + ValueF::PartialExpr(e) => normalize_one_layer(e, ty), ValueF::TextLit(elts) => { ValueF::TextLit(squash_textlit(elts.into_iter())).into_vovf_whnf() } diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 0268b80..270191a 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -307,14 +307,15 @@ fn type_with( use dhall_syntax::ExprF::{Annot, Embed, Lam, Let, Pi, Var}; Ok(match e.as_ref() { - Lam(x, t, b) => { - let tx = type_with(ctx, t.clone())?; - let ctx2 = ctx.insert_type(x, tx.clone()); - let b = type_with(&ctx2, b.clone())?; - let v = ValueF::Lam(x.clone().into(), tx.clone(), b.clone()); - let tb = b.get_type()?; - let t = tck_pi_type(ctx, x.clone(), tx, tb)?; - Value::from_valuef_and_type(v, t) + Lam(var, annot, body) => { + let annot = type_with(ctx, annot.clone())?; + let ctx2 = ctx.insert_type(var, annot.clone()); + let body = type_with(&ctx2, body.clone())?; + let body_type = body.get_type()?; + Value::from_valuef_and_type( + ValueF::Lam(var.clone().into(), annot.clone(), body), + tck_pi_type(ctx, var.clone(), annot, body_type)?, + ) } Pi(x, ta, tb) => { let ta = type_with(ctx, ta.clone())?; @@ -567,7 +568,7 @@ fn type_last_layer( // Union the two records, prefering // the values found in the RHS. - let kts = merge_maps::<_, _, _, !>(kts_x, kts_y, |_, r_t| { + let kts = merge_maps::<_, _, _, !>(kts_x, kts_y, |_, _, r_t| { Ok(r_t.clone()) })?; @@ -611,7 +612,7 @@ fn type_last_layer( kts_x, kts_y, // If the Label exists for both records, then we hit the recursive case. - |l: &Value, r: &Value| { + |_, l: &Value, r: &Value| { type_last_layer( ctx, ExprF::BinOp( -- cgit v1.2.3 From 80fb5355ea90377492b9863f632c01a808f8aade Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 25 Aug 2019 16:33:12 +0200 Subject: Check consistency of type information --- dhall/src/phase/normalize.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 5743b0d..fe99696 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -61,8 +61,8 @@ macro_rules! make_closure { (Some($($rest:tt)*)) => {{ let v = make_closure!($($rest)*); let v_type = v.get_type().expect("Internal type error"); - ValueF::NEOptionalLit(v) - .into_value_with_type(v_type) + let opt_v_type = Value::from_builtin(Builtin::Optional).app(v_type); + ValueF::NEOptionalLit(v).into_value_with_type(opt_v_type) }}; (1 + $($rest:tt)*) => { ValueF::PartialExpr(ExprF::BinOp( -- cgit v1.2.3 From f9ec2cdf2803ed92fa404db989b786fc1dfac12e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 25 Aug 2019 17:07:59 +0200 Subject: Enforce type information almost everywhere --- dhall/src/phase/normalize.rs | 25 +++++++++---------------- dhall/src/phase/typecheck.rs | 21 ++++++++------------- 2 files changed, 17 insertions(+), 29 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index fe99696..9837a8b 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -46,7 +46,7 @@ macro_rules! make_closure { let var: AlphaLabel = Label::from(stringify!($var)).into(); let ty = make_closure!($($ty)*); let body = make_closure!($($body)*); - let body_ty = body.get_type().expect("Internal type error"); + let body_ty = body.get_type_not_sort(); let lam_ty = ValueF::Pi(var.clone(), ty.clone(), body_ty) .into_value_with_type(Value::from_const(Type)); ValueF::Lam(var, ty, body).into_value_with_type(lam_ty) @@ -60,7 +60,7 @@ macro_rules! make_closure { }; (Some($($rest:tt)*)) => {{ let v = make_closure!($($rest)*); - let v_type = v.get_type().expect("Internal type error"); + let v_type = v.get_type_not_sort(); let opt_v_type = Value::from_builtin(Builtin::Optional).app(v_type); ValueF::NEOptionalLit(v).into_value_with_type(opt_v_type) }}; @@ -79,7 +79,7 @@ macro_rules! make_closure { ([ $($head:tt)* ] # $($tail:tt)*) => {{ let head = make_closure!($($head)*); let tail = make_closure!($($tail)*); - let list_type = tail.get_type().expect("Internal type error"); + let list_type = tail.get_type_not_sort(); ValueF::PartialExpr(ExprF::BinOp( dhall_syntax::BinOp::ListAppend, ValueF::NEListLit(vec![head]) @@ -90,11 +90,7 @@ macro_rules! make_closure { } #[allow(clippy::cognitive_complexity)] -pub(crate) fn apply_builtin( - b: Builtin, - args: Vec, - _ty: Option<&Value>, -) -> VoVF { +pub(crate) fn apply_builtin(b: Builtin, args: Vec, _ty: &Value) -> VoVF { use dhall_syntax::Builtin::*; use ValueF::*; @@ -251,9 +247,7 @@ pub(crate) fn apply_builtin( // Extract the type of the list elements let t = match &*l_whnf { EmptyListLit(t) => t.clone(), - NEListLit(xs) => { - xs[0].get_type().expect("Internal type error") - } + NEListLit(xs) => xs[0].get_type_not_sort(), _ => unreachable!(), }; @@ -429,7 +423,7 @@ pub(crate) fn apply_builtin( } } -pub(crate) fn apply_any(f: Value, a: Value, ty: Option<&Value>) -> VoVF { +pub(crate) fn apply_any(f: Value, a: Value, ty: &Value) -> VoVF { let fallback = |f: Value, a: Value| { ValueF::PartialExpr(ExprF::App(f, a)).into_vovf_whnf() }; @@ -524,7 +518,7 @@ fn apply_binop<'a>( o: BinOp, x: &'a Value, y: &'a Value, - ty: Option<&Value>, + ty: &Value, ) -> Option> { use BinOp::{ BoolAnd, BoolEQ, BoolNE, BoolOr, Equivalence, ListAppend, NaturalPlus, @@ -618,7 +612,6 @@ fn apply_binop<'a>( Ret::ValueRef(y) } (RecursiveRecordMerge, RecordLit(kvs1), RecordLit(kvs2)) => { - let ty = ty.expect("Internal type error"); let ty_borrow = ty.as_whnf(); let kts = match &*ty_borrow { RecordType(kts) => kts, @@ -647,7 +640,7 @@ fn apply_binop<'a>( pub(crate) fn normalize_one_layer( expr: ExprF, - ty: Option<&Value>, + ty: &Value, ) -> VoVF { use ValueF::{ AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, @@ -808,7 +801,7 @@ pub(crate) fn normalize_one_layer( } /// Normalize a ValueF into WHNF -pub(crate) fn normalize_whnf(v: ValueF, ty: Option<&Value>) -> VoVF { +pub(crate) fn normalize_whnf(v: ValueF, ty: &Value) -> VoVF { match v { ValueF::AppliedBuiltin(b, args) => apply_builtin(b, args, ty), ValueF::PartialExpr(e) => normalize_one_layer(e, ty), diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 270191a..ef2018a 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -129,21 +129,16 @@ fn function_check(a: Const, b: Const) -> Const { } } -fn type_of_const(c: Const) -> Result { - match c { - Const::Type => Ok(const_to_value(Const::Kind)), - Const::Kind => Ok(const_to_value(Const::Sort)), - Const::Sort => { - Err(TypeError::new(&TypecheckContext::new(), TypeMessage::Sort)) - } - } -} - pub(crate) fn const_to_value(c: Const) -> Value { let v = ValueF::Const(c); - match type_of_const(c) { - Ok(t) => Value::from_valuef_and_type(v, t), - Err(_) => Value::from_valuef_untyped(v), + match c { + Const::Type => { + Value::from_valuef_and_type(v, const_to_value(Const::Kind)) + } + Const::Kind => { + Value::from_valuef_and_type(v, const_to_value(Const::Sort)) + } + Const::Sort => Value::const_sort(), } } -- cgit v1.2.3 From bf37fd9da3782134ca4bca9567c34bbee81784b9 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 25 Aug 2019 21:16:38 +0200 Subject: Rework apply_builtin to enforce preservation of type information --- dhall/src/phase/normalize.rs | 339 ++++++++++++++++++++----------------------- 1 file changed, 156 insertions(+), 183 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 9837a8b..77f5023 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -11,25 +11,6 @@ use crate::core::valuef::ValueF; use crate::core::var::{AlphaLabel, Shift, Subst}; use crate::phase::Normalized; -// Small helper enum to avoid repetition -enum Ret<'a> { - ValueF(ValueF), - Value(Value), - ValueRef(&'a Value), - Expr(ExprF), -} - -impl<'a> Ret<'a> { - fn into_vovf_whnf(self) -> VoVF { - match self { - Ret::ValueF(v) => v.into_vovf_whnf(), - Ret::Value(v) => v.into_vovf(), - Ret::ValueRef(v) => v.clone().into_vovf(), - Ret::Expr(expr) => ValueF::PartialExpr(expr).into_vovf_whnf(), - } - } -} - // Ad-hoc macro to help construct closures macro_rules! make_closure { (#$var:ident) => { $var.clone() }; @@ -94,80 +75,77 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec, _ty: &Value) -> VoVF { use dhall_syntax::Builtin::*; use ValueF::*; - // Return Ok((unconsumed args, returned value)), or Err(()) if value could not be produced. + // Small helper enum + enum Ret<'a> { + ValueF(ValueF), + Value(Value), + // For applications that can return a function, it's important to keep the remaining + // arguments to apply them to the resulting function. + ValueWithRemainingArgs(&'a [Value], Value), + DoneAsIs, + } + let ret = match (b, args.as_slice()) { - (OptionalNone, [t, r..]) => { - Ok((r, Ret::ValueF(EmptyOptionalLit(t.clone())))) - } - (NaturalIsZero, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, Ret::ValueF(BoolLit(*n == 0)))), - _ => Err(()), + (OptionalNone, [t]) => Ret::ValueF(EmptyOptionalLit(t.clone())), + (NaturalIsZero, [n]) => match &*n.as_whnf() { + NaturalLit(n) => Ret::ValueF(BoolLit(*n == 0)), + _ => Ret::DoneAsIs, }, - (NaturalEven, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, Ret::ValueF(BoolLit(*n % 2 == 0)))), - _ => Err(()), + (NaturalEven, [n]) => match &*n.as_whnf() { + NaturalLit(n) => Ret::ValueF(BoolLit(*n % 2 == 0)), + _ => Ret::DoneAsIs, }, - (NaturalOdd, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, Ret::ValueF(BoolLit(*n % 2 != 0)))), - _ => Err(()), + (NaturalOdd, [n]) => match &*n.as_whnf() { + NaturalLit(n) => Ret::ValueF(BoolLit(*n % 2 != 0)), + _ => Ret::DoneAsIs, }, - (NaturalToInteger, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok((r, Ret::ValueF(IntegerLit(*n as isize)))), - _ => Err(()), + (NaturalToInteger, [n]) => match &*n.as_whnf() { + NaturalLit(n) => Ret::ValueF(IntegerLit(*n as isize)), + _ => Ret::DoneAsIs, }, - (NaturalShow, [n, r..]) => match &*n.as_whnf() { - NaturalLit(n) => Ok(( - r, + (NaturalShow, [n]) => match &*n.as_whnf() { + NaturalLit(n) => { Ret::ValueF(TextLit(vec![InterpolatedTextContents::Text( n.to_string(), - )])), - )), - _ => Err(()), + )])) + } + _ => Ret::DoneAsIs, }, - (NaturalSubtract, [a, b, r..]) => { - match (&*a.as_whnf(), &*b.as_whnf()) { - (NaturalLit(a), NaturalLit(b)) => Ok(( - r, - Ret::ValueF(NaturalLit(if b > a { b - a } else { 0 })), - )), - (NaturalLit(0), _) => Ok((r, Ret::ValueRef(b))), - (_, NaturalLit(0)) => Ok((r, Ret::ValueF(NaturalLit(0)))), - _ if a == b => Ok((r, Ret::ValueF(NaturalLit(0)))), - _ => Err(()), + (NaturalSubtract, [a, b]) => match (&*a.as_whnf(), &*b.as_whnf()) { + (NaturalLit(a), NaturalLit(b)) => { + Ret::ValueF(NaturalLit(if b > a { b - a } else { 0 })) } - } - (IntegerShow, [n, r..]) => match &*n.as_whnf() { + (NaturalLit(0), _) => Ret::Value(b.clone()), + (_, NaturalLit(0)) => Ret::ValueF(NaturalLit(0)), + _ if a == b => Ret::ValueF(NaturalLit(0)), + _ => Ret::DoneAsIs, + }, + (IntegerShow, [n]) => match &*n.as_whnf() { IntegerLit(n) => { let s = if *n < 0 { n.to_string() } else { format!("+{}", n) }; - Ok(( - r, - Ret::ValueF(TextLit(vec![InterpolatedTextContents::Text( - s, - )])), - )) + Ret::ValueF(TextLit(vec![InterpolatedTextContents::Text(s)])) } - _ => Err(()), + _ => Ret::DoneAsIs, }, - (IntegerToDouble, [n, r..]) => match &*n.as_whnf() { + (IntegerToDouble, [n]) => match &*n.as_whnf() { IntegerLit(n) => { - Ok((r, Ret::ValueF(DoubleLit(NaiveDouble::from(*n as f64))))) + Ret::ValueF(DoubleLit(NaiveDouble::from(*n as f64))) } - _ => Err(()), + _ => Ret::DoneAsIs, }, - (DoubleShow, [n, r..]) => match &*n.as_whnf() { - DoubleLit(n) => Ok(( - r, + (DoubleShow, [n]) => match &*n.as_whnf() { + DoubleLit(n) => { Ret::ValueF(TextLit(vec![InterpolatedTextContents::Text( n.to_string(), - )])), - )), - _ => Err(()), + )])) + } + _ => Ret::DoneAsIs, }, - (TextShow, [v, r..]) => match &*v.as_whnf() { + (TextShow, [v]) => match &*v.as_whnf() { TextLit(elts) => { match elts.as_slice() { // Empty string literal. @@ -176,12 +154,9 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec, _ty: &Value) -> VoVF { let txt: InterpolatedText = std::iter::empty().collect(); let s = txt.to_string(); - Ok(( - r, - Ret::ValueF(TextLit(vec![ - InterpolatedTextContents::Text(s), - ])), - )) + Ret::ValueF(TextLit(vec![ + InterpolatedTextContents::Text(s), + ])) } // If there are no interpolations (invariants ensure that when there are no // interpolations, there is a single Text item) in the literal. @@ -193,54 +168,42 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec, _ty: &Value) -> VoVF { )) .collect(); let s = txt.to_string(); - Ok(( - r, - Ret::ValueF(TextLit(vec![ - InterpolatedTextContents::Text(s), - ])), - )) + Ret::ValueF(TextLit(vec![ + InterpolatedTextContents::Text(s), + ])) } - _ => Err(()), + _ => Ret::DoneAsIs, } } - _ => Err(()), + _ => Ret::DoneAsIs, }, - (ListLength, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(_) => Ok((r, Ret::ValueF(NaturalLit(0)))), - NEListLit(xs) => Ok((r, Ret::ValueF(NaturalLit(xs.len())))), - _ => Err(()), + (ListLength, [_, l]) => match &*l.as_whnf() { + EmptyListLit(_) => Ret::ValueF(NaturalLit(0)), + NEListLit(xs) => Ret::ValueF(NaturalLit(xs.len())), + _ => Ret::DoneAsIs, }, - (ListHead, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(n) => { - Ok((r, Ret::ValueF(EmptyOptionalLit(n.clone())))) + (ListHead, [_, l]) => match &*l.as_whnf() { + EmptyListLit(n) => Ret::ValueF(EmptyOptionalLit(n.clone())), + NEListLit(xs) => { + Ret::ValueF(NEOptionalLit(xs.iter().next().unwrap().clone())) } - NEListLit(xs) => Ok(( - r, - Ret::ValueF(NEOptionalLit(xs.iter().next().unwrap().clone())), - )), - _ => Err(()), + _ => Ret::DoneAsIs, }, - (ListLast, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(n) => { - Ok((r, Ret::ValueF(EmptyOptionalLit(n.clone())))) - } - NEListLit(xs) => Ok(( - r, - Ret::ValueF(NEOptionalLit( - xs.iter().rev().next().unwrap().clone(), - )), + (ListLast, [_, l]) => match &*l.as_whnf() { + EmptyListLit(n) => Ret::ValueF(EmptyOptionalLit(n.clone())), + NEListLit(xs) => Ret::ValueF(NEOptionalLit( + xs.iter().rev().next().unwrap().clone(), )), - _ => Err(()), + _ => Ret::DoneAsIs, }, - (ListReverse, [_, l, r..]) => match &*l.as_whnf() { - EmptyListLit(n) => Ok((r, Ret::ValueF(EmptyListLit(n.clone())))), - NEListLit(xs) => Ok(( - r, - Ret::ValueF(NEListLit(xs.iter().rev().cloned().collect())), - )), - _ => Err(()), + (ListReverse, [_, l]) => match &*l.as_whnf() { + EmptyListLit(n) => Ret::ValueF(EmptyListLit(n.clone())), + NEListLit(xs) => { + Ret::ValueF(NEListLit(xs.iter().rev().cloned().collect())) + } + _ => Ret::DoneAsIs, }, - (ListIndexed, [_, l, r..]) => { + (ListIndexed, [_, l]) => { let l_whnf = l.as_whnf(); match &*l_whnf { EmptyListLit(_) | NEListLit(_) => { @@ -287,16 +250,16 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec, _ty: &Value) -> VoVF { ), _ => unreachable!(), }; - Ok((r, Ret::ValueF(list))) + Ret::ValueF(list) } - _ => Err(()), + _ => Ret::DoneAsIs, } } - (ListBuild, [t, f, r..]) => match &*f.as_whnf() { + (ListBuild, [t, f]) => match &*f.as_whnf() { // fold/build fusion ValueF::AppliedBuiltin(ListFold, args) => { if args.len() >= 2 { - Ok((r, Ret::Value(args[1].clone()))) + Ret::Value(args[1].clone()) } else { // Do we really need to handle this case ? unimplemented!() @@ -304,44 +267,41 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec, _ty: &Value) -> VoVF { } _ => { let list_t = Value::from_builtin(List).app(t.clone()); - Ok(( - r, - Ret::Value( - f.app(list_t.clone()) - .app({ - // Move `t` under new variables - let t1 = t.under_binder(Label::from("x")); - let t2 = t1.under_binder(Label::from("xs")); - make_closure!( - λ(x : #t) -> - λ(xs : List #t1) -> - [ var(x, 1, #t2) ] # var(xs, 0, List #t2) - ) - }) - .app( - EmptyListLit(t.clone()) - .into_value_with_type(list_t), - ), - ), - )) + Ret::Value( + f.app(list_t.clone()) + .app({ + // Move `t` under new variables + let t1 = t.under_binder(Label::from("x")); + let t2 = t1.under_binder(Label::from("xs")); + make_closure!( + λ(x : #t) -> + λ(xs : List #t1) -> + [ var(x, 1, #t2) ] # var(xs, 0, List #t2) + ) + }) + .app( + EmptyListLit(t.clone()) + .into_value_with_type(list_t), + ), + ) } }, (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_whnf() { - EmptyListLit(_) => Ok((r, Ret::ValueRef(nil))), + EmptyListLit(_) => Ret::ValueWithRemainingArgs(r, nil.clone()), NEListLit(xs) => { let mut v = nil.clone(); for x in xs.iter().cloned().rev() { v = cons.app(x).app(v); } - Ok((r, Ret::Value(v))) + Ret::ValueWithRemainingArgs(r, v) } - _ => Err(()), + _ => Ret::DoneAsIs, }, - (OptionalBuild, [t, f, r..]) => match &*f.as_whnf() { + (OptionalBuild, [t, f]) => match &*f.as_whnf() { // fold/build fusion ValueF::AppliedBuiltin(OptionalFold, args) => { if args.len() >= 2 { - Ok((r, Ret::Value(args[1].clone()))) + Ret::Value(args[1].clone()) } else { // Do we really need to handle this case ? unimplemented!() @@ -349,52 +309,51 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec, _ty: &Value) -> VoVF { } _ => { let optional_t = Value::from_builtin(Optional).app(t.clone()); - Ok(( - r, - Ret::Value( - f.app(optional_t.clone()) - .app({ - let t1 = t.under_binder(Label::from("x")); - make_closure!(λ(x: #t) -> Some(var(x, 0, #t1))) - }) - .app( - EmptyOptionalLit(t.clone()) - .into_value_with_type(optional_t), - ), - ), - )) + Ret::Value( + f.app(optional_t.clone()) + .app({ + let t1 = t.under_binder(Label::from("x")); + make_closure!(λ(x: #t) -> Some(var(x, 0, #t1))) + }) + .app( + EmptyOptionalLit(t.clone()) + .into_value_with_type(optional_t), + ), + ) } }, (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_whnf() { - EmptyOptionalLit(_) => Ok((r, Ret::ValueRef(nothing))), - NEOptionalLit(x) => Ok((r, Ret::Value(just.app(x.clone())))), - _ => Err(()), + EmptyOptionalLit(_) => { + Ret::ValueWithRemainingArgs(r, nothing.clone()) + } + NEOptionalLit(x) => { + Ret::ValueWithRemainingArgs(r, just.app(x.clone())) + } + _ => Ret::DoneAsIs, }, - (NaturalBuild, [f, r..]) => match &*f.as_whnf() { + (NaturalBuild, [f]) => match &*f.as_whnf() { // fold/build fusion ValueF::AppliedBuiltin(NaturalFold, args) => { if !args.is_empty() { - Ok((r, Ret::Value(args[0].clone()))) + Ret::Value(args[0].clone()) } else { // Do we really need to handle this case ? unimplemented!() } } - _ => Ok(( - r, - Ret::Value( - f.app(Value::from_builtin(Natural)) - .app(make_closure!( - λ(x : Natural) -> 1 + var(x, 0, Natural) - )) - .app(NaturalLit(0).into_value_with_type( - Value::from_builtin(Natural), - )), - ), - )), + _ => Ret::Value( + f.app(Value::from_builtin(Natural)) + .app(make_closure!( + λ(x : Natural) -> 1 + var(x, 0, Natural) + )) + .app( + NaturalLit(0) + .into_value_with_type(Value::from_builtin(Natural)), + ), + ), }, (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_whnf() { - NaturalLit(0) => Ok((r, Ret::ValueRef(zero))), + NaturalLit(0) => Ret::ValueWithRemainingArgs(r, zero.clone()), NaturalLit(n) => { let fold = Value::from_builtin(NaturalFold) .app( @@ -404,22 +363,23 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec, _ty: &Value) -> VoVF { .app(t.clone()) .app(succ.clone()) .app(zero.clone()); - Ok((r, Ret::Value(succ.app(fold)))) + Ret::ValueWithRemainingArgs(r, succ.app(fold)) } - _ => Err(()), + _ => Ret::DoneAsIs, }, - _ => Err(()), + _ => Ret::DoneAsIs, }; match ret { - Ok((unconsumed_args, ret)) => { - let mut v = ret.into_vovf_whnf(); + Ret::ValueF(v) => v.into_vovf_whnf(), + Ret::Value(v) => v.into_vovf(), + Ret::ValueWithRemainingArgs(unconsumed_args, mut v) => { let n_consumed_args = args.len() - unconsumed_args.len(); for x in args.into_iter().skip(n_consumed_args) { v = v.app(x); } - v + v.into_vovf() } - Err(()) => AppliedBuiltin(b, args).into_vovf_whnf(), + Ret::DoneAsIs => AppliedBuiltin(b, args).into_vovf_whnf(), } } @@ -514,6 +474,14 @@ where Ok(kvs) } +// Small helper enum to avoid repetition +enum Ret<'a> { + ValueF(ValueF), + Value(Value), + ValueRef(&'a Value), + Expr(ExprF), +} + fn apply_binop<'a>( o: BinOp, x: &'a Value, @@ -797,7 +765,12 @@ pub(crate) fn normalize_one_layer( } }; - ret.into_vovf_whnf() + match ret { + Ret::ValueF(v) => v.into_vovf_whnf(), + Ret::Value(v) => v.into_vovf(), + Ret::ValueRef(v) => v.clone().into_vovf(), + Ret::Expr(expr) => ValueF::PartialExpr(expr).into_vovf_whnf(), + } } /// Normalize a ValueF into WHNF -- cgit v1.2.3 From 906cbf5fc4c3bee65f24df1604497e33c6a20833 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 25 Aug 2019 21:52:59 +0200 Subject: Remove now unnecessary VoVF enum --- dhall/src/phase/normalize.rs | 46 +++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 77f5023..82a378c 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -6,7 +6,7 @@ use dhall_syntax::{ NaiveDouble, }; -use crate::core::value::{Value, VoVF}; +use crate::core::value::Value; use crate::core::valuef::ValueF; use crate::core::var::{AlphaLabel, Shift, Subst}; use crate::phase::Normalized; @@ -71,7 +71,11 @@ macro_rules! make_closure { } #[allow(clippy::cognitive_complexity)] -pub(crate) fn apply_builtin(b: Builtin, args: Vec, _ty: &Value) -> VoVF { +pub(crate) fn apply_builtin( + b: Builtin, + args: Vec, + ty: &Value, +) -> ValueF { use dhall_syntax::Builtin::*; use ValueF::*; @@ -370,38 +374,36 @@ pub(crate) fn apply_builtin(b: Builtin, args: Vec, _ty: &Value) -> VoVF { _ => Ret::DoneAsIs, }; match ret { - Ret::ValueF(v) => v.into_vovf_whnf(), - Ret::Value(v) => v.into_vovf(), + Ret::ValueF(v) => v, + Ret::Value(v) => v.to_whnf_check_type(ty), Ret::ValueWithRemainingArgs(unconsumed_args, mut v) => { let n_consumed_args = args.len() - unconsumed_args.len(); for x in args.into_iter().skip(n_consumed_args) { v = v.app(x); } - v.into_vovf() + v.to_whnf_check_type(ty) } - Ret::DoneAsIs => AppliedBuiltin(b, args).into_vovf_whnf(), + Ret::DoneAsIs => AppliedBuiltin(b, args), } } -pub(crate) fn apply_any(f: Value, a: Value, ty: &Value) -> VoVF { - let fallback = |f: Value, a: Value| { - ValueF::PartialExpr(ExprF::App(f, a)).into_vovf_whnf() - }; - +pub(crate) fn apply_any(f: Value, a: Value, ty: &Value) -> ValueF { let f_borrow = f.as_whnf(); match &*f_borrow { - ValueF::Lam(x, _, e) => e.subst_shift(&x.into(), &a).into_vovf(), + ValueF::Lam(x, _, e) => { + e.subst_shift(&x.into(), &a).to_whnf_check_type(ty) + } ValueF::AppliedBuiltin(b, args) => { use std::iter::once; let args = args.iter().cloned().chain(once(a.clone())).collect(); apply_builtin(*b, args, ty) } ValueF::UnionConstructor(l, kts) => { - ValueF::UnionLit(l.clone(), a, kts.clone()).into_vovf_whnf() + ValueF::UnionLit(l.clone(), a, kts.clone()) } _ => { drop(f_borrow); - fallback(f, a) + ValueF::PartialExpr(ExprF::App(f, a)) } } } @@ -609,7 +611,7 @@ fn apply_binop<'a>( pub(crate) fn normalize_one_layer( expr: ExprF, ty: &Value, -) -> VoVF { +) -> ValueF { use ValueF::{ AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, NEListLit, NEOptionalLit, NaturalLit, RecordLit, TextLit, @@ -766,22 +768,22 @@ pub(crate) fn normalize_one_layer( }; match ret { - Ret::ValueF(v) => v.into_vovf_whnf(), - Ret::Value(v) => v.into_vovf(), - Ret::ValueRef(v) => v.clone().into_vovf(), - Ret::Expr(expr) => ValueF::PartialExpr(expr).into_vovf_whnf(), + Ret::ValueF(v) => v, + Ret::Value(v) => v.to_whnf_check_type(ty), + Ret::ValueRef(v) => v.to_whnf_check_type(ty), + Ret::Expr(expr) => ValueF::PartialExpr(expr), } } /// Normalize a ValueF into WHNF -pub(crate) fn normalize_whnf(v: ValueF, ty: &Value) -> VoVF { +pub(crate) fn normalize_whnf(v: ValueF, ty: &Value) -> ValueF { match v { ValueF::AppliedBuiltin(b, args) => apply_builtin(b, args, ty), ValueF::PartialExpr(e) => normalize_one_layer(e, ty), ValueF::TextLit(elts) => { - ValueF::TextLit(squash_textlit(elts.into_iter())).into_vovf_whnf() + ValueF::TextLit(squash_textlit(elts.into_iter())) } // All other cases are already in WHNF - v => v.into_vovf_whnf(), + v => v, } } -- cgit v1.2.3 From 2df5c09242375ca29b7e95ac76de427c4f1518ed Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 26 Aug 2019 20:12:40 +0200 Subject: Tweak tests to avoid double compilation --- dhall/src/phase/mod.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index ecf04e9..ed608df 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -119,7 +119,6 @@ impl Typed { self.0.normalize_mut() } - #[allow(dead_code)] pub(crate) fn get_type(&self) -> Result { Ok(self.0.get_type()?.into_typed()) } @@ -166,7 +165,6 @@ impl Normalized { pub(crate) fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() } - #[allow(dead_code)] pub(crate) fn to_expr_alpha(&self) -> NormalizedSubExpr { self.0.to_expr_alpha() } -- cgit v1.2.3 From a981afc465f4279a7a4d6ce3ac5844e04846613b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 27 Aug 2019 22:58:20 +0200 Subject: clippy --- dhall/src/phase/mod.rs | 5 ++--- dhall/src/phase/typecheck.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index ed608df..bd8853a 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -221,9 +221,8 @@ impl std::hash::Hash for Normalized { where H: std::hash::Hasher, { - match self.encode() { - Ok(vec) => vec.hash(state), - Err(_) => {} + if let Ok(vec) = self.encode() { + vec.hash(state) } } } diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index ef2018a..ab6d882 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -408,7 +408,7 @@ fn type_last_layer( RetTypeOnly(t.clone()) } BoolIf(x, y, z) => { - if &*x.get_type()?.as_whnf() != &ValueF::from_builtin(Bool) { + if *x.get_type()?.as_whnf() != ValueF::from_builtin(Bool) { return mkerr(InvalidPredicate(x.clone())); } -- cgit v1.2.3 From a7363042a16364a6dafdd545f4069dcf04a4197e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 27 Aug 2019 23:18:13 +0200 Subject: Rename SubExpr to Expr, and Expr to RawExpr For clarity, and consistency with Value --- dhall/src/phase/binary.rs | 49 ++++++++++++++++++++------------------------ dhall/src/phase/mod.rs | 22 ++++++++++---------- dhall/src/phase/resolve.rs | 4 ++-- dhall/src/phase/typecheck.rs | 16 +++++++-------- 4 files changed, 43 insertions(+), 48 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index 3746635..7dc9be2 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -4,28 +4,26 @@ use std::iter::FromIterator; use dhall_syntax::map::DupTreeMap; use dhall_syntax::{ - rc, ExprF, FilePrefix, Hash, Import, ImportLocation, ImportMode, Integer, - InterpolatedText, Label, Natural, Scheme, SubExpr, URL, V, + rc, Expr, ExprF, FilePrefix, Hash, Import, ImportLocation, ImportMode, + Integer, InterpolatedText, Label, Natural, Scheme, URL, V, }; use crate::error::{DecodeError, EncodeError}; -use crate::phase::DecodedSubExpr; +use crate::phase::DecodedExpr; -pub(crate) fn decode(data: &[u8]) -> Result { +pub(crate) fn decode(data: &[u8]) -> Result { match serde_cbor::de::from_slice(data) { Ok(v) => cbor_value_to_dhall(&v), Err(e) => Err(DecodeError::CBORError(e)), } } -pub(crate) fn encode(expr: &SubExpr) -> Result, EncodeError> { +pub(crate) fn encode(expr: &Expr) -> Result, EncodeError> { serde_cbor::ser::to_vec(&Serialize::Expr(expr)) .map_err(|e| EncodeError::CBORError(e)) } -fn cbor_value_to_dhall( - data: &cbor::Value, -) -> Result { +fn cbor_value_to_dhall(data: &cbor::Value) -> Result { use cbor::Value::*; use dhall_syntax::{BinOp, Builtin, Const}; use ExprF::*; @@ -382,7 +380,7 @@ fn cbor_map_to_dhall_map<'a, T>( map: impl IntoIterator, ) -> Result where - T: FromIterator<(Label, DecodedSubExpr)>, + T: FromIterator<(Label, DecodedExpr)>, { map.into_iter() .map(|(k, v)| -> Result<(_, _), _> { @@ -399,7 +397,7 @@ fn cbor_map_to_dhall_opt_map<'a, T>( map: impl IntoIterator, ) -> Result where - T: FromIterator<(Label, Option)>, + T: FromIterator<(Label, Option)>, { map.into_iter() .map(|(k, v)| -> Result<(_, _), _> { @@ -416,10 +414,10 @@ where } enum Serialize<'a, E> { - Expr(&'a SubExpr), + Expr(&'a Expr), CBOR(cbor::Value), - RecordMap(&'a DupTreeMap>), - UnionMap(&'a DupTreeMap>>), + RecordMap(&'a DupTreeMap>), + UnionMap(&'a DupTreeMap>>), } macro_rules! count { @@ -439,7 +437,7 @@ macro_rules! ser_seq { }}; } -fn serialize_subexpr(ser: S, e: &SubExpr) -> Result +fn serialize_subexpr(ser: S, e: &Expr) -> Result where S: serde::ser::Serializer, { @@ -449,7 +447,7 @@ where use std::iter::once; use self::Serialize::{RecordMap, UnionMap}; - fn expr(x: &SubExpr) -> self::Serialize<'_, E> { + fn expr(x: &Expr) -> self::Serialize<'_, E> { self::Serialize::Expr(x) } let cbor = @@ -566,7 +564,7 @@ where fn serialize_import( ser: S, - import: &Import>, + import: &Import>, ) -> Result where S: serde::ser::Serializer, @@ -675,12 +673,9 @@ impl<'a, E> serde::ser::Serialize for Serialize<'a, E> { } fn collect_nested_applications<'a, E>( - e: &'a SubExpr, -) -> (&'a SubExpr, Vec<&'a SubExpr>) { - fn go<'a, E>( - e: &'a SubExpr, - vec: &mut Vec<&'a SubExpr>, - ) -> &'a SubExpr { + e: &'a Expr, +) -> (&'a Expr, Vec<&'a Expr>) { + fn go<'a, E>(e: &'a Expr, vec: &mut Vec<&'a Expr>) -> &'a Expr { match e.as_ref() { ExprF::App(f, a) => { vec.push(a); @@ -694,15 +689,15 @@ fn collect_nested_applications<'a, E>( (e, vec) } -type LetBinding<'a, E> = (&'a Label, &'a Option>, &'a SubExpr); +type LetBinding<'a, E> = (&'a Label, &'a Option>, &'a Expr); fn collect_nested_lets<'a, E>( - e: &'a SubExpr, -) -> (&'a SubExpr, Vec>) { + e: &'a Expr, +) -> (&'a Expr, Vec>) { fn go<'a, E>( - e: &'a SubExpr, + e: &'a Expr, vec: &mut Vec>, - ) -> &'a SubExpr { + ) -> &'a Expr { match e.as_ref() { ExprF::Let(l, t, v, e) => { vec.push((l, t, v)); diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index bd8853a..ecc9213 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -1,7 +1,7 @@ use std::fmt::Display; use std::path::Path; -use dhall_syntax::{Builtin, Const, SubExpr}; +use dhall_syntax::{Builtin, Const, Expr}; use crate::core::value::Value; use crate::core::valuef::ValueF; @@ -16,19 +16,19 @@ pub(crate) mod parse; pub(crate) mod resolve; pub(crate) mod typecheck; -pub type ParsedSubExpr = SubExpr; -pub type DecodedSubExpr = SubExpr; -pub type ResolvedSubExpr = SubExpr; -pub type NormalizedSubExpr = SubExpr; +pub type ParsedExpr = Expr; +pub type DecodedExpr = Expr; +pub type ResolvedExpr = Expr; +pub type NormalizedExpr = Expr; #[derive(Debug, Clone)] -pub struct Parsed(ParsedSubExpr, ImportRoot); +pub struct Parsed(ParsedExpr, ImportRoot); /// An expression where all imports have been resolved /// /// Invariant: there must be no `Import` nodes or `ImportAlt` operations left. #[derive(Debug, Clone)] -pub struct Resolved(ResolvedSubExpr); +pub struct Resolved(ResolvedExpr); /// A typed expression #[derive(Debug, Clone)] @@ -102,10 +102,10 @@ impl Typed { Typed::from_const(Const::Type) } - pub fn to_expr(&self) -> NormalizedSubExpr { + pub fn to_expr(&self) -> NormalizedExpr { self.0.to_expr() } - pub(crate) fn to_expr_alpha(&self) -> NormalizedSubExpr { + pub(crate) fn to_expr_alpha(&self) -> NormalizedExpr { self.0.to_expr_alpha() } pub(crate) fn to_value(&self) -> Value { @@ -162,10 +162,10 @@ impl Normalized { crate::phase::binary::encode(&self.to_expr()) } - pub(crate) fn to_expr(&self) -> NormalizedSubExpr { + pub(crate) fn to_expr(&self) -> NormalizedExpr { self.0.to_expr() } - pub(crate) fn to_expr_alpha(&self) -> NormalizedSubExpr { + pub(crate) fn to_expr_alpha(&self) -> NormalizedExpr { self.0.to_expr_alpha() } pub(crate) fn into_typed(self) -> Typed { diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs index 27ae7a3..b715e72 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/phase/resolve.rs @@ -2,9 +2,9 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use crate::error::{Error, ImportError}; -use crate::phase::{Normalized, NormalizedSubExpr, Parsed, Resolved}; +use crate::phase::{Normalized, NormalizedExpr, Parsed, Resolved}; -type Import = dhall_syntax::Import; +type Import = dhall_syntax::Import; /// A root from which to resolve relative imports. #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index ab6d882..52a4e47 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -2,7 +2,7 @@ use std::cmp::max; use std::collections::HashMap; use dhall_syntax::{ - rc, Builtin, Const, Expr, ExprF, InterpolatedTextContents, Label, SubExpr, + rc, Builtin, Const, Expr, ExprF, InterpolatedTextContents, Label, }; use crate::core::context::TypecheckContext; @@ -200,7 +200,7 @@ macro_rules! make_type { fn type_of_builtin(b: Builtin) -> Expr { use dhall_syntax::Builtin::*; - match b { + rc(match b { Bool | Natural | Integer | Double | Text => make_type!(Type), List | Optional => make_type!( Type -> Type @@ -280,14 +280,14 @@ fn type_of_builtin(b: Builtin) -> Expr { OptionalNone => make_type!( forall (a: Type) -> Optional a ), - } + }) } pub(crate) fn builtin_to_value(b: Builtin) -> Value { let ctx = TypecheckContext::new(); Value::from_valuef_and_type( ValueF::from_builtin(b), - type_with(&ctx, rc(type_of_builtin(b))).unwrap(), + type_with(&ctx, type_of_builtin(b)).unwrap(), ) } @@ -297,7 +297,7 @@ pub(crate) fn builtin_to_value(b: Builtin) -> Value { /// normalized as well. fn type_with( ctx: &TypecheckContext, - e: SubExpr, + e: Expr, ) -> Result { use dhall_syntax::ExprF::{Annot, Embed, Lam, Let, Pi, Var}; @@ -791,13 +791,13 @@ fn type_last_layer( /// `type_of` is the same as `type_with` with an empty context, meaning that the /// expression must be closed (i.e. no free variables), otherwise type-checking /// will fail. -pub(crate) fn typecheck(e: SubExpr) -> Result { +pub(crate) fn typecheck(e: Expr) -> Result { type_with(&TypecheckContext::new(), e) } pub(crate) fn typecheck_with( - expr: SubExpr, - ty: SubExpr, + expr: Expr, + ty: Expr, ) -> Result { typecheck(expr.rewrap(ExprF::Annot(expr.clone(), ty))) } -- cgit v1.2.3 From 55c127e70eb484df486a45b25bcf03479eebda10 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 28 Aug 2019 13:49:27 +0200 Subject: Cleanup conversion of `Value` to `Expr` --- dhall/src/phase/mod.rs | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs index ecc9213..2c5505c 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/phase/mod.rs @@ -3,7 +3,7 @@ use std::path::Path; use dhall_syntax::{Builtin, Const, Expr}; -use crate::core::value::Value; +use crate::core::value::{ToExprOptions, Value}; use crate::core::valuef::ValueF; use crate::core::var::{AlphaVar, Shift, Subst}; use crate::error::{EncodeError, Error, ImportError, TypeError}; @@ -71,7 +71,8 @@ impl Resolved { Ok(typecheck::typecheck(self.0)?.into_typed()) } pub fn typecheck_with(self, ty: &Typed) -> Result { - Ok(typecheck::typecheck_with(self.0, ty.to_expr())?.into_typed()) + Ok(typecheck::typecheck_with(self.0, ty.normalize_to_expr())? + .into_typed()) } } @@ -102,11 +103,23 @@ impl Typed { Typed::from_const(Const::Type) } - pub fn to_expr(&self) -> NormalizedExpr { - self.0.to_expr() - } - pub(crate) fn to_expr_alpha(&self) -> NormalizedExpr { - self.0.to_expr_alpha() + pub(crate) fn to_expr(&self) -> NormalizedExpr { + self.0.to_expr(ToExprOptions { + alpha: false, + normalize: false, + }) + } + pub fn normalize_to_expr(&self) -> NormalizedExpr { + self.0.to_expr(ToExprOptions { + alpha: false, + normalize: true, + }) + } + pub(crate) fn normalize_to_expr_alpha(&self) -> NormalizedExpr { + self.0.to_expr(ToExprOptions { + alpha: true, + normalize: true, + }) } pub(crate) fn to_value(&self) -> Value { self.0.clone() @@ -163,10 +176,10 @@ impl Normalized { } pub(crate) fn to_expr(&self) -> NormalizedExpr { - self.0.to_expr() + self.0.normalize_to_expr() } pub(crate) fn to_expr_alpha(&self) -> NormalizedExpr { - self.0.to_expr_alpha() + self.0.normalize_to_expr_alpha() } pub(crate) fn into_typed(self) -> Typed { self.0 -- cgit v1.2.3 From a2c2cd76d256a4e6ca66b9b1bd756fb17e600ef5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 30 Aug 2019 20:05:12 +0200 Subject: Rework test harness to prepare for new types of tests --- dhall/src/phase/resolve.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs index b715e72..a58f5e4 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/phase/resolve.rs @@ -109,13 +109,22 @@ pub(crate) fn skip_resolve_expr( mod spec_tests { macro_rules! import_success { ($name:ident, $path:expr) => { - make_spec_test!(Import, Success, $name, &("../dhall-lang/tests/import/success/".to_owned() + $path)); + make_spec_test!( + ImportSuccess( + &("../dhall-lang/tests/import/success/".to_owned() + $path + "A.dhall"), + &("../dhall-lang/tests/import/success/".to_owned() + $path + "B.dhall") + ), + $name + ); }; } // macro_rules! import_failure { // ($name:ident, $path:expr) => { - // make_spec_test!(Import, Failure, $name, &("../dhall-lang/tests/import/failure/".to_owned() + $path)); + // make_spec_test!( + // ImportFailure(&("../dhall-lang/tests/import/failure/".to_owned() + $path + ".dhall")), + // $name + // ); // }; // } -- cgit v1.2.3 From aba7e62e49ac9dead0a2868f739091d2d15ff0d1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 31 Aug 2019 21:59:39 +0200 Subject: Implement parsing of `toMap` keyword --- dhall/src/phase/binary.rs | 11 +++++++++++ dhall/src/phase/normalize.rs | 1 + dhall/src/phase/typecheck.rs | 1 + 3 files changed, 13 insertions(+) (limited to 'dhall/src/phase') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index 7dc9be2..40219d9 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -366,6 +366,15 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { let y = cbor_value_to_dhall(&y)?; Annot(x, y) } + [U64(27), x] => { + let x = cbor_value_to_dhall(&x)?; + ToMap(x, None) + } + [U64(27), x, y] => { + let x = cbor_value_to_dhall(&x)?; + let y = cbor_value_to_dhall(&y)?; + ToMap(x, Some(y)) + } [U64(28), x] => { let x = cbor_value_to_dhall(&x)?; EmptyListLit(x) @@ -550,6 +559,8 @@ where Merge(x, y, Some(z)) => { ser_seq!(ser; tag(6), expr(x), expr(y), expr(z)) } + ToMap(x, None) => ser_seq!(ser; tag(27), expr(x)), + ToMap(x, Some(y)) => ser_seq!(ser; tag(27), expr(x), expr(y)), Projection(x, ls) => ser.collect_seq( once(tag(10)) .chain(once(expr(x))) diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 82a378c..3f6e99c 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -765,6 +765,7 @@ pub(crate) fn normalize_one_layer( } } } + ExprF::ToMap(_, _) => unimplemented!("toMap"), }; match ret { diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index 52a4e47..9013c1f 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -757,6 +757,7 @@ fn type_last_layer( (None, None) => return mkerr(MergeEmptyNeedsAnnotation), } } + ToMap(_, _) => unimplemented!("toMap"), Projection(record, labels) => { let record_type = record.get_type()?; let record_borrow = record_type.as_whnf(); -- cgit v1.2.3