From db1375eccd1e6943b504cd54ed17eb8f4d19c25f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 6 Feb 2020 17:35:54 +0000 Subject: Remove most reliance on types stored in Value --- dhall/src/semantics/nze/env.rs | 23 ++++++++------ dhall/src/semantics/nze/normalize.rs | 8 ++--- dhall/src/semantics/nze/value.rs | 60 +++++++++++++++++++++--------------- dhall/src/semantics/tck/env.rs | 8 ++--- dhall/src/semantics/tck/typecheck.rs | 56 ++++++++++++++++++--------------- 5 files changed, 88 insertions(+), 67 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/nze/env.rs b/dhall/src/semantics/nze/env.rs index 0b22a8b..261e0b6 100644 --- a/dhall/src/semantics/nze/env.rs +++ b/dhall/src/semantics/nze/env.rs @@ -1,4 +1,4 @@ -use crate::semantics::{AlphaVar, Value, ValueKind}; +use crate::semantics::{AlphaVar, Type, Value, ValueKind}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum NzVar { @@ -11,9 +11,9 @@ pub(crate) enum NzVar { #[derive(Debug, Clone)] enum NzEnvItem { // Variable is bound with given type - Kept(Value), + Kept(Type), // Variable has been replaced by corresponding value - Replaced(Value), + Replaced(Value, Type), } #[derive(Debug, Clone)] @@ -49,28 +49,31 @@ impl NzEnv { NzEnv { items: Vec::new() } } - pub fn insert_type(&self, t: Value) -> Self { + pub fn insert_type(&self, ty: Type) -> Self { let mut env = self.clone(); - env.items.push(NzEnvItem::Kept(t)); + env.items.push(NzEnvItem::Kept(ty)); env } - pub fn insert_value(&self, e: Value) -> Self { + pub fn insert_value(&self, e: Value, ty: Type) -> Self { let mut env = self.clone(); - env.items.push(NzEnvItem::Replaced(e)); + env.items.push(NzEnvItem::Replaced(e, ty)); env } + pub fn insert_value_noty(&self, e: Value) -> Self { + let ty = e.get_type_not_sort(); + self.insert_value(e, ty) + } pub fn lookup_val(&self, var: &AlphaVar) -> ValueKind { let idx = self.items.len() - 1 - var.idx(); match &self.items[idx] { NzEnvItem::Kept(_) => ValueKind::Var(NzVar::new(idx)), - NzEnvItem::Replaced(x) => x.kind().clone(), + NzEnvItem::Replaced(x, _) => x.kind().clone(), } } pub fn lookup_ty(&self, var: &AlphaVar) -> Value { let idx = self.items.len() - 1 - var.idx(); match &self.items[idx] { - NzEnvItem::Kept(ty) => ty.clone(), - NzEnvItem::Replaced(x) => x.get_type().unwrap(), + NzEnvItem::Kept(ty) | NzEnvItem::Replaced(_, ty) => ty.clone(), } } } diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index a00b7ff..3a981f4 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -17,14 +17,14 @@ pub(crate) fn apply_any(f: Value, a: Value, ty: &Value) -> ValueKind { closure.apply(a).to_whnf_check_type(ty) } ValueKind::AppliedBuiltin(closure) => { - closure.apply(a, f.get_type().unwrap(), ty) + closure.apply(a, f.get_type_not_sort(), ty) } ValueKind::UnionConstructor(l, kts, uniont) => ValueKind::UnionLit( l.clone(), a, kts.clone(), uniont.clone(), - f.get_type().unwrap(), + f.get_type_not_sort(), ), _ => ValueKind::PartialExpr(ExprKind::App(f, a)), } @@ -349,7 +349,7 @@ pub(crate) fn normalize_one_layer( UnionType(kts) => Ret::ValueKind(UnionConstructor( l.clone(), kts.clone(), - v.get_type().unwrap(), + v.get_type_not_sort(), )), PartialExpr(ExprKind::BinOp( BinOp::RightBiasedRecordMerge, @@ -536,7 +536,7 @@ pub(crate) fn normalize_tyexpr_whnf(tye: &TyExpr, env: &NzEnv) -> ValueKind { } TyExprKind::Expr(ExprKind::Let(_, None, val, body)) => { let val = val.eval(env); - body.eval(&env.insert_value(val)).kind().clone() + body.eval(&env.insert_value_noty(val)).kind().clone() } TyExprKind::Expr(e) => { let ty = match tye.get_type() { diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index 607aa0d..203b479 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -3,13 +3,11 @@ use std::rc::Rc; use crate::error::{TypeError, TypeMessage}; use crate::semantics::nze::lazy; -use crate::semantics::Binder; use crate::semantics::{ apply_any, normalize_one_layer, normalize_tyexpr_whnf, squash_textlit, - TyEnv, + type_of_builtin, type_with, typecheck, Binder, BuiltinClosure, NzEnv, + NzVar, TyEnv, TyExpr, TyExprKind, VarEnv, }; -use crate::semantics::{type_of_builtin, typecheck, TyExpr, TyExprKind}; -use crate::semantics::{BuiltinClosure, NzEnv, NzVar, VarEnv}; use crate::syntax::{ BinOp, Builtin, Const, ExprKind, Integer, InterpolatedTextContents, Label, NaiveDouble, Natural, Span, @@ -119,11 +117,14 @@ impl Value { ) .into_value() } + pub(crate) fn const_kind() -> Value { + Value::from_const(Const::Kind) + } /// Construct a Value from a completely unnormalized expression. pub(crate) fn new_thunk(env: &NzEnv, tye: TyExpr) -> Value { ValueInternal::from_thunk( Thunk::new(env, tye.clone()), - tye.get_type().ok(), + Some(Value::const_kind()), tye.span().clone(), ) .into_value() @@ -137,24 +138,31 @@ impl Value { let env = NzEnv::new(); ValueInternal::from_thunk( Thunk::from_partial_expr(env, e, ty.clone()), - Some(ty), + Some(Value::const_kind()), Span::Artificial, ) .into_value() } /// Make a Value from a ValueKind pub(crate) fn from_kind_and_type(v: ValueKind, t: Value) -> Value { - ValueInternal::from_whnf(v, Some(t), Span::Artificial).into_value() + ValueInternal::from_whnf(v, Some(Value::const_kind()), Span::Artificial) + .into_value() } pub(crate) fn from_const(c: Const) -> Self { let v = ValueKind::Const(c); match c { - Const::Type => { - Value::from_kind_and_type(v, Value::from_const(Const::Kind)) - } - Const::Kind => { - Value::from_kind_and_type(v, Value::from_const(Const::Sort)) - } + Const::Type => ValueInternal::from_whnf( + v, + Some(Value::from_const(Const::Kind)), + Span::Artificial, + ) + .into_value(), + Const::Kind => ValueInternal::from_whnf( + v, + Some(Value::const_sort()), + Span::Artificial, + ) + .into_value(), Const::Sort => Value::const_sort(), } } @@ -226,14 +234,10 @@ impl Value { } pub(crate) fn app(&self, v: Value) -> Value { - let body_t = match &*self.get_type_not_sort().kind() { - ValueKind::PiClosure { annot, closure, .. } => { - v.check_type(annot); - closure.apply(v.clone()) - } - _ => unreachable!("Internal type error"), - }; - Value::from_kind_and_type(apply_any(self.clone(), v, &body_t), body_t) + Value::from_kind_and_type( + apply_any(self.clone(), v, &Value::const_kind()), + Value::const_kind(), + ) } /// In debug mode, panic if the provided type doesn't match the value's type. @@ -246,12 +250,16 @@ impl Value { // "Internal type error" // ); } - pub(crate) fn get_type(&self) -> Result { + pub(crate) fn get_type(&self, tyenv: &TyEnv) -> Result { + let expr = self.to_tyexpr(tyenv.as_varenv()).to_expr_tyenv(tyenv); + type_with(tyenv, &expr).unwrap().get_type() + } + pub(crate) fn get_type_noenv(&self) -> Result { Ok(self.0.get_type()?.clone()) } /// When we know the value isn't `Sort`, this gets the type directly pub(crate) fn get_type_not_sort(&self) -> Value { - self.get_type() + self.get_type_noenv() .expect("Internal type error: value is `Sort` but shouldn't be") } @@ -366,6 +374,10 @@ impl Value { TyExpr::new(tye, self.0.ty.clone(), self.0.span.clone()) } + pub fn to_tyexpr_tyenv(&self, tyenv: &TyEnv) -> TyExpr { + let expr = self.to_tyexpr(tyenv.as_varenv()).to_expr_tyenv(tyenv); + type_with(tyenv, &expr).unwrap() + } pub fn to_tyexpr_noenv(&self) -> TyExpr { self.to_tyexpr(VarEnv::new()) } @@ -522,7 +534,7 @@ impl Closure { pub fn apply(&self, val: Value) -> Value { match self { Closure::Closure { env, body, .. } => { - body.eval(&env.insert_value(val)) + body.eval(&env.insert_value_noty(val)) } Closure::ConstantClosure { body, .. } => body.clone(), } diff --git a/dhall/src/semantics/tck/env.rs b/dhall/src/semantics/tck/env.rs index 1fc711c..b3e7895 100644 --- a/dhall/src/semantics/tck/env.rs +++ b/dhall/src/semantics/tck/env.rs @@ -104,16 +104,16 @@ impl TyEnv { &self.names } - pub fn insert_type(&self, x: &Label, t: Type) -> Self { + pub fn insert_type(&self, x: &Label, ty: Type) -> Self { TyEnv { names: self.names.insert(x), - items: self.items.insert_type(t), + items: self.items.insert_type(ty), } } - pub fn insert_value(&self, x: &Label, e: Value) -> Self { + pub fn insert_value(&self, x: &Label, e: Value, ty: Type) -> Self { TyEnv { names: self.names.insert(x), - items: self.items.insert_value(e), + items: self.items.insert_value(e, ty), } } pub fn lookup(&self, var: &V) -> Option<(AlphaVar, Type)> { diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index dd9a8fa..ceb83de 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -72,7 +72,9 @@ fn type_one_layer( ExprKind::Lam(binder, annot, body) => { let body_ty = body.get_type()?; - let body_ty = body_ty.to_tyexpr(env.as_varenv().insert()); + let body_ty = body_ty.to_tyexpr_tyenv( + &env.insert_type(&binder.clone(), annot.eval(env.as_nzenv())), + ); let pi_ekind = ExprKind::Pi(binder.clone(), annot.clone(), body_ty); type_one_layer(env, pi_ekind, Span::Artificial)? .eval(env.as_nzenv()) @@ -154,7 +156,7 @@ fn type_one_layer( } } let t = x.get_type()?; - if t.get_type()?.as_const() != Some(Const::Type) { + if t.get_type(env)?.as_const() != Some(Const::Type) { return span_err("InvalidListType"); } @@ -162,7 +164,7 @@ fn type_one_layer( } ExprKind::SomeLit(x) => { let t = x.get_type()?; - if t.get_type()?.as_const() != Some(Const::Type) { + if t.get_type(env)?.as_const() != Some(Const::Type) { return span_err("InvalidOptionalType"); } @@ -183,8 +185,7 @@ fn type_one_layer( let ty = type_of_recordtype( span.clone(), - kts.iter() - .map(|(_, t)| Cow::Owned(t.to_tyexpr(env.as_varenv()))), + kts.iter().map(|(_, t)| Cow::Owned(t.to_tyexpr_tyenv(env))), )?; Value::from_kind_and_type(ValueKind::RecordType(kts), ty) } @@ -278,13 +279,13 @@ fn type_one_layer( return span_err(&format!( "annot mismatch: ({} : {}) : {}", x.to_expr_tyenv(env), - x_ty.to_tyexpr(env.as_varenv()).to_expr_tyenv(env), - t.to_tyexpr(env.as_varenv()).to_expr_tyenv(env) + x_ty.to_tyexpr_tyenv(env).to_expr_tyenv(env), + t.to_tyexpr_tyenv(env).to_expr_tyenv(env) )); // return span_err(format!( // "annot mismatch: {} != {}", - // x_ty.to_tyexpr(env.as_varenv()).to_expr_tyenv(env), - // t.to_tyexpr(env.as_varenv()).to_expr_tyenv(env) + // x_ty.to_tyexpr_tyenv(env).to_expr_tyenv(env), + // t.to_tyexpr_tyenv(env).to_expr_tyenv(env) // )); // return span_err(format!("annot mismatch: {:#?} : {:#?}", x, t,)); } @@ -352,10 +353,9 @@ fn type_one_layer( if *x.get_type()?.kind() != ValueKind::from_builtin(Builtin::Bool) { return span_err("InvalidPredicate"); } - if y.get_type()?.get_type()?.as_const() != Some(Const::Type) { - return span_err("IfBranchMustBeTerm"); - } - if z.get_type()?.get_type()?.as_const() != Some(Const::Type) { + let y_ty = y.get_type()?; + let y_ty = y_ty.to_tyexpr_tyenv(env); + if y_ty.get_type()?.as_const() != Some(Const::Type) { return span_err("IfBranchMustBeTerm"); } if y.get_type()? != z.get_type()? { @@ -388,16 +388,15 @@ fn type_one_layer( // Construct the final record type let ty = type_of_recordtype( span.clone(), - kts.iter() - .map(|(_, t)| Cow::Owned(t.to_tyexpr(env.as_varenv()))), + kts.iter().map(|(_, t)| Cow::Owned(t.to_tyexpr_tyenv(env))), )?; Value::from_kind_and_type(ValueKind::RecordType(kts), ty) } ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y) => { let ekind = ExprKind::BinOp( BinOp::RecursiveRecordTypeMerge, - x.get_type()?.to_tyexpr(env.as_varenv()), - y.get_type()?.to_tyexpr(env.as_varenv()), + x.get_type()?.to_tyexpr_tyenv(env), + y.get_type()?.to_tyexpr_tyenv(env), ); type_one_layer(env, ekind, Span::Artificial)?.eval(env.as_nzenv()) } @@ -418,8 +417,8 @@ fn type_one_layer( env, ExprKind::BinOp( BinOp::RecursiveRecordTypeMerge, - tx.to_tyexpr(env.as_varenv()), - ty.to_tyexpr(env.as_varenv()), + tx.to_tyexpr_tyenv(env), + ty.to_tyexpr_tyenv(env), ), Span::Artificial, )?; @@ -451,7 +450,9 @@ fn type_one_layer( if l.get_type()? != r.get_type()? { return span_err("EquivalenceTypeMismatch"); } - if l.get_type()?.get_type()?.as_const() != Some(Const::Type) { + if l.get_type()?.to_tyexpr_tyenv(env).get_type()?.as_const() + != Some(Const::Type) + { return span_err("EquivalenceArgumentsMustBeTerms"); } @@ -668,7 +669,7 @@ fn type_one_layer( annot_val } else { let entry_type = kts.iter().next().unwrap().1.clone(); - if entry_type.get_type()?.as_const() != Some(Const::Type) { + if entry_type.get_type(env)?.as_const() != Some(Const::Type) { return span_err( "`toMap` only accepts records of type `Type`", ); @@ -724,7 +725,7 @@ fn type_one_layer( Value::from_kind_and_type( ValueKind::RecordType(new_kts), - record_type.get_type()?, + record_type.get_type(env)?, ) } ExprKind::ProjectionByExpr(record, selection) => { @@ -804,7 +805,12 @@ pub(crate) fn type_with( (TyExprKind::Expr(ExprKind::Const(Const::Sort)), None) } ExprKind::Embed(p) => { - return Ok(p.clone().into_value().to_tyexpr_noenv()) + let val = p.clone().into_value(); + ( + val.to_tyexpr_noenv().kind().clone(), + Some(val.get_type(&TyEnv::new())?), + ) + // return Ok(p.clone().into_value().to_tyexpr_noenv()) } ekind => { let ekind = match ekind { @@ -829,9 +835,9 @@ pub(crate) fn type_with( val.clone() }; let val = type_with(env, &val)?; - val.get_type()?; // Ensure val is not Sort + let val_ty = val.get_type()?; let val_nf = val.eval(&env.as_nzenv()); - let body_env = env.insert_value(&binder, val_nf); + let body_env = env.insert_value(&binder, val_nf, val_ty); let body = type_with(&body_env, body)?; ExprKind::Let(binder.clone(), None, val, body) } -- cgit v1.2.3 From 5870a46d5ab5810901198f03ed461d5c3bb5aa8a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 6 Feb 2020 17:58:48 +0000 Subject: Remove move type propagation through Value --- dhall/src/semantics/builtins.rs | 41 +++--------- dhall/src/semantics/nze/normalize.rs | 124 ++++++++++------------------------- dhall/src/semantics/nze/value.rs | 84 ++++++------------------ dhall/src/semantics/tck/typecheck.rs | 42 ++++-------- 4 files changed, 76 insertions(+), 215 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs index 907d449..a513967 100644 --- a/dhall/src/semantics/builtins.rs +++ b/dhall/src/semantics/builtins.rs @@ -35,11 +35,11 @@ impl BuiltinClosure { } } - pub fn apply(&self, a: Value, f_ty: Value, ret_ty: &Value) -> ValueKind { + pub fn apply(&self, a: Value, f_ty: Value) -> ValueKind { use std::iter::once; let args = self.args.iter().cloned().chain(once(a.clone())).collect(); let types = self.types.iter().cloned().chain(once(f_ty)).collect(); - apply_builtin(self.b, args, ret_ty, types, self.env.clone()) + apply_builtin(self.b, args, types, self.env.clone()) } /// This doesn't break the invariant because we already checked that the appropriate arguments /// did not normalize to something that allows evaluation to proceed. @@ -267,7 +267,6 @@ macro_rules! make_closure { fn apply_builtin( b: Builtin, args: Vec, - ty: &Value, types: Vec, env: NzEnv, ) -> ValueKind { @@ -399,10 +398,7 @@ fn apply_builtin( let mut kts = HashMap::new(); kts.insert("index".into(), Value::from_builtin(Natural)); kts.insert("value".into(), t.clone()); - let t = Value::from_kind_and_type( - RecordType(kts), - Value::from_const(Type), - ); + let t = Value::from_kind(RecordType(kts)); // Construct the new list, with added indices let list = match &*l_whnf { @@ -414,18 +410,10 @@ fn apply_builtin( let mut kvs = HashMap::new(); kvs.insert( "index".into(), - Value::from_kind_and_type( - NaturalLit(i), - Value::from_builtin( - Builtin::Natural, - ), - ), + Value::from_kind(NaturalLit(i)), ); kvs.insert("value".into(), e.clone()); - Value::from_kind_and_type( - RecordLit(kvs), - t.clone(), - ) + Value::from_kind(RecordLit(kvs)) }) .collect(), ), @@ -449,7 +437,7 @@ fn apply_builtin( )) .app(t.clone()), ) - .app(EmptyListLit(t.clone()).into_value_with_type(list_t)), + .app(EmptyListLit(t.clone()).into_value()), ) } (ListFold, [_, l, _, cons, nil]) => match &*l.kind() { @@ -475,10 +463,7 @@ fn apply_builtin( )) .app(t.clone()), ) - .app( - EmptyOptionalLit(t.clone()) - .into_value_with_type(optional_t), - ), + .app(EmptyOptionalLit(t.clone()).into_value()), ) } (OptionalFold, [_, v, _, just, nothing]) => match &*v.kind() { @@ -492,20 +477,14 @@ fn apply_builtin( λ(x : Natural) -> 1 + var(x) ))) - .app( - NaturalLit(0) - .into_value_with_type(Value::from_builtin(Natural)), - ), + .app(NaturalLit(0).into_value()), ), (NaturalFold, [n, t, succ, zero]) => match &*n.kind() { NaturalLit(0) => Ret::Value(zero.clone()), NaturalLit(n) => { let fold = Value::from_builtin(NaturalFold) - .app( - NaturalLit(n - 1) - .into_value_with_type(Value::from_builtin(Natural)), - ) + .app(NaturalLit(n - 1).into_value()) .app(t.clone()) .app(succ.clone()) .app(zero.clone()); @@ -517,7 +496,7 @@ fn apply_builtin( }; match ret { Ret::ValueKind(v) => v, - Ret::Value(v) => v.to_whnf_check_type(ty), + Ret::Value(v) => v.kind().clone(), Ret::DoneAsIs => AppliedBuiltin(BuiltinClosure { b, args, diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index 3a981f4..c660fce 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -6,18 +6,16 @@ use crate::semantics::{ Binder, BuiltinClosure, Closure, TextLit, TyExpr, TyExprKind, Value, ValueKind, }; -use crate::syntax::{ - BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, -}; +use crate::syntax::{BinOp, Builtin, ExprKind, InterpolatedTextContents}; use crate::Normalized; -pub(crate) fn apply_any(f: Value, a: Value, ty: &Value) -> ValueKind { +pub(crate) fn apply_any(f: Value, a: Value) -> ValueKind { match f.kind() { ValueKind::LamClosure { closure, .. } => { - closure.apply(a).to_whnf_check_type(ty) + closure.apply(a).kind().clone() } ValueKind::AppliedBuiltin(closure) => { - closure.apply(a, f.get_type_not_sort(), ty) + closure.apply(a, f.get_type_not_sort()) } ValueKind::UnionConstructor(l, kts, uniont) => ValueKind::UnionLit( l.clone(), @@ -102,12 +100,7 @@ enum Ret<'a> { Expr(ExprKind), } -fn apply_binop<'a>( - o: BinOp, - x: &'a Value, - y: &'a Value, - ty: &Value, -) -> 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, @@ -194,19 +187,12 @@ fn apply_binop<'a>( Ret::ValueRef(y) } (RecursiveRecordMerge, RecordLit(kvs1), RecordLit(kvs2)) => { - let kts = match ty.kind() { - RecordType(kts) => kts, - _ => unreachable!("Internal type error"), - }; - let kvs = merge_maps::<_, _, _, !>(kvs1, kvs2, |k, v1, v2| { - Ok(Value::from_partial_expr( - ExprKind::BinOp( - RecursiveRecordMerge, - v1.clone(), - v2.clone(), - ), - kts.get(k).expect("Internal type error").clone(), - )) + let kvs = merge_maps::<_, _, _, !>(kvs1, kvs2, |_, v1, v2| { + Ok(Value::from_partial_expr(ExprKind::BinOp( + RecursiveRecordMerge, + v1.clone(), + v2.clone(), + ))) })?; Ret::ValueKind(RecordLit(kvs)) } @@ -217,14 +203,11 @@ fn apply_binop<'a>( kts_y, // If the Label exists for both records, then we hit the recursive case. |_, l: &Value, r: &Value| { - Ok(Value::from_partial_expr( - ExprKind::BinOp( - RecursiveRecordTypeMerge, - l.clone(), - r.clone(), - ), - ty.clone(), - )) + Ok(Value::from_partial_expr(ExprKind::BinOp( + RecursiveRecordTypeMerge, + l.clone(), + r.clone(), + ))) }, )?; Ret::ValueKind(RecordType(kts)) @@ -240,7 +223,6 @@ fn apply_binop<'a>( pub(crate) fn normalize_one_layer( expr: ExprKind, - ty: &Value, env: &NzEnv, ) -> ValueKind { use ValueKind::{ @@ -318,7 +300,7 @@ pub(crate) fn normalize_one_layer( } } } - ExprKind::BinOp(o, ref x, ref y) => match apply_binop(o, x, y, ty) { + ExprKind::BinOp(o, ref x, ref y) => match apply_binop(o, x, y) { Some(ret) => ret, None => Ret::Expr(expr), }, @@ -335,7 +317,6 @@ pub(crate) fn normalize_one_layer( PartialExpr(ExprKind::Projection(v2, _)) => { return normalize_one_layer( ExprKind::Projection(v2.clone(), ls.clone()), - ty, env, ) } @@ -361,45 +342,26 @@ pub(crate) fn normalize_one_layer( None => { return normalize_one_layer( ExprKind::Field(x.clone(), l.clone()), - ty, env, ) } }, (RecordLit(kvs), _) => match kvs.get(l) { Some(r) => Ret::Expr(ExprKind::Field( - Value::from_kind_and_type( - PartialExpr(ExprKind::BinOp( - BinOp::RightBiasedRecordMerge, - Value::from_kind_and_type( - RecordLit({ - let mut kvs = HashMap::new(); - kvs.insert(l.clone(), r.clone()); - kvs - }), - Value::from_kind_and_type( - RecordType({ - let mut kvs = HashMap::new(); - kvs.insert( - l.clone(), - r.get_type_not_sort(), - ); - kvs - }), - r.get_type_not_sort() - .get_type_not_sort(), - ), - ), - y.clone(), - )), - v.get_type_not_sort(), - ), + Value::from_kind(PartialExpr(ExprKind::BinOp( + BinOp::RightBiasedRecordMerge, + Value::from_kind(RecordLit({ + let mut kvs = HashMap::new(); + kvs.insert(l.clone(), r.clone()); + kvs + })), + y.clone(), + ))), l.clone(), )), None => { return normalize_one_layer( ExprKind::Field(y.clone(), l.clone()), - ty, env, ) } @@ -416,7 +378,6 @@ pub(crate) fn normalize_one_layer( None => { return normalize_one_layer( ExprKind::Field(y.clone(), l.clone()), - ty, env, ) } @@ -426,7 +387,6 @@ pub(crate) fn normalize_one_layer( None => { return normalize_one_layer( ExprKind::Field(x.clone(), l.clone()), - ty, env, ) } @@ -482,22 +442,9 @@ pub(crate) fn normalize_one_layer( .sorted_by_key(|(k, _)| k.clone()) .map(|(k, v)| { let mut rec = HashMap::new(); - let mut rec_ty = HashMap::new(); rec.insert("mapKey".into(), Value::from_text(k)); rec.insert("mapValue".into(), v.clone()); - rec_ty.insert( - "mapKey".into(), - Value::from_builtin(Builtin::Text), - ); - rec_ty.insert("mapValue".into(), v.get_type_not_sort()); - - Value::from_kind_and_type( - ValueKind::RecordLit(rec), - Value::from_kind_and_type( - ValueKind::RecordType(rec_ty), - Value::from_const(Const::Type), - ), - ) + Value::from_kind(ValueKind::RecordLit(rec)) }) .collect(), )), @@ -507,8 +454,8 @@ pub(crate) fn normalize_one_layer( match ret { Ret::ValueKind(v) => v, - Ret::Value(v) => v.to_whnf_check_type(ty), - Ret::ValueRef(v) => v.to_whnf_check_type(ty), + Ret::Value(v) => v.kind().clone(), + Ret::ValueRef(v) => v.kind().clone(), Ret::Expr(expr) => ValueKind::PartialExpr(expr), } } @@ -521,17 +468,16 @@ pub(crate) fn normalize_tyexpr_whnf(tye: &TyExpr, env: &NzEnv) -> ValueKind { let annot = annot.eval(env); ValueKind::LamClosure { binder: Binder::new(binder.clone()), - annot: annot.clone(), - closure: Closure::new(annot, env, body.clone()), + annot: annot, + closure: Closure::new(env, body.clone()), } } TyExprKind::Expr(ExprKind::Pi(binder, annot, body)) => { let annot = annot.eval(env); - let closure = Closure::new(annot.clone(), env, body.clone()); ValueKind::PiClosure { binder: Binder::new(binder.clone()), annot, - closure, + closure: Closure::new(env, body.clone()), } } TyExprKind::Expr(ExprKind::Let(_, None, val, body)) => { @@ -539,12 +485,8 @@ pub(crate) fn normalize_tyexpr_whnf(tye: &TyExpr, env: &NzEnv) -> ValueKind { body.eval(&env.insert_value_noty(val)).kind().clone() } TyExprKind::Expr(e) => { - let ty = match tye.get_type() { - Ok(ty) => ty, - Err(_) => return ValueKind::Const(Const::Sort), - }; let e = e.map_ref(|tye| tye.eval(env)); - normalize_one_layer(e, &ty, env) + normalize_one_layer(e, env) } } } diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index 203b479..47c50a4 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -5,8 +5,8 @@ use crate::error::{TypeError, TypeMessage}; use crate::semantics::nze::lazy; use crate::semantics::{ apply_any, normalize_one_layer, normalize_tyexpr_whnf, squash_textlit, - type_of_builtin, type_with, typecheck, Binder, BuiltinClosure, NzEnv, - NzVar, TyEnv, TyExpr, TyExprKind, VarEnv, + type_with, Binder, BuiltinClosure, NzEnv, NzVar, TyEnv, TyExpr, TyExprKind, + VarEnv, }; use crate::syntax::{ BinOp, Builtin, Const, ExprKind, Integer, InterpolatedTextContents, Label, @@ -39,7 +39,6 @@ pub(crate) enum Thunk { PartialExpr { env: NzEnv, expr: ExprKind, - ty: Value, }, } @@ -47,11 +46,7 @@ pub(crate) enum Thunk { #[derive(Debug, Clone)] pub(crate) enum Closure { /// Normal closure - Closure { - arg_ty: Value, - env: NzEnv, - body: TyExpr, - }, + Closure { env: NzEnv, body: TyExpr }, /// Closure that ignores the argument passed ConstantClosure { body: Value }, } @@ -130,21 +125,18 @@ impl Value { .into_value() } /// Construct a Value from a partially normalized expression that's not in WHNF. - pub(crate) fn from_partial_expr( - e: ExprKind, - ty: Value, - ) -> Value { + pub(crate) fn from_partial_expr(e: ExprKind) -> Value { // TODO: env let env = NzEnv::new(); ValueInternal::from_thunk( - Thunk::from_partial_expr(env, e, ty.clone()), + Thunk::from_partial_expr(env, e), Some(Value::const_kind()), Span::Artificial, ) .into_value() } /// Make a Value from a ValueKind - pub(crate) fn from_kind_and_type(v: ValueKind, t: Value) -> Value { + pub(crate) fn from_kind(v: ValueKind) -> Value { ValueInternal::from_whnf(v, Some(Value::const_kind()), Span::Artificial) .into_value() } @@ -170,16 +162,12 @@ impl Value { Self::from_builtin_env(b, &NzEnv::new()) } pub(crate) fn from_builtin_env(b: Builtin, env: &NzEnv) -> Self { - Value::from_kind_and_type( - ValueKind::from_builtin_env(b, env.clone()), - typecheck(&type_of_builtin(b)).unwrap().eval_closed_expr(), - ) + Value::from_kind(ValueKind::from_builtin_env(b, env.clone())) } pub(crate) fn from_text(txt: impl ToString) -> Self { - Value::from_kind_and_type( - ValueKind::TextLit(TextLit::from_text(txt.to_string())), - Value::from_builtin(Builtin::Text), - ) + Value::from_kind(ValueKind::TextLit(TextLit::from_text( + txt.to_string(), + ))) } pub(crate) fn as_const(&self) -> Option { @@ -210,14 +198,6 @@ impl Value { pub(crate) fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { self.to_tyexpr(env.as_varenv()).to_expr_tyenv(env) } - pub(crate) fn to_whnf_ignore_type(&self) -> ValueKind { - self.kind().clone() - } - /// Before discarding type information, check that it matches the expected return type. - pub(crate) fn to_whnf_check_type(&self, ty: &Value) -> ValueKind { - self.check_type(ty); - self.to_whnf_ignore_type() - } /// Normalizes contents to normal form; faster than `normalize` if /// no one else shares this. @@ -234,33 +214,19 @@ impl Value { } pub(crate) fn app(&self, v: Value) -> Value { - Value::from_kind_and_type( - apply_any(self.clone(), v, &Value::const_kind()), - Value::const_kind(), - ) + Value::from_kind(apply_any(self.clone(), v)) } - /// In debug mode, panic if the provided type doesn't match the value's type. - /// Otherwise does nothing. - pub(crate) fn check_type(&self, _ty: &Value) { - // TODO: reenable - // debug_assert_eq!( - // Some(ty), - // self.get_type().ok().as_ref(), - // "Internal type error" - // ); - } pub(crate) fn get_type(&self, tyenv: &TyEnv) -> Result { let expr = self.to_tyexpr(tyenv.as_varenv()).to_expr_tyenv(tyenv); type_with(tyenv, &expr).unwrap().get_type() } - pub(crate) fn get_type_noenv(&self) -> Result { - Ok(self.0.get_type()?.clone()) - } /// When we know the value isn't `Sort`, this gets the type directly pub(crate) fn get_type_not_sort(&self) -> Value { - self.get_type_noenv() + self.0 + .get_type() .expect("Internal type error: value is `Sort` but shouldn't be") + .clone() } pub fn to_tyexpr(&self, venv: VarEnv) -> TyExpr { @@ -422,8 +388,8 @@ impl ValueInternal { } impl ValueKind { - pub(crate) fn into_value_with_type(self, t: Value) -> Value { - Value::from_kind_and_type(self, t) + pub(crate) fn into_value(self) -> Value { + Value::from_kind(self) } pub(crate) fn normalize(&self) { @@ -504,24 +470,20 @@ impl Thunk { pub fn from_partial_expr( env: NzEnv, expr: ExprKind, - ty: Value, ) -> Self { - Thunk::PartialExpr { env, expr, ty } + Thunk::PartialExpr { env, expr } } pub fn eval(self) -> ValueKind { match self { Thunk::Thunk { env, body } => normalize_tyexpr_whnf(&body, &env), - Thunk::PartialExpr { env, expr, ty } => { - normalize_one_layer(expr, &ty, &env) - } + Thunk::PartialExpr { env, expr } => normalize_one_layer(expr, &env), } } } impl Closure { - pub fn new(arg_ty: Value, env: &NzEnv, body: TyExpr) -> Self { + pub fn new(env: &NzEnv, body: TyExpr) -> Self { Closure::Closure { - arg_ty, env: env.clone(), body, } @@ -541,12 +503,8 @@ impl Closure { } fn apply_var(&self, var: NzVar) -> Value { match self { - Closure::Closure { arg_ty, .. } => { - let val = Value::from_kind_and_type( - ValueKind::Var(var), - arg_ty.clone(), - ); - self.apply(val) + Closure::Closure { .. } => { + self.apply(Value::from_kind(ValueKind::Var(var))) } Closure::ConstantClosure { body, .. } => body.clone(), } diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index ceb83de..810e483 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -183,11 +183,11 @@ fn type_one_layer( }; } - let ty = type_of_recordtype( + type_of_recordtype( span.clone(), kts.iter().map(|(_, t)| Cow::Owned(t.to_tyexpr_tyenv(env))), )?; - Value::from_kind_and_type(ValueKind::RecordType(kts), ty) + Value::from_kind(ValueKind::RecordType(kts)) } ExprKind::RecordType(kts) => { use std::collections::hash_map::Entry; @@ -247,22 +247,11 @@ fn type_one_layer( ValueKind::UnionType(kts) => match kts.get(x) { // Constructor has type T -> < x: T, ... > Some(Some(ty)) => { - // Can't fail because uniontypes must have type Const(_). - let kt = scrut.get_type()?.as_const().unwrap(); - // The type of the field must be Const smaller than `kt`, thus the - // function type has type `kt`. - let pi_ty = Value::from_const(kt); - - Value::from_kind_and_type( - ValueKind::PiClosure { - binder: Binder::new(x.clone()), - annot: ty.clone(), - closure: Closure::new_constant( - scrut_nf, - ), - }, - pi_ty, - ) + Value::from_kind(ValueKind::PiClosure { + binder: Binder::new(x.clone()), + annot: ty.clone(), + closure: Closure::new_constant(scrut_nf), + }) } Some(None) => scrut_nf, None => return span_err("MissingUnionField"), @@ -386,11 +375,11 @@ fn type_one_layer( })?; // Construct the final record type - let ty = type_of_recordtype( + type_of_recordtype( span.clone(), kts.iter().map(|(_, t)| Cow::Owned(t.to_tyexpr_tyenv(env))), )?; - Value::from_kind_and_type(ValueKind::RecordType(kts), ty) + Value::from_kind(ValueKind::RecordType(kts)) } ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y) => { let ekind = ExprKind::BinOp( @@ -685,12 +674,8 @@ fn type_one_layer( let mut kts = HashMap::new(); kts.insert("mapKey".into(), Value::from_builtin(Builtin::Text)); kts.insert("mapValue".into(), entry_type); - let output_type = Value::from_builtin(Builtin::List).app( - Value::from_kind_and_type( - ValueKind::RecordType(kts), - Value::from_const(Const::Type), - ), - ); + let output_type = Value::from_builtin(Builtin::List) + .app(Value::from_kind(ValueKind::RecordType(kts))); if let Some(annot) = annot { let annot_val = annot.eval(env.as_nzenv()); if output_type != annot_val { @@ -723,10 +708,7 @@ fn type_one_layer( }; } - Value::from_kind_and_type( - ValueKind::RecordType(new_kts), - record_type.get_type(env)?, - ) + Value::from_kind(ValueKind::RecordType(new_kts)) } ExprKind::ProjectionByExpr(record, selection) => { let record_type = record.get_type()?; -- cgit v1.2.3 From 27031b3739ff9f2043e64130a4c5699d0f9233e8 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 11:23:59 +0000 Subject: Add Hir as untyped alternative to TyExpr --- dhall/src/semantics/hir.rs | 112 +++++++++++++++++++++++++++++++++++ dhall/src/semantics/mod.rs | 2 + dhall/src/semantics/nze/normalize.rs | 4 +- dhall/src/semantics/nze/value.rs | 10 ++-- dhall/src/semantics/tck/tyexpr.rs | 70 ++++------------------ 5 files changed, 133 insertions(+), 65 deletions(-) create mode 100644 dhall/src/semantics/hir.rs (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs new file mode 100644 index 0000000..2784ecb --- /dev/null +++ b/dhall/src/semantics/hir.rs @@ -0,0 +1,112 @@ +#![allow(dead_code)] +use crate::semantics::{rc, NameEnv, NzEnv, TyEnv, Value}; +use crate::syntax::{ExprKind, Span, V}; +use crate::{Normalized, NormalizedExpr, ToExprOptions}; + +/// Stores an alpha-normalized variable. +#[derive(Debug, Clone, Copy)] +pub struct AlphaVar { + idx: usize, +} + +#[derive(Debug, Clone)] +pub(crate) enum HirKind { + Var(AlphaVar), + // Forbidden ExprKind variants: Var, Import, Embed + Expr(ExprKind), +} + +// An expression with resolved variables and imports. +#[derive(Debug, Clone)] +pub(crate) struct Hir { + kind: Box, + span: Span, +} + +impl AlphaVar { + pub(crate) fn new(idx: usize) -> Self { + AlphaVar { idx } + } + pub(crate) fn idx(&self) -> usize { + self.idx + } +} + +impl Hir { + pub fn new(kind: HirKind, span: Span) -> Self { + Hir { + kind: Box::new(kind), + span, + } + } + + pub fn kind(&self) -> &HirKind { + &*self.kind + } + pub fn span(&self) -> Span { + self.span.clone() + } + + /// Converts a HIR expr back to the corresponding AST expression. + pub fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { + hir_to_expr(self, opts, &mut NameEnv::new()) + } + pub fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { + let opts = ToExprOptions { + normalize: true, + alpha: false, + }; + let mut env = env.as_nameenv().clone(); + hir_to_expr(self, opts, &mut env) + } + + /// Eval the Hir. It will actually get evaluated only as needed on demand. + pub fn eval(&self, env: &NzEnv) -> Value { + // Value::new_thunk(env, self.clone()) + todo!() + } + /// Eval a closed Hir (i.e. without free variables). It will actually get evaluated only as + /// needed on demand. + pub fn eval_closed_expr(&self) -> Value { + self.eval(&NzEnv::new()) + } + /// Eval a closed Hir fully and recursively (TODO: ish, need to fix under lambdas) + pub fn rec_eval_closed_expr(&self) -> Value { + let mut val = self.eval_closed_expr(); + val.normalize_mut(); + val + } +} + +fn hir_to_expr( + hir: &Hir, + opts: ToExprOptions, + env: &mut NameEnv, +) -> NormalizedExpr { + rc(match hir.kind() { + HirKind::Var(v) if opts.alpha => ExprKind::Var(V("_".into(), v.idx())), + HirKind::Var(v) => ExprKind::Var(env.label_var(v)), + HirKind::Expr(e) => { + let e = e.map_ref_maybe_binder(|l, hir| { + if let Some(l) = l { + env.insert_mut(l); + } + let e = hir_to_expr(hir, opts, env); + if let Some(_) = l { + env.remove_mut(); + } + e + }); + + match e { + ExprKind::Lam(_, t, e) if opts.alpha => { + ExprKind::Lam("_".into(), t, e) + } + ExprKind::Pi(_, t, e) if opts.alpha => { + ExprKind::Pi("_".into(), t, e) + } + e => e, + } + } + }) +} diff --git a/dhall/src/semantics/mod.rs b/dhall/src/semantics/mod.rs index 98fdf5a..a8c0659 100644 --- a/dhall/src/semantics/mod.rs +++ b/dhall/src/semantics/mod.rs @@ -1,8 +1,10 @@ pub mod builtins; +pub mod hir; pub mod nze; pub mod parse; pub mod resolve; pub mod tck; pub(crate) use self::builtins::*; +pub(crate) use self::hir::*; pub(crate) use self::nze::*; pub(crate) use self::tck::*; diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index c660fce..b5949f5 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -3,8 +3,8 @@ use std::collections::HashMap; use crate::semantics::NzEnv; use crate::semantics::{ - Binder, BuiltinClosure, Closure, TextLit, TyExpr, TyExprKind, Value, - ValueKind, + Binder, BuiltinClosure, Closure, Hir, HirKind, TextLit, TyExpr, TyExprKind, + Value, ValueKind, }; use crate::syntax::{BinOp, Builtin, ExprKind, InterpolatedTextContents}; use crate::Normalized; diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index 47c50a4..d4213bc 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -5,8 +5,8 @@ use crate::error::{TypeError, TypeMessage}; use crate::semantics::nze::lazy; use crate::semantics::{ apply_any, normalize_one_layer, normalize_tyexpr_whnf, squash_textlit, - type_with, Binder, BuiltinClosure, NzEnv, NzVar, TyEnv, TyExpr, TyExprKind, - VarEnv, + type_with, Binder, BuiltinClosure, Hir, NzEnv, NzVar, TyEnv, TyExpr, + TyExprKind, VarEnv, }; use crate::syntax::{ BinOp, Builtin, Const, ExprKind, Integer, InterpolatedTextContents, Label, @@ -461,19 +461,19 @@ impl ValueKind { } impl Thunk { - pub fn new(env: &NzEnv, body: TyExpr) -> Self { + fn new(env: &NzEnv, body: TyExpr) -> Self { Thunk::Thunk { env: env.clone(), body, } } - pub fn from_partial_expr( + fn from_partial_expr( env: NzEnv, expr: ExprKind, ) -> Self { Thunk::PartialExpr { env, expr } } - pub fn eval(self) -> ValueKind { + fn eval(self) -> ValueKind { match self { Thunk::Thunk { env, body } => normalize_tyexpr_whnf(&body, &env), Thunk::PartialExpr { env, expr } => normalize_one_layer(expr, &env), diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index 1886646..fa578c0 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -1,17 +1,13 @@ use crate::error::{TypeError, TypeMessage}; -use crate::semantics::{rc, NameEnv, NzEnv, TyEnv, Value}; +use crate::semantics::{ + rc, AlphaVar, Hir, HirKind, NameEnv, NzEnv, TyEnv, Value, +}; use crate::syntax::{ExprKind, Span, V}; use crate::Normalized; use crate::{NormalizedExpr, ToExprOptions}; pub(crate) type Type = Value; -/// Stores an alpha-normalized variable. -#[derive(Debug, Clone, Copy)] -pub struct AlphaVar { - idx: usize, -} - #[derive(Debug, Clone)] pub(crate) enum TyExprKind { Var(AlphaVar), @@ -27,15 +23,6 @@ pub(crate) struct TyExpr { span: Span, } -impl AlphaVar { - pub(crate) fn new(idx: usize) -> Self { - AlphaVar { idx } - } - pub(crate) fn idx(&self) -> usize { - self.idx - } -} - impl TyExpr { pub fn new(kind: TyExprKind, ty: Option, span: Span) -> Self { TyExpr { @@ -58,17 +45,19 @@ impl TyExpr { } } + pub fn to_hir(&self) -> Hir { + let kind = match self.kind() { + TyExprKind::Var(v) => HirKind::Var(v.clone()), + TyExprKind::Expr(e) => HirKind::Expr(e.map_ref(|tye| tye.to_hir())), + }; + Hir::new(kind, self.span()) + } /// Converts a value back to the corresponding AST expression. pub fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { - tyexpr_to_expr(self, opts, &mut NameEnv::new()) + self.to_hir().to_expr(opts) } pub fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { - let opts = ToExprOptions { - normalize: true, - alpha: false, - }; - let mut env = env.as_nameenv().clone(); - tyexpr_to_expr(self, opts, &mut env) + self.to_hir().to_expr_tyenv(env) } /// Eval the TyExpr. It will actually get evaluated only as needed on demand. @@ -88,41 +77,6 @@ impl TyExpr { } } -fn tyexpr_to_expr<'a>( - tyexpr: &'a TyExpr, - opts: ToExprOptions, - env: &mut NameEnv, -) -> NormalizedExpr { - rc(match tyexpr.kind() { - TyExprKind::Var(v) if opts.alpha => { - ExprKind::Var(V("_".into(), v.idx())) - } - TyExprKind::Var(v) => ExprKind::Var(env.label_var(v)), - TyExprKind::Expr(e) => { - let e = e.map_ref_maybe_binder(|l, tye| { - if let Some(l) = l { - env.insert_mut(l); - } - let e = tyexpr_to_expr(tye, opts, env); - if let Some(_) = l { - env.remove_mut(); - } - e - }); - - match e { - ExprKind::Lam(_, t, e) if opts.alpha => { - ExprKind::Lam("_".into(), t, e) - } - ExprKind::Pi(_, t, e) if opts.alpha => { - ExprKind::Pi("_".into(), t, e) - } - e => e, - } - } - }) -} - impl std::fmt::Debug for TyExpr { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut x = fmt.debug_struct("TyExpr"); -- cgit v1.2.3 From 6c90d356c9a4a5bbeb88f25ad0ab499ba1503eae Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 11:53:55 +0000 Subject: Remove most TyExpr from normalization --- dhall/src/semantics/builtins.rs | 14 ++-- dhall/src/semantics/hir.rs | 3 +- dhall/src/semantics/nze/normalize.rs | 21 +++--- dhall/src/semantics/nze/value.rs | 120 ++++++++++++++++------------------- dhall/src/semantics/tck/env.rs | 6 +- dhall/src/semantics/tck/tyexpr.rs | 11 +--- dhall/src/semantics/tck/typecheck.rs | 13 +--- 7 files changed, 80 insertions(+), 108 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs index a513967..423364d 100644 --- a/dhall/src/semantics/builtins.rs +++ b/dhall/src/semantics/builtins.rs @@ -1,5 +1,5 @@ use crate::semantics::{ - typecheck, NzEnv, TyExpr, TyExprKind, Value, ValueKind, VarEnv, + typecheck, Hir, HirKind, NzEnv, Value, ValueKind, VarEnv, }; use crate::syntax::map::DupTreeMap; use crate::syntax::Const::Type; @@ -48,17 +48,13 @@ impl BuiltinClosure { x.normalize(); } } - pub fn to_tyexprkind(&self, venv: VarEnv) -> TyExprKind { - TyExprKind::Expr(self.args.iter().zip(self.types.iter()).fold( + pub fn to_hirkind(&self, venv: VarEnv) -> HirKind { + HirKind::Expr(self.args.iter().zip(self.types.iter()).fold( ExprKind::Builtin(self.b), |acc, (v, ty)| { ExprKind::App( - TyExpr::new( - TyExprKind::Expr(acc), - Some(ty.clone()), - Span::Artificial, - ), - v.to_tyexpr(venv), + Hir::new(HirKind::Expr(acc), Span::Artificial), + v.to_hir(venv), ) }, )) diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index 2784ecb..683dbbb 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -62,8 +62,7 @@ impl Hir { /// Eval the Hir. It will actually get evaluated only as needed on demand. pub fn eval(&self, env: &NzEnv) -> Value { - // Value::new_thunk(env, self.clone()) - todo!() + Value::new_thunk(env, self.clone()) } /// Eval a closed Hir (i.e. without free variables). It will actually get evaluated only as /// needed on demand. diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index b5949f5..acb2e51 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -3,8 +3,7 @@ use std::collections::HashMap; use crate::semantics::NzEnv; use crate::semantics::{ - Binder, BuiltinClosure, Closure, Hir, HirKind, TextLit, TyExpr, TyExprKind, - Value, ValueKind, + Binder, BuiltinClosure, Closure, Hir, HirKind, TextLit, Value, ValueKind, }; use crate::syntax::{BinOp, Builtin, ExprKind, InterpolatedTextContents}; use crate::Normalized; @@ -460,11 +459,11 @@ pub(crate) fn normalize_one_layer( } } -/// Normalize a TyExpr into WHNF -pub(crate) fn normalize_tyexpr_whnf(tye: &TyExpr, env: &NzEnv) -> ValueKind { - match tye.kind() { - TyExprKind::Var(var) => env.lookup_val(var), - TyExprKind::Expr(ExprKind::Lam(binder, annot, body)) => { +/// Normalize Hir into WHNF +pub(crate) fn normalize_hir_whnf(env: &NzEnv, hir: &Hir) -> ValueKind { + match hir.kind() { + HirKind::Var(var) => env.lookup_val(var), + HirKind::Expr(ExprKind::Lam(binder, annot, body)) => { let annot = annot.eval(env); ValueKind::LamClosure { binder: Binder::new(binder.clone()), @@ -472,7 +471,7 @@ pub(crate) fn normalize_tyexpr_whnf(tye: &TyExpr, env: &NzEnv) -> ValueKind { closure: Closure::new(env, body.clone()), } } - TyExprKind::Expr(ExprKind::Pi(binder, annot, body)) => { + HirKind::Expr(ExprKind::Pi(binder, annot, body)) => { let annot = annot.eval(env); ValueKind::PiClosure { binder: Binder::new(binder.clone()), @@ -480,12 +479,12 @@ pub(crate) fn normalize_tyexpr_whnf(tye: &TyExpr, env: &NzEnv) -> ValueKind { closure: Closure::new(env, body.clone()), } } - TyExprKind::Expr(ExprKind::Let(_, None, val, body)) => { + HirKind::Expr(ExprKind::Let(_, None, val, body)) => { let val = val.eval(env); body.eval(&env.insert_value_noty(val)).kind().clone() } - TyExprKind::Expr(e) => { - let e = e.map_ref(|tye| tye.eval(env)); + HirKind::Expr(e) => { + let e = e.map_ref(|hir| hir.eval(env)); normalize_one_layer(e, env) } } diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index d4213bc..d05c545 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -4,9 +4,9 @@ use std::rc::Rc; use crate::error::{TypeError, TypeMessage}; use crate::semantics::nze::lazy; use crate::semantics::{ - apply_any, normalize_one_layer, normalize_tyexpr_whnf, squash_textlit, - type_with, Binder, BuiltinClosure, Hir, NzEnv, NzVar, TyEnv, TyExpr, - TyExprKind, VarEnv, + apply_any, normalize_hir_whnf, normalize_one_layer, squash_textlit, + type_with, Binder, BuiltinClosure, Hir, HirKind, NzEnv, NzVar, TyEnv, + TyExpr, VarEnv, }; use crate::syntax::{ BinOp, Builtin, Const, ExprKind, Integer, InterpolatedTextContents, Label, @@ -34,7 +34,7 @@ struct ValueInternal { #[derive(Debug, Clone)] pub(crate) enum Thunk { /// A completely unnormalized expression. - Thunk { env: NzEnv, body: TyExpr }, + Thunk { env: NzEnv, body: Hir }, /// A partially normalized expression that may need to go through `normalize_one_layer`. PartialExpr { env: NzEnv, @@ -46,7 +46,7 @@ pub(crate) enum Thunk { #[derive(Debug, Clone)] pub(crate) enum Closure { /// Normal closure - Closure { env: NzEnv, body: TyExpr }, + Closure { env: NzEnv, body: Hir }, /// Closure that ignores the argument passed ConstantClosure { body: Value }, } @@ -116,11 +116,12 @@ impl Value { Value::from_const(Const::Kind) } /// Construct a Value from a completely unnormalized expression. - pub(crate) fn new_thunk(env: &NzEnv, tye: TyExpr) -> Value { + pub(crate) fn new_thunk(env: &NzEnv, hir: Hir) -> Value { + let span = hir.span(); ValueInternal::from_thunk( - Thunk::new(env, tye.clone()), + Thunk::new(env, hir), Some(Value::const_kind()), - tye.span().clone(), + span, ) .into_value() } @@ -176,13 +177,8 @@ impl Value { _ => None, } } - // pub(crate) fn span(&self) -> Span { - // self.0.span.clone() - // } /// This is what you want if you want to pattern-match on the value. - /// WARNING: drop this ref before normalizing the same value or you will run into BorrowMut - /// panics. pub(crate) fn kind(&self) -> &ValueKind { self.0.kind() } @@ -196,7 +192,7 @@ impl Value { self.to_tyexpr_noenv().to_expr(opts) } pub(crate) fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { - self.to_tyexpr(env.as_varenv()).to_expr_tyenv(env) + self.to_hir(env.as_varenv()).to_expr_tyenv(env) } /// Normalizes contents to normal form; faster than `normalize` if @@ -218,8 +214,7 @@ impl Value { } pub(crate) fn get_type(&self, tyenv: &TyEnv) -> Result { - let expr = self.to_tyexpr(tyenv.as_varenv()).to_expr_tyenv(tyenv); - type_with(tyenv, &expr).unwrap().get_type() + self.to_tyexpr_tyenv(tyenv).get_type() } /// When we know the value isn't `Sort`, this gets the type directly pub(crate) fn get_type_not_sort(&self) -> Value { @@ -229,21 +224,21 @@ impl Value { .clone() } - pub fn to_tyexpr(&self, venv: VarEnv) -> TyExpr { + pub fn to_hir(&self, venv: VarEnv) -> Hir { let map_uniontype = |kts: &HashMap>| { ExprKind::UnionType( kts.iter() .map(|(k, v)| { - (k.clone(), v.as_ref().map(|v| v.to_tyexpr(venv))) + (k.clone(), v.as_ref().map(|v| v.to_hir(venv))) }) .collect(), ) }; - let tye = match &*self.kind() { - ValueKind::Var(v) => TyExprKind::Var(venv.lookup(v)), - ValueKind::AppliedBuiltin(closure) => closure.to_tyexprkind(venv), - self_kind => TyExprKind::Expr(match self_kind { + let hir = match &*self.kind() { + ValueKind::Var(v) => HirKind::Var(venv.lookup(v)), + ValueKind::AppliedBuiltin(closure) => closure.to_hirkind(venv), + self_kind => HirKind::Expr(match self_kind { ValueKind::Var(..) | ValueKind::AppliedBuiltin(..) => { unreachable!() } @@ -253,8 +248,8 @@ impl Value { closure, } => ExprKind::Lam( binder.to_label(), - annot.to_tyexpr(venv), - closure.to_tyexpr(venv), + annot.to_hir(venv), + closure.to_hir(venv), ), ValueKind::PiClosure { binder, @@ -262,8 +257,8 @@ impl Value { closure, } => ExprKind::Pi( binder.to_label(), - annot.to_tyexpr(venv), - closure.to_tyexpr(venv), + annot.to_hir(venv), + closure.to_hir(venv), ), ValueKind::Const(c) => ExprKind::Const(*c), ValueKind::BoolLit(b) => ExprKind::BoolLit(*b), @@ -271,81 +266,75 @@ impl Value { ValueKind::IntegerLit(n) => ExprKind::IntegerLit(*n), ValueKind::DoubleLit(n) => ExprKind::DoubleLit(*n), ValueKind::EmptyOptionalLit(n) => ExprKind::App( - Value::from_builtin(Builtin::OptionalNone).to_tyexpr(venv), - n.to_tyexpr(venv), + Value::from_builtin(Builtin::OptionalNone).to_hir(venv), + n.to_hir(venv), ), ValueKind::NEOptionalLit(n) => { - ExprKind::SomeLit(n.to_tyexpr(venv)) - } - ValueKind::EmptyListLit(n) => { - ExprKind::EmptyListLit(TyExpr::new( - TyExprKind::Expr(ExprKind::App( - Value::from_builtin(Builtin::List).to_tyexpr(venv), - n.to_tyexpr(venv), - )), - Some(Value::from_const(Const::Type)), - Span::Artificial, - )) + ExprKind::SomeLit(n.to_hir(venv)) } + ValueKind::EmptyListLit(n) => ExprKind::EmptyListLit(Hir::new( + HirKind::Expr(ExprKind::App( + Value::from_builtin(Builtin::List).to_hir(venv), + n.to_hir(venv), + )), + Span::Artificial, + )), ValueKind::NEListLit(elts) => ExprKind::NEListLit( - elts.iter().map(|v| v.to_tyexpr(venv)).collect(), + elts.iter().map(|v| v.to_hir(venv)).collect(), ), ValueKind::TextLit(elts) => ExprKind::TextLit( elts.iter() - .map(|t| t.map_ref(|v| v.to_tyexpr(venv))) + .map(|t| t.map_ref(|v| v.to_hir(venv))) .collect(), ), ValueKind::RecordLit(kvs) => ExprKind::RecordLit( kvs.iter() - .map(|(k, v)| (k.clone(), v.to_tyexpr(venv))) + .map(|(k, v)| (k.clone(), v.to_hir(venv))) .collect(), ), ValueKind::RecordType(kts) => ExprKind::RecordType( kts.iter() - .map(|(k, v)| (k.clone(), v.to_tyexpr(venv))) + .map(|(k, v)| (k.clone(), v.to_hir(venv))) .collect(), ), ValueKind::UnionType(kts) => map_uniontype(kts), ValueKind::UnionConstructor(l, kts, t) => ExprKind::Field( - TyExpr::new( - TyExprKind::Expr(map_uniontype(kts)), - Some(t.clone()), + Hir::new( + HirKind::Expr(map_uniontype(kts)), Span::Artificial, ), l.clone(), ), ValueKind::UnionLit(l, v, kts, uniont, ctort) => ExprKind::App( - TyExpr::new( - TyExprKind::Expr(ExprKind::Field( - TyExpr::new( - TyExprKind::Expr(map_uniontype(kts)), - Some(uniont.clone()), + Hir::new( + HirKind::Expr(ExprKind::Field( + Hir::new( + HirKind::Expr(map_uniontype(kts)), Span::Artificial, ), l.clone(), )), - Some(ctort.clone()), Span::Artificial, ), - v.to_tyexpr(venv), + v.to_hir(venv), ), ValueKind::Equivalence(x, y) => ExprKind::BinOp( BinOp::Equivalence, - x.to_tyexpr(venv), - y.to_tyexpr(venv), + x.to_hir(venv), + y.to_hir(venv), ), - ValueKind::PartialExpr(e) => e.map_ref(|v| v.to_tyexpr(venv)), + ValueKind::PartialExpr(e) => e.map_ref(|v| v.to_hir(venv)), }), }; - TyExpr::new(tye, self.0.ty.clone(), self.0.span.clone()) + Hir::new(hir, self.0.span.clone()) } pub fn to_tyexpr_tyenv(&self, tyenv: &TyEnv) -> TyExpr { - let expr = self.to_tyexpr(tyenv.as_varenv()).to_expr_tyenv(tyenv); + let expr = self.to_hir(tyenv.as_varenv()).to_expr_tyenv(tyenv); type_with(tyenv, &expr).unwrap() } pub fn to_tyexpr_noenv(&self) -> TyExpr { - self.to_tyexpr(VarEnv::new()) + self.to_tyexpr_tyenv(&TyEnv::new()) } } @@ -461,7 +450,7 @@ impl ValueKind { } impl Thunk { - fn new(env: &NzEnv, body: TyExpr) -> Self { + fn new(env: &NzEnv, body: Hir) -> Self { Thunk::Thunk { env: env.clone(), body, @@ -475,14 +464,14 @@ impl Thunk { } fn eval(self) -> ValueKind { match self { - Thunk::Thunk { env, body } => normalize_tyexpr_whnf(&body, &env), + Thunk::Thunk { env, body } => normalize_hir_whnf(&env, &body), Thunk::PartialExpr { env, expr } => normalize_one_layer(expr, &env), } } } impl Closure { - pub fn new(env: &NzEnv, body: TyExpr) -> Self { + pub fn new(env: &NzEnv, body: Hir) -> Self { Closure::Closure { env: env.clone(), body, @@ -512,10 +501,11 @@ impl Closure { // TODO: somehow normalize the body. Might require to pass an env. pub fn normalize(&self) {} - /// Convert this closure to a TyExpr - pub fn to_tyexpr(&self, venv: VarEnv) -> TyExpr { + + /// Convert this closure to a Hir expression + pub fn to_hir(&self, venv: VarEnv) -> Hir { self.apply_var(NzVar::new(venv.size())) - .to_tyexpr(venv.insert()) + .to_hir(venv.insert()) } /// If the closure variable is free in the closure, return Err. Otherwise, return the value /// with that free variable remove. diff --git a/dhall/src/semantics/tck/env.rs b/dhall/src/semantics/tck/env.rs index b3e7895..af955f4 100644 --- a/dhall/src/semantics/tck/env.rs +++ b/dhall/src/semantics/tck/env.rs @@ -21,9 +21,9 @@ pub(crate) struct TyEnv { } impl VarEnv { - pub fn new() -> Self { - VarEnv { size: 0 } - } + // pub fn new() -> Self { + // VarEnv { size: 0 } + // } pub fn size(&self) -> usize { self.size } diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index fa578c0..29099c5 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -1,8 +1,6 @@ use crate::error::{TypeError, TypeMessage}; -use crate::semantics::{ - rc, AlphaVar, Hir, HirKind, NameEnv, NzEnv, TyEnv, Value, -}; -use crate::syntax::{ExprKind, Span, V}; +use crate::semantics::{AlphaVar, Hir, HirKind, NzEnv, Value}; +use crate::syntax::{ExprKind, Span}; use crate::Normalized; use crate::{NormalizedExpr, ToExprOptions}; @@ -56,13 +54,10 @@ impl TyExpr { pub fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { self.to_hir().to_expr(opts) } - pub fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { - self.to_hir().to_expr_tyenv(env) - } /// Eval the TyExpr. It will actually get evaluated only as needed on demand. pub fn eval(&self, env: &NzEnv) -> Value { - Value::new_thunk(env, self.clone()) + Value::new_thunk(env, self.to_hir()) } /// Eval a closed TyExpr (i.e. without free variables). It will actually get evaluated only as /// needed on demand. diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 810e483..5b233f8 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -266,17 +266,10 @@ fn type_one_layer( let x_ty = x.get_type()?; if x_ty != t { return span_err(&format!( - "annot mismatch: ({} : {}) : {}", - x.to_expr_tyenv(env), - x_ty.to_tyexpr_tyenv(env).to_expr_tyenv(env), - t.to_tyexpr_tyenv(env).to_expr_tyenv(env) + "annot mismatch: {} != {}", + x_ty.to_expr_tyenv(env), + t.to_expr_tyenv(env) )); - // return span_err(format!( - // "annot mismatch: {} != {}", - // x_ty.to_tyexpr_tyenv(env).to_expr_tyenv(env), - // t.to_tyexpr_tyenv(env).to_expr_tyenv(env) - // )); - // return span_err(format!("annot mismatch: {:#?} : {:#?}", x, t,)); } x_ty } -- cgit v1.2.3 From 5688ed654eee258bf8ffc8761ce693c73a0242d5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 11:58:11 +0000 Subject: Remove extra types stored in Value --- dhall/src/semantics/builtins.rs | 28 ++++++---------------------- dhall/src/semantics/nze/normalize.rs | 24 ++++++++---------------- dhall/src/semantics/nze/value.rs | 15 ++++++--------- 3 files changed, 20 insertions(+), 47 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs index 423364d..715e045 100644 --- a/dhall/src/semantics/builtins.rs +++ b/dhall/src/semantics/builtins.rs @@ -19,10 +19,6 @@ pub(crate) struct BuiltinClosure { pub b: Builtin, /// Arguments applied to the closure so far. pub args: Vec, - /// Keeps the types of the partial applications around to be able to convert back to TyExpr. - /// If the args so far are `x_1`, ..., `x_n`, this contains the types of `b`, `b x1`, ..., - /// `b x_1 x_2 ... x_(n-1)`. - pub types: Vec, } impl BuiltinClosure { @@ -31,15 +27,13 @@ impl BuiltinClosure { env, b, args: Vec::new(), - types: Vec::new(), } } - pub fn apply(&self, a: Value, f_ty: Value) -> ValueKind { + pub fn apply(&self, a: Value) -> ValueKind { use std::iter::once; let args = self.args.iter().cloned().chain(once(a.clone())).collect(); - let types = self.types.iter().cloned().chain(once(f_ty)).collect(); - apply_builtin(self.b, args, types, self.env.clone()) + apply_builtin(self.b, args, self.env.clone()) } /// This doesn't break the invariant because we already checked that the appropriate arguments /// did not normalize to something that allows evaluation to proceed. @@ -49,9 +43,9 @@ impl BuiltinClosure { } } pub fn to_hirkind(&self, venv: VarEnv) -> HirKind { - HirKind::Expr(self.args.iter().zip(self.types.iter()).fold( + HirKind::Expr(self.args.iter().fold( ExprKind::Builtin(self.b), - |acc, (v, ty)| { + |acc, v| { ExprKind::App( Hir::new(HirKind::Expr(acc), Span::Artificial), v.to_hir(venv), @@ -260,12 +254,7 @@ macro_rules! make_closure { } #[allow(clippy::cognitive_complexity)] -fn apply_builtin( - b: Builtin, - args: Vec, - types: Vec, - env: NzEnv, -) -> ValueKind { +fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { use Builtin::*; use ValueKind::*; @@ -493,12 +482,7 @@ fn apply_builtin( match ret { Ret::ValueKind(v) => v, Ret::Value(v) => v.kind().clone(), - Ret::DoneAsIs => AppliedBuiltin(BuiltinClosure { - b, - args, - types, - env, - }), + Ret::DoneAsIs => AppliedBuiltin(BuiltinClosure { b, args, env }), } } diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index acb2e51..981d894 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -13,16 +13,10 @@ pub(crate) fn apply_any(f: Value, a: Value) -> ValueKind { ValueKind::LamClosure { closure, .. } => { closure.apply(a).kind().clone() } - ValueKind::AppliedBuiltin(closure) => { - closure.apply(a, f.get_type_not_sort()) + ValueKind::AppliedBuiltin(closure) => closure.apply(a), + ValueKind::UnionConstructor(l, kts) => { + ValueKind::UnionLit(l.clone(), a, kts.clone()) } - ValueKind::UnionConstructor(l, kts, uniont) => ValueKind::UnionLit( - l.clone(), - a, - kts.clone(), - uniont.clone(), - f.get_type_not_sort(), - ), _ => ValueKind::PartialExpr(ExprKind::App(f, a)), } } @@ -326,11 +320,9 @@ pub(crate) fn normalize_one_layer( Some(r) => Ret::Value(r.clone()), None => Ret::Expr(expr), }, - UnionType(kts) => Ret::ValueKind(UnionConstructor( - l.clone(), - kts.clone(), - v.get_type_not_sort(), - )), + UnionType(kts) => { + Ret::ValueKind(UnionConstructor(l.clone(), kts.clone())) + } PartialExpr(ExprKind::BinOp( BinOp::RightBiasedRecordMerge, x, @@ -402,11 +394,11 @@ pub(crate) fn normalize_one_layer( ExprKind::Merge(ref handlers, ref variant, _) => { match handlers.kind() { RecordLit(kvs) => match variant.kind() { - UnionConstructor(l, _, _) => match kvs.get(l) { + UnionConstructor(l, _) => match kvs.get(l) { Some(h) => Ret::Value(h.clone()), None => Ret::Expr(expr), }, - UnionLit(l, v, _, _, _) => match kvs.get(l) { + UnionLit(l, v, _) => match kvs.get(l) { Some(h) => Ret::Value(h.app(v.clone())), None => Ret::Expr(expr), }, diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index d05c545..a771b91 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -93,10 +93,8 @@ pub(crate) enum ValueKind { RecordType(HashMap), RecordLit(HashMap), UnionType(HashMap>), - // Also keep the type of the uniontype around - UnionConstructor(Label, HashMap>, Value), - // Also keep the type of the uniontype and the constructor around - UnionLit(Label, Value, HashMap>, Value, Value), + UnionConstructor(Label, HashMap>), + UnionLit(Label, Value, HashMap>), TextLit(TextLit), Equivalence(Value, Value), /// Invariant: evaluation must not be able to progress with `normalize_one_layer`? @@ -298,14 +296,14 @@ impl Value { .collect(), ), ValueKind::UnionType(kts) => map_uniontype(kts), - ValueKind::UnionConstructor(l, kts, t) => ExprKind::Field( + ValueKind::UnionConstructor(l, kts) => ExprKind::Field( Hir::new( HirKind::Expr(map_uniontype(kts)), Span::Artificial, ), l.clone(), ), - ValueKind::UnionLit(l, v, kts, uniont, ctort) => ExprKind::App( + ValueKind::UnionLit(l, v, kts) => ExprKind::App( Hir::new( HirKind::Expr(ExprKind::Field( Hir::new( @@ -418,13 +416,12 @@ impl ValueKind { x.normalize(); } } - ValueKind::UnionType(kts) - | ValueKind::UnionConstructor(_, kts, _) => { + ValueKind::UnionType(kts) | ValueKind::UnionConstructor(_, kts) => { for x in kts.values().flat_map(|opt| opt) { x.normalize(); } } - ValueKind::UnionLit(_, v, kts, _, _) => { + ValueKind::UnionLit(_, v, kts) => { v.normalize(); for x in kts.values().flat_map(|opt| opt) { x.normalize(); -- cgit v1.2.3 From bbcb0c497dcf922d19bd529ceb936aff9d71a732 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 12:29:05 +0000 Subject: Introduce environment for import resolution --- dhall/src/semantics/resolve.rs | 87 +++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 31 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index 3acf114..5ec6192 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -18,11 +18,42 @@ type ImportCache = HashMap; pub(crate) type ImportStack = Vec; +struct ResolveEnv { + cache: ImportCache, + stack: ImportStack, +} + +impl ResolveEnv { + pub fn new() -> Self { + ResolveEnv { + cache: HashMap::new(), + stack: Vec::new(), + } + } + pub fn to_import_stack(&self) -> ImportStack { + self.stack.clone() + } + pub fn check_cyclic_import(&self, import: &Import) -> bool { + self.stack.contains(import) + } + pub fn get_from_cache(&self, import: &Import) -> Option<&Normalized> { + self.cache.get(import) + } + pub fn push_on_stack(&mut self, import: Import) { + self.stack.push(import) + } + pub fn pop_from_stack(&mut self) { + self.stack.pop(); + } + pub fn insert_cache(&mut self, import: Import, expr: Normalized) { + self.cache.insert(import, expr); + } +} + fn resolve_import( + env: &mut ResolveEnv, import: &Import, root: &ImportRoot, - import_cache: &mut ImportCache, - import_stack: &ImportStack, ) -> Result { use self::ImportRoot::*; use syntax::FilePrefix::*; @@ -39,53 +70,47 @@ fn resolve_import( Here => cwd.join(path_buf), _ => unimplemented!("{:?}", import), }; - Ok(load_import(&path_buf, import_cache, import_stack).map_err( - |e| ImportError::Recursive(import.clone(), Box::new(e)), - )?) + Ok(load_import(env, &path_buf).map_err(|e| { + ImportError::Recursive(import.clone(), Box::new(e)) + })?) } _ => unimplemented!("{:?}", import), } } -fn load_import( - f: &Path, - import_cache: &mut ImportCache, - import_stack: &ImportStack, -) -> Result { - Ok( - do_resolve_expr(Parsed::parse_file(f)?, import_cache, import_stack)? - .typecheck()? - .normalize(), - ) +fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { + Ok(do_resolve_expr(env, Parsed::parse_file(f)?)? + .typecheck()? + .normalize()) } fn do_resolve_expr( + env: &mut ResolveEnv, parsed: Parsed, - import_cache: &mut ImportCache, - import_stack: &ImportStack, ) -> Result { let Parsed(mut expr, root) = parsed; let mut resolve = |import: Import| -> Result { - if import_stack.contains(&import) { - return Err(ImportError::ImportCycle(import_stack.clone(), import)); + if env.check_cyclic_import(&import) { + return Err(ImportError::ImportCycle( + env.to_import_stack(), + import, + )); } - match import_cache.get(&import) { + match env.get_from_cache(&import) { Some(expr) => Ok(expr.clone()), None => { - // Copy the import stack and push the current import - let mut import_stack = import_stack.clone(); - import_stack.push(import.clone()); + // Push the current import on the stack + env.push_on_stack(import.clone()); // Resolve the import recursively - let expr = resolve_import( - &import, - &root, - import_cache, - &import_stack, - )?; + let expr = resolve_import(env, &import, &root)?; + + // Remove import from the stack. + env.pop_from_stack(); // Add the import to the cache - import_cache.insert(import, expr.clone()); + env.insert_cache(import, expr.clone()); + Ok(expr) } } @@ -95,7 +120,7 @@ fn do_resolve_expr( } pub(crate) fn resolve(e: Parsed) -> Result { - do_resolve_expr(e, &mut HashMap::new(), &Vec::new()) + do_resolve_expr(&mut ResolveEnv::new(), e) } pub(crate) fn skip_resolve_expr( -- cgit v1.2.3 From 5c342a5688fe7a4bb337ce0622968226d524022e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 15:32:27 +0000 Subject: Resolve by ref instead of by mut --- dhall/src/semantics/resolve.rs | 136 +++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 59 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index 5ec6192..223cfa4 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use crate::error::{Error, ImportError}; use crate::syntax; -use crate::syntax::{FilePath, ImportLocation, URL}; +use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; use crate::{Normalized, NormalizedExpr, Parsed, Resolved}; type Import = syntax::Import; @@ -30,27 +30,40 @@ impl ResolveEnv { stack: Vec::new(), } } - pub fn to_import_stack(&self) -> ImportStack { - self.stack.clone() - } - pub fn check_cyclic_import(&self, import: &Import) -> bool { - self.stack.contains(import) - } - pub fn get_from_cache(&self, import: &Import) -> Option<&Normalized> { - self.cache.get(import) - } - pub fn push_on_stack(&mut self, import: Import) { - self.stack.push(import) - } - pub fn pop_from_stack(&mut self) { - self.stack.pop(); - } - pub fn insert_cache(&mut self, import: Import, expr: Normalized) { - self.cache.insert(import, expr); + + pub fn handle_import( + &mut self, + import: Import, + mut do_resolve: impl FnMut( + &mut Self, + &Import, + ) -> Result, + ) -> Result { + if self.stack.contains(&import) { + return Err(ImportError::ImportCycle(self.stack.clone(), import)); + } + Ok(match self.cache.get(&import) { + Some(expr) => expr.clone(), + None => { + // Push the current import on the stack + self.stack.push(import.clone()); + + // Resolve the import recursively + let expr = do_resolve(self, &import)?; + + // Remove import from the stack. + self.stack.pop(); + + // Add the import to the cache + self.cache.insert(import, expr.clone()); + + expr + } + }) } } -fn resolve_import( +fn resolve_one_import( env: &mut ResolveEnv, import: &Import, root: &ImportRoot, @@ -79,59 +92,64 @@ fn resolve_import( } fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { - Ok(do_resolve_expr(env, Parsed::parse_file(f)?)? - .typecheck()? - .normalize()) + let parsed = Parsed::parse_file(f)?; + Ok(resolve_with_env(env, parsed)?.typecheck()?.normalize()) } -fn do_resolve_expr( +/// Traverse the expression, handling import alternatives and passing +/// found imports to the provided function. +fn traverse_resolve_expr( + expr: &Expr, + f: &mut impl FnMut(Import) -> Result, +) -> Result, ImportError> { + Ok(match expr.kind() { + ExprKind::BinOp(BinOp::ImportAlt, l, r) => { + match traverse_resolve_expr(l, f) { + Ok(l) => l, + Err(_) => { + match traverse_resolve_expr(r, f) { + Ok(r) => r, + // TODO: keep track of the other error too + Err(e) => return Err(e), + } + } + } + } + kind => { + let kind = kind.traverse_ref(|e| traverse_resolve_expr(e, f))?; + expr.rewrap(match kind { + ExprKind::Import(import) => ExprKind::Embed(f(import)?), + kind => kind, + }) + } + }) +} + +fn resolve_with_env( env: &mut ResolveEnv, parsed: Parsed, ) -> Result { - let Parsed(mut expr, root) = parsed; - let mut resolve = |import: Import| -> Result { - if env.check_cyclic_import(&import) { - return Err(ImportError::ImportCycle( - env.to_import_stack(), - import, - )); - } - match env.get_from_cache(&import) { - Some(expr) => Ok(expr.clone()), - None => { - // Push the current import on the stack - env.push_on_stack(import.clone()); - - // Resolve the import recursively - let expr = resolve_import(env, &import, &root)?; - - // Remove import from the stack. - env.pop_from_stack(); - - // Add the import to the cache - env.insert_cache(import, expr.clone()); - - Ok(expr) - } - } - }; - expr.traverse_resolve_mut(&mut resolve)?; - Ok(Resolved(expr)) + let Parsed(expr, root) = parsed; + let resolved = traverse_resolve_expr(&expr, &mut |import| { + env.handle_import(import, |env, import| { + resolve_one_import(env, import, &root) + }) + })?; + Ok(Resolved(resolved)) } -pub(crate) fn resolve(e: Parsed) -> Result { - do_resolve_expr(&mut ResolveEnv::new(), e) +pub(crate) fn resolve(parsed: Parsed) -> Result { + resolve_with_env(&mut ResolveEnv::new(), parsed) } pub(crate) fn skip_resolve_expr( parsed: Parsed, ) -> Result { - let mut expr = parsed.0; - let mut resolve = |import: Import| -> Result { + let Parsed(expr, _) = parsed; + let resolved = traverse_resolve_expr(&expr, &mut |import| { Err(ImportError::UnexpectedImport(import)) - }; - expr.traverse_resolve_mut(&mut resolve)?; - Ok(Resolved(expr)) + })?; + Ok(Resolved(resolved)) } pub trait Canonicalize { -- cgit v1.2.3 From a709c65eb28f1b6a666f15bfc2255da7bc7105ab Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 21:38:37 +0000 Subject: Resolve variables alongside import resolution --- dhall/src/semantics/hir.rs | 36 +++++++++++--- dhall/src/semantics/resolve.rs | 93 ++++++++++++++++++++++-------------- dhall/src/semantics/tck/typecheck.rs | 2 +- 3 files changed, 87 insertions(+), 44 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index 683dbbb..80d17fb 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -1,15 +1,15 @@ #![allow(dead_code)] -use crate::semantics::{rc, NameEnv, NzEnv, TyEnv, Value}; +use crate::semantics::{NameEnv, NzEnv, TyEnv, Value}; use crate::syntax::{ExprKind, Span, V}; -use crate::{Normalized, NormalizedExpr, ToExprOptions}; +use crate::{Expr, Normalized, NormalizedExpr, ToExprOptions}; /// Stores an alpha-normalized variable. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct AlphaVar { idx: usize, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) enum HirKind { Var(AlphaVar), // Forbidden ExprKind variants: Var, Import, Embed @@ -51,6 +51,14 @@ impl Hir { pub fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { hir_to_expr(self, opts, &mut NameEnv::new()) } + /// Converts a HIR expr back to the corresponding AST expression. + pub fn to_expr_noopts(&self) -> NormalizedExpr { + let opts = ToExprOptions { + normalize: false, + alpha: false, + }; + self.to_expr(opts) + } pub fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { let opts = ToExprOptions { normalize: true, @@ -82,7 +90,7 @@ fn hir_to_expr( opts: ToExprOptions, env: &mut NameEnv, ) -> NormalizedExpr { - rc(match hir.kind() { + let kind = match hir.kind() { HirKind::Var(v) if opts.alpha => ExprKind::Var(V("_".into(), v.idx())), HirKind::Var(v) => ExprKind::Var(env.label_var(v)), HirKind::Expr(e) => { @@ -107,5 +115,21 @@ fn hir_to_expr( e => e, } } - }) + }; + Expr::new(kind, hir.span()) +} + +impl std::cmp::PartialEq for Hir { + fn eq(&self, other: &Self) -> bool { + self.kind == other.kind + } +} +impl std::cmp::Eq for Hir {} +impl std::hash::Hash for Hir { + fn hash(&self, state: &mut H) + where + H: std::hash::Hasher, + { + self.kind.hash(state) + } } diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index 223cfa4..e12e892 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -1,12 +1,14 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; +use crate::error::ErrorBuilder; use crate::error::{Error, ImportError}; +use crate::semantics::{mkerr, Hir, HirKind, NameEnv}; use crate::syntax; use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; -use crate::{Normalized, NormalizedExpr, Parsed, Resolved}; +use crate::{Normalized, Parsed, Resolved}; -type Import = syntax::Import; +type Import = syntax::Import; /// A root from which to resolve relative imports. #[derive(Debug, Clone, PartialEq, Eq)] @@ -34,13 +36,12 @@ impl ResolveEnv { pub fn handle_import( &mut self, import: Import, - mut do_resolve: impl FnMut( - &mut Self, - &Import, - ) -> Result, - ) -> Result { + mut do_resolve: impl FnMut(&mut Self, &Import) -> Result, + ) -> Result { if self.stack.contains(&import) { - return Err(ImportError::ImportCycle(self.stack.clone(), import)); + return Err( + ImportError::ImportCycle(self.stack.clone(), import).into() + ); } Ok(match self.cache.get(&import) { Some(expr) => expr.clone(), @@ -67,7 +68,7 @@ fn resolve_one_import( env: &mut ResolveEnv, import: &Import, root: &ImportRoot, -) -> Result { +) -> Result { use self::ImportRoot::*; use syntax::FilePrefix::*; use syntax::ImportLocation::*; @@ -83,9 +84,7 @@ fn resolve_one_import( Here => cwd.join(path_buf), _ => unimplemented!("{:?}", import), }; - Ok(load_import(env, &path_buf).map_err(|e| { - ImportError::Recursive(import.clone(), Box::new(e)) - })?) + Ok(load_import(env, &path_buf)?) } _ => unimplemented!("{:?}", import), } @@ -99,56 +98,76 @@ fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { /// Traverse the expression, handling import alternatives and passing /// found imports to the provided function. fn traverse_resolve_expr( + name_env: &mut NameEnv, expr: &Expr, - f: &mut impl FnMut(Import) -> Result, -) -> Result, ImportError> { - Ok(match expr.kind() { + f: &mut impl FnMut(Import) -> Result, +) -> Result { + let kind = match expr.kind() { + ExprKind::Var(var) => match name_env.unlabel_var(&var) { + Some(v) => HirKind::Var(v), + None => mkerr( + ErrorBuilder::new(format!("unbound variable `{}`", var)) + .span_err(expr.span(), "not found in this scope") + .format(), + )?, + }, ExprKind::BinOp(BinOp::ImportAlt, l, r) => { - match traverse_resolve_expr(l, f) { - Ok(l) => l, + return match traverse_resolve_expr(name_env, l, f) { + Ok(l) => Ok(l), Err(_) => { - match traverse_resolve_expr(r, f) { - Ok(r) => r, + match traverse_resolve_expr(name_env, r, f) { + Ok(r) => Ok(r), // TODO: keep track of the other error too - Err(e) => return Err(e), + Err(e) => Err(e), } } - } + }; } kind => { - let kind = kind.traverse_ref(|e| traverse_resolve_expr(e, f))?; - expr.rewrap(match kind { + let kind = kind.traverse_ref_maybe_binder(|l, e| { + if let Some(l) = l { + name_env.insert_mut(l); + } + let hir = traverse_resolve_expr(name_env, e, f)?; + if let Some(_) = l { + name_env.remove_mut(); + } + Ok::<_, Error>(hir) + })?; + HirKind::Expr(match kind { ExprKind::Import(import) => ExprKind::Embed(f(import)?), kind => kind, }) } - }) + }; + + Ok(Hir::new(kind, expr.span())) } fn resolve_with_env( env: &mut ResolveEnv, parsed: Parsed, -) -> Result { +) -> Result { let Parsed(expr, root) = parsed; - let resolved = traverse_resolve_expr(&expr, &mut |import| { - env.handle_import(import, |env, import| { - resolve_one_import(env, import, &root) - }) - })?; + let resolved = + traverse_resolve_expr(&mut NameEnv::new(), &expr, &mut |import| { + env.handle_import(import, |env, import| { + resolve_one_import(env, import, &root) + }) + })?; Ok(Resolved(resolved)) } -pub(crate) fn resolve(parsed: Parsed) -> Result { +pub(crate) fn resolve(parsed: Parsed) -> Result { resolve_with_env(&mut ResolveEnv::new(), parsed) } -pub(crate) fn skip_resolve_expr( - parsed: Parsed, -) -> Result { +pub(crate) fn skip_resolve_expr(parsed: Parsed) -> Result { let Parsed(expr, _) = parsed; - let resolved = traverse_resolve_expr(&expr, &mut |import| { - Err(ImportError::UnexpectedImport(import)) - })?; + let resolved = + traverse_resolve_expr(&mut NameEnv::new(), &expr, &mut |import| { + Err(ImportError::UnexpectedImport(import).into()) + })?; Ok(Resolved(resolved)) } diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 5b233f8..eb6a58c 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -43,7 +43,7 @@ fn function_check(a: Const, b: Const) -> Const { } } -fn mkerr(x: S) -> Result { +pub fn mkerr(x: S) -> Result { Err(TypeError::new(TypeMessage::Custom(x.to_string()))) } -- cgit v1.2.3 From 21db63d3e614554f258526182c7ed89a2c244b65 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 21:58:28 +0000 Subject: Take Hir for typecheck --- dhall/src/semantics/builtins.rs | 12 +++++--- dhall/src/semantics/mod.rs | 1 + dhall/src/semantics/nze/value.rs | 7 +++-- dhall/src/semantics/resolve.rs | 13 +++----- dhall/src/semantics/tck/env.rs | 12 +++----- dhall/src/semantics/tck/typecheck.rs | 60 +++++++++++++++++------------------- 6 files changed, 51 insertions(+), 54 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs index 715e045..b1d12aa 100644 --- a/dhall/src/semantics/builtins.rs +++ b/dhall/src/semantics/builtins.rs @@ -1,5 +1,5 @@ use crate::semantics::{ - typecheck, Hir, HirKind, NzEnv, Value, ValueKind, VarEnv, + skip_resolve, typecheck, Hir, HirKind, NzEnv, Value, ValueKind, VarEnv, }; use crate::syntax::map::DupTreeMap; use crate::syntax::Const::Type; @@ -115,9 +115,9 @@ macro_rules! make_type { }; } -pub(crate) fn type_of_builtin(b: Builtin) -> Expr { +pub(crate) fn type_of_builtin(b: Builtin) -> Hir { use Builtin::*; - match b { + let expr = match b { Bool | Natural | Integer | Double | Text => make_type!(Type), List | Optional => make_type!( Type -> Type @@ -200,7 +200,8 @@ pub(crate) fn type_of_builtin(b: Builtin) -> Expr { OptionalNone => make_type!( forall (A: Type) -> Optional A ), - } + }; + skip_resolve(&expr).unwrap() } // Ad-hoc macro to help construct closures @@ -264,7 +265,8 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { Value(Value), DoneAsIs, } - let make_closure = |e| typecheck(&e).unwrap().eval(&env); + let make_closure = + |e| typecheck(&skip_resolve(&e).unwrap()).unwrap().eval(&env); let ret = match (b, args.as_slice()) { (OptionalNone, [t]) => Ret::ValueKind(EmptyOptionalLit(t.clone())), diff --git a/dhall/src/semantics/mod.rs b/dhall/src/semantics/mod.rs index a8c0659..ffa16ca 100644 --- a/dhall/src/semantics/mod.rs +++ b/dhall/src/semantics/mod.rs @@ -7,4 +7,5 @@ pub mod tck; pub(crate) use self::builtins::*; pub(crate) use self::hir::*; pub(crate) use self::nze::*; +pub(crate) use self::resolve::*; pub(crate) use self::tck::*; diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index a771b91..48acdb5 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -327,9 +327,12 @@ impl Value { Hir::new(hir, self.0.span.clone()) } + pub fn to_hir_noenv(&self) -> Hir { + self.to_hir(VarEnv::new()) + } pub fn to_tyexpr_tyenv(&self, tyenv: &TyEnv) -> TyExpr { - let expr = self.to_hir(tyenv.as_varenv()).to_expr_tyenv(tyenv); - type_with(tyenv, &expr).unwrap() + let hir = self.to_hir(tyenv.as_varenv()); + type_with(tyenv, &hir).unwrap() } pub fn to_tyexpr_noenv(&self) -> TyExpr { self.to_tyexpr_tyenv(&TyEnv::new()) diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index e12e892..8c9bb05 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -6,7 +6,7 @@ use crate::error::{Error, ImportError}; use crate::semantics::{mkerr, Hir, HirKind, NameEnv}; use crate::syntax; use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; -use crate::{Normalized, Parsed, Resolved}; +use crate::{Normalized, Parsed, ParsedExpr, Resolved}; type Import = syntax::Import; @@ -162,13 +162,10 @@ pub(crate) fn resolve(parsed: Parsed) -> Result { resolve_with_env(&mut ResolveEnv::new(), parsed) } -pub(crate) fn skip_resolve_expr(parsed: Parsed) -> Result { - let Parsed(expr, _) = parsed; - let resolved = - traverse_resolve_expr(&mut NameEnv::new(), &expr, &mut |import| { - Err(ImportError::UnexpectedImport(import).into()) - })?; - Ok(Resolved(resolved)) +pub(crate) fn skip_resolve(expr: &ParsedExpr) -> Result { + traverse_resolve_expr(&mut NameEnv::new(), expr, &mut |import| { + Err(ImportError::UnexpectedImport(import).into()) + }) } pub trait Canonicalize { diff --git a/dhall/src/semantics/tck/env.rs b/dhall/src/semantics/tck/env.rs index af955f4..3b02074 100644 --- a/dhall/src/semantics/tck/env.rs +++ b/dhall/src/semantics/tck/env.rs @@ -21,9 +21,9 @@ pub(crate) struct TyEnv { } impl VarEnv { - // pub fn new() -> Self { - // VarEnv { size: 0 } - // } + pub fn new() -> Self { + VarEnv { size: 0 } + } pub fn size(&self) -> usize { self.size } @@ -116,9 +116,7 @@ impl TyEnv { items: self.items.insert_value(e, ty), } } - pub fn lookup(&self, var: &V) -> Option<(AlphaVar, Type)> { - let var = self.names.unlabel_var(var)?; - let ty = self.items.lookup_ty(&var); - Some((var, ty)) + pub fn lookup(&self, var: &AlphaVar) -> Type { + self.items.lookup_ty(&var) } } diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index eb6a58c..ac113cd 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -5,11 +5,11 @@ use std::collections::HashMap; use crate::error::{ErrorBuilder, TypeError, TypeMessage}; use crate::semantics::merge_maps; use crate::semantics::{ - type_of_builtin, Binder, BuiltinClosure, Closure, TyEnv, TyExpr, - TyExprKind, Type, Value, ValueKind, + type_of_builtin, Binder, BuiltinClosure, Closure, Hir, HirKind, TyEnv, + TyExpr, TyExprKind, Type, Value, ValueKind, }; use crate::syntax::{ - BinOp, Builtin, Const, Expr, ExprKind, InterpolatedTextContents, Span, + BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, Span, }; use crate::Normalized; @@ -115,8 +115,8 @@ fn type_one_layer( ExprKind::Const(Const::Type) => Value::from_const(Const::Kind), ExprKind::Const(Const::Kind) => Value::from_const(Const::Sort), ExprKind::Builtin(b) => { - let t_expr = type_of_builtin(*b); - let t_tyexpr = type_with(env, &t_expr)?; + let t_hir = type_of_builtin(*b); + let t_tyexpr = typecheck(&t_hir)?; t_tyexpr.eval(env.as_nzenv()) } ExprKind::BoolLit(_) => Value::from_builtin(Builtin::Bool), @@ -761,25 +761,16 @@ fn type_one_layer( } /// `type_with` typechecks an expressio in the provided environment. -pub(crate) fn type_with( - env: &TyEnv, - expr: &Expr, -) -> Result { - let (tyekind, ty) = match expr.as_ref() { - ExprKind::Var(var) => match env.lookup(&var) { - Some((v, ty)) => (TyExprKind::Var(v), Some(ty)), - None => { - return mkerr( - ErrorBuilder::new(format!("unbound variable `{}`", var)) - .span_err(expr.span(), "not found in this scope") - .format(), - ) - } - }, - ExprKind::Const(Const::Sort) => { +pub(crate) fn type_with(env: &TyEnv, hir: &Hir) -> Result { + let (tyekind, ty) = match hir.kind() { + HirKind::Var(var) => (TyExprKind::Var(*var), Some(env.lookup(&var))), + HirKind::Expr(ExprKind::Var(_)) => { + unreachable!("Hir should contain no unresolved variables") + } + HirKind::Expr(ExprKind::Const(Const::Sort)) => { (TyExprKind::Expr(ExprKind::Const(Const::Sort)), None) } - ExprKind::Embed(p) => { + HirKind::Expr(ExprKind::Embed(p)) => { let val = p.clone().into_value(); ( val.to_tyexpr_noenv().kind().clone(), @@ -787,7 +778,7 @@ pub(crate) fn type_with( ) // return Ok(p.clone().into_value().to_tyexpr_noenv()) } - ekind => { + HirKind::Expr(ekind) => { let ekind = match ekind { ExprKind::Lam(binder, annot, body) => { let annot = type_with(env, annot)?; @@ -805,7 +796,13 @@ pub(crate) fn type_with( } ExprKind::Let(binder, annot, val, body) => { let val = if let Some(t) = annot { - t.rewrap(ExprKind::Annot(val.clone(), t.clone())) + Hir::new( + HirKind::Expr(ExprKind::Annot( + val.clone(), + t.clone(), + )), + t.span(), + ) } else { val.clone() }; @@ -818,16 +815,16 @@ pub(crate) fn type_with( } _ => ekind.traverse_ref(|e| type_with(env, e))?, }; - return type_one_layer(env, ekind, expr.span()); + return type_one_layer(env, ekind, hir.span()); } }; - Ok(TyExpr::new(tyekind, ty, expr.span())) + Ok(TyExpr::new(tyekind, ty, hir.span())) } /// Typecheck an expression and return the expression annotated with types if type-checking /// succeeded, or an error if type-checking failed. -pub(crate) fn typecheck(e: &Expr) -> Result { +pub(crate) fn typecheck(e: &Hir) -> Result { let res = type_with(&TyEnv::new(), e)?; // Ensure that the inferred type exists (i.e. this is not Sort) res.get_type()?; @@ -835,9 +832,8 @@ pub(crate) fn typecheck(e: &Expr) -> Result { } /// Like `typecheck`, but additionally checks that the expression's type matches the provided type. -pub(crate) fn typecheck_with( - expr: &Expr, - ty: Expr, -) -> Result { - typecheck(&expr.rewrap(ExprKind::Annot(expr.clone(), ty))) +pub(crate) fn typecheck_with(hir: &Hir, ty: Hir) -> Result { + let hir = + Hir::new(HirKind::Expr(ExprKind::Annot(hir.clone(), ty)), hir.span()); + typecheck(&hir) } -- cgit v1.2.3 From ad085a20bc257d03a52708d920cfc65f0e9051e6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 22:07:03 +0000 Subject: Remove all types from Value --- dhall/src/semantics/builtins.rs | 14 ++----- dhall/src/semantics/hir.rs | 4 +- dhall/src/semantics/nze/env.rs | 3 +- dhall/src/semantics/nze/value.rs | 80 ++++----------------------------------- dhall/src/semantics/tck/tyexpr.rs | 4 +- 5 files changed, 16 insertions(+), 89 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs index b1d12aa..9d4f8a2 100644 --- a/dhall/src/semantics/builtins.rs +++ b/dhall/src/semantics/builtins.rs @@ -370,17 +370,9 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { } _ => Ret::DoneAsIs, }, - (ListIndexed, [_, l]) => { - let l_whnf = l.kind(); - match &*l_whnf { + (ListIndexed, [t, l]) => { + match l.kind() { EmptyListLit(_) | NEListLit(_) => { - // Extract the type of the list elements - let t = match &*l_whnf { - EmptyListLit(t) => t.clone(), - NEListLit(xs) => xs[0].get_type_not_sort(), - _ => unreachable!(), - }; - // Construct the returned record type: { index: Natural, value: t } let mut kts = HashMap::new(); kts.insert("index".into(), Value::from_builtin(Natural)); @@ -388,7 +380,7 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { let t = Value::from_kind(RecordType(kts)); // Construct the new list, with added indices - let list = match &*l_whnf { + let list = match l.kind() { EmptyListLit(_) => EmptyListLit(t), NEListLit(xs) => NEListLit( xs.iter() diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index 80d17fb..28b38e3 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -79,8 +79,8 @@ impl Hir { } /// Eval a closed Hir fully and recursively (TODO: ish, need to fix under lambdas) pub fn rec_eval_closed_expr(&self) -> Value { - let mut val = self.eval_closed_expr(); - val.normalize_mut(); + let val = self.eval_closed_expr(); + val.normalize(); val } } diff --git a/dhall/src/semantics/nze/env.rs b/dhall/src/semantics/nze/env.rs index 261e0b6..ff52343 100644 --- a/dhall/src/semantics/nze/env.rs +++ b/dhall/src/semantics/nze/env.rs @@ -60,7 +60,8 @@ impl NzEnv { env } pub fn insert_value_noty(&self, e: Value) -> Self { - let ty = e.get_type_not_sort(); + // TODO + let ty = Value::const_sort(); self.insert_value(e, ty) } pub fn lookup_val(&self, var: &AlphaVar) -> ValueKind { diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index 48acdb5..5a7b558 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::rc::Rc; -use crate::error::{TypeError, TypeMessage}; +use crate::error::TypeError; use crate::semantics::nze::lazy; use crate::semantics::{ apply_any, normalize_hir_whnf, normalize_one_layer, squash_textlit, @@ -25,8 +25,6 @@ pub(crate) struct Value(Rc); #[derive(Debug)] struct ValueInternal { kind: lazy::Lazy, - /// This is None if and only if `form` is `Sort` (which doesn't have a type) - ty: Option, span: Span, } @@ -103,25 +101,12 @@ pub(crate) enum ValueKind { impl Value { pub(crate) fn const_sort() -> Value { - ValueInternal::from_whnf( - ValueKind::Const(Const::Sort), - None, - Span::Artificial, - ) - .into_value() - } - pub(crate) fn const_kind() -> Value { - Value::from_const(Const::Kind) + Value::from_const(Const::Sort) } /// Construct a Value from a completely unnormalized expression. pub(crate) fn new_thunk(env: &NzEnv, hir: Hir) -> Value { let span = hir.span(); - ValueInternal::from_thunk( - Thunk::new(env, hir), - Some(Value::const_kind()), - span, - ) - .into_value() + ValueInternal::from_thunk(Thunk::new(env, hir), span).into_value() } /// Construct a Value from a partially normalized expression that's not in WHNF. pub(crate) fn from_partial_expr(e: ExprKind) -> Value { @@ -129,33 +114,17 @@ impl Value { let env = NzEnv::new(); ValueInternal::from_thunk( Thunk::from_partial_expr(env, e), - Some(Value::const_kind()), Span::Artificial, ) .into_value() } /// Make a Value from a ValueKind pub(crate) fn from_kind(v: ValueKind) -> Value { - ValueInternal::from_whnf(v, Some(Value::const_kind()), Span::Artificial) - .into_value() + ValueInternal::from_whnf(v, Span::Artificial).into_value() } pub(crate) fn from_const(c: Const) -> Self { let v = ValueKind::Const(c); - match c { - Const::Type => ValueInternal::from_whnf( - v, - Some(Value::from_const(Const::Kind)), - Span::Artificial, - ) - .into_value(), - Const::Kind => ValueInternal::from_whnf( - v, - Some(Value::const_sort()), - Span::Artificial, - ) - .into_value(), - Const::Sort => Value::const_sort(), - } + ValueInternal::from_whnf(v, Span::Artificial).into_value() } pub(crate) fn from_builtin(b: Builtin) -> Self { Self::from_builtin_env(b, &NzEnv::new()) @@ -193,16 +162,6 @@ impl Value { self.to_hir(env.as_varenv()).to_expr_tyenv(env) } - /// Normalizes contents to normal form; faster than `normalize` if - /// no one else shares this. - pub(crate) fn normalize_mut(&mut self) { - match Rc::get_mut(&mut self.0) { - // Mutate directly if sole owner - Some(vint) => vint.normalize_mut(), - // Otherwise mutate through the refcell - None => self.normalize(), - } - } pub(crate) fn normalize(&self) { self.0.normalize() } @@ -214,13 +173,6 @@ impl Value { pub(crate) fn get_type(&self, tyenv: &TyEnv) -> Result { self.to_tyexpr_tyenv(tyenv).get_type() } - /// When we know the value isn't `Sort`, this gets the type directly - pub(crate) fn get_type_not_sort(&self) -> Value { - self.0 - .get_type() - .expect("Internal type error: value is `Sort` but shouldn't be") - .clone() - } pub fn to_hir(&self, venv: VarEnv) -> Hir { let map_uniontype = |kts: &HashMap>| { @@ -340,17 +292,15 @@ impl Value { } impl ValueInternal { - fn from_whnf(k: ValueKind, ty: Option, span: Span) -> Self { + fn from_whnf(k: ValueKind, span: Span) -> Self { ValueInternal { kind: lazy::Lazy::new_completed(k), - ty, span, } } - fn from_thunk(th: Thunk, ty: Option, span: Span) -> Self { + fn from_thunk(th: Thunk, span: Span) -> Self { ValueInternal { kind: lazy::Lazy::new(th), - ty, span, } } @@ -364,17 +314,6 @@ impl ValueInternal { fn normalize(&self) { self.kind().normalize(); } - // TODO: deprecated - fn normalize_mut(&mut self) { - self.normalize(); - } - - fn get_type(&self) -> Result<&Value, TypeError> { - match &self.ty { - Some(t) => Ok(t), - None => Err(TypeError::new(TypeMessage::Sort)), - } - } } impl ValueKind { @@ -616,11 +555,6 @@ impl std::fmt::Debug for Value { } let mut x = fmt.debug_struct(&format!("Value@WHNF")); x.field("kind", kind); - if let Some(ty) = vint.ty.as_ref() { - x.field("type", &ty); - } else { - x.field("type", &None::<()>); - } x.finish() } } diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index 29099c5..05fa4b5 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -66,8 +66,8 @@ impl TyExpr { } /// Eval a closed TyExpr fully and recursively; pub fn rec_eval_closed_expr(&self) -> Value { - let mut val = self.eval_closed_expr(); - val.normalize_mut(); + let val = self.eval_closed_expr(); + val.normalize(); val } } -- cgit v1.2.3 From f6732982c522dd579d378ab4820001d5ae107c43 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 22:18:32 +0000 Subject: Automate conversion between envs --- dhall/src/semantics/tck/env.rs | 6 ++++++ dhall/src/semantics/tck/tyexpr.rs | 4 ++-- dhall/src/semantics/tck/typecheck.rs | 38 +++++++++++++++++------------------- 3 files changed, 26 insertions(+), 22 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/tck/env.rs b/dhall/src/semantics/tck/env.rs index 3b02074..ba7fb73 100644 --- a/dhall/src/semantics/tck/env.rs +++ b/dhall/src/semantics/tck/env.rs @@ -120,3 +120,9 @@ impl TyEnv { self.items.lookup_ty(&var) } } + +impl<'a> From<&'a TyEnv> for &'a NzEnv { + fn from(x: &'a TyEnv) -> Self { + x.as_nzenv() + } +} diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index 05fa4b5..edba477 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -56,8 +56,8 @@ impl TyExpr { } /// Eval the TyExpr. It will actually get evaluated only as needed on demand. - pub fn eval(&self, env: &NzEnv) -> Value { - Value::new_thunk(env, self.to_hir()) + pub fn eval<'e>(&self, env: impl Into<&'e NzEnv>) -> Value { + Value::new_thunk(env.into(), self.to_hir()) } /// Eval a closed TyExpr (i.e. without free variables). It will actually get evaluated only as /// needed on demand. diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index ac113cd..7f02832 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -73,11 +73,10 @@ fn type_one_layer( ExprKind::Lam(binder, annot, body) => { let body_ty = body.get_type()?; let body_ty = body_ty.to_tyexpr_tyenv( - &env.insert_type(&binder.clone(), annot.eval(env.as_nzenv())), + &env.insert_type(&binder.clone(), annot.eval(env)), ); let pi_ekind = ExprKind::Pi(binder.clone(), annot.clone(), body_ty); - type_one_layer(env, pi_ekind, Span::Artificial)? - .eval(env.as_nzenv()) + type_one_layer(env, pi_ekind, Span::Artificial)?.eval(env) } ExprKind::Pi(_, annot, body) => { let ks = match annot.get_type()?.as_const() { @@ -117,7 +116,7 @@ fn type_one_layer( ExprKind::Builtin(b) => { let t_hir = type_of_builtin(*b); let t_tyexpr = typecheck(&t_hir)?; - t_tyexpr.eval(env.as_nzenv()) + t_tyexpr.eval(env) } ExprKind::BoolLit(_) => Value::from_builtin(Builtin::Bool), ExprKind::NaturalLit(_) => Value::from_builtin(Builtin::Natural), @@ -136,7 +135,7 @@ fn type_one_layer( text_type } ExprKind::EmptyListLit(t) => { - let t = t.eval(env.as_nzenv()); + let t = t.eval(env); match &*t.kind() { ValueKind::AppliedBuiltin(BuiltinClosure { b: Builtin::List, @@ -242,7 +241,7 @@ fn type_one_layer( }, // TODO: branch here only when scrut.get_type() is a Const _ => { - let scrut_nf = scrut.eval(env.as_nzenv()); + let scrut_nf = scrut.eval(env); match scrut_nf.kind() { ValueKind::UnionType(kts) => match kts.get(x) { // Constructor has type T -> < x: T, ... > @@ -262,7 +261,7 @@ fn type_one_layer( } } ExprKind::Annot(x, t) => { - let t = t.eval(env.as_nzenv()); + let t = t.eval(env); let x_ty = x.get_type()?; if x_ty != t { return span_err(&format!( @@ -274,7 +273,7 @@ fn type_one_layer( x_ty } ExprKind::Assert(t) => { - let t = t.eval(env.as_nzenv()); + let t = t.eval(env); match &*t.kind() { ValueKind::Equivalence(x, y) if x == y => {} ValueKind::Equivalence(..) => { @@ -315,7 +314,7 @@ fn type_one_layer( ); } - let arg_nf = arg.eval(env.as_nzenv()); + let arg_nf = arg.eval(env); closure.apply(arg_nf) } _ => return mkerr( @@ -380,11 +379,11 @@ fn type_one_layer( x.get_type()?.to_tyexpr_tyenv(env), y.get_type()?.to_tyexpr_tyenv(env), ); - type_one_layer(env, ekind, Span::Artificial)?.eval(env.as_nzenv()) + type_one_layer(env, ekind, Span::Artificial)?.eval(env) } ExprKind::BinOp(BinOp::RecursiveRecordTypeMerge, x, y) => { - let x_val = x.eval(env.as_nzenv()); - let y_val = y.eval(env.as_nzenv()); + let x_val = x.eval(env); + let y_val = y.eval(env); let kts_x = match x_val.kind() { ValueKind::RecordType(kts) => kts, _ => return span_err("RecordTypeMergeRequiresRecordType"), @@ -589,8 +588,7 @@ fn type_one_layer( } } - let type_annot = - type_annot.as_ref().map(|t| t.eval(env.as_nzenv())); + let type_annot = type_annot.as_ref().map(|t| t.eval(env)); match (inferred_type, type_annot) { (Some(t1), Some(t2)) => { if t1 != t2 { @@ -621,7 +619,7 @@ fn type_one_layer( annotation", ); }; - let annot_val = annot.eval(env.as_nzenv()); + let annot_val = annot.eval(env); let err_msg = "The type of `toMap x` must be of the form \ `List { mapKey : Text, mapValue : T }`"; @@ -670,7 +668,7 @@ fn type_one_layer( let output_type = Value::from_builtin(Builtin::List) .app(Value::from_kind(ValueKind::RecordType(kts))); if let Some(annot) = annot { - let annot_val = annot.eval(env.as_nzenv()); + let annot_val = annot.eval(env); if output_type != annot_val { return span_err("Annotation mismatch"); } @@ -710,7 +708,7 @@ fn type_one_layer( _ => return span_err("ProjectionMustBeRecord"), }; - let selection_val = selection.eval(env.as_nzenv()); + let selection_val = selection.eval(env); let sel_kts = match selection_val.kind() { ValueKind::RecordType(kts) => kts, _ => return span_err("ProjectionByExprTakesRecordType"), @@ -782,14 +780,14 @@ pub(crate) fn type_with(env: &TyEnv, hir: &Hir) -> Result { let ekind = match ekind { ExprKind::Lam(binder, annot, body) => { let annot = type_with(env, annot)?; - let annot_nf = annot.eval(env.as_nzenv()); + let annot_nf = annot.eval(env); let body_env = env.insert_type(binder, annot_nf); let body = type_with(&body_env, body)?; ExprKind::Lam(binder.clone(), annot, body) } ExprKind::Pi(binder, annot, body) => { let annot = type_with(env, annot)?; - let annot_nf = annot.eval(env.as_nzenv()); + let annot_nf = annot.eval(env); let body_env = env.insert_type(binder, annot_nf); let body = type_with(&body_env, body)?; ExprKind::Pi(binder.clone(), annot, body) @@ -808,7 +806,7 @@ pub(crate) fn type_with(env: &TyEnv, hir: &Hir) -> Result { }; let val = type_with(env, &val)?; let val_ty = val.get_type()?; - let val_nf = val.eval(&env.as_nzenv()); + let val_nf = val.eval(env); let body_env = env.insert_value(&binder, val_nf, val_ty); let body = type_with(&body_env, body)?; ExprKind::Let(binder.clone(), None, val, body) -- cgit v1.2.3 From 35cc98dc767247f4881866de40c7d8dd82eba8a5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 22:30:32 +0000 Subject: Remove types from NzEnv --- dhall/src/semantics/builtins.rs | 7 ++++-- dhall/src/semantics/hir.rs | 2 +- dhall/src/semantics/nze/env.rs | 42 +++++++++++++++++++++--------------- dhall/src/semantics/nze/normalize.rs | 2 +- dhall/src/semantics/nze/value.rs | 18 ++++++---------- dhall/src/semantics/tck/env.rs | 14 ++++++------ dhall/src/semantics/tck/tyexpr.rs | 4 ++-- 7 files changed, 47 insertions(+), 42 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs index 9d4f8a2..d9a3599 100644 --- a/dhall/src/semantics/builtins.rs +++ b/dhall/src/semantics/builtins.rs @@ -265,8 +265,11 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { Value(Value), DoneAsIs, } - let make_closure = - |e| typecheck(&skip_resolve(&e).unwrap()).unwrap().eval(&env); + let make_closure = |e| { + typecheck(&skip_resolve(&e).unwrap()) + .unwrap() + .eval(env.clone()) + }; let ret = match (b, args.as_slice()) { (OptionalNone, [t]) => Ret::ValueKind(EmptyOptionalLit(t.clone())), diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index 28b38e3..9ad7374 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -70,7 +70,7 @@ impl Hir { /// Eval the Hir. It will actually get evaluated only as needed on demand. pub fn eval(&self, env: &NzEnv) -> Value { - Value::new_thunk(env, self.clone()) + Value::new_thunk(env.clone(), self.clone()) } /// Eval a closed Hir (i.e. without free variables). It will actually get evaluated only as /// needed on demand. diff --git a/dhall/src/semantics/nze/env.rs b/dhall/src/semantics/nze/env.rs index ff52343..5b036f0 100644 --- a/dhall/src/semantics/nze/env.rs +++ b/dhall/src/semantics/nze/env.rs @@ -1,4 +1,4 @@ -use crate::semantics::{AlphaVar, Type, Value, ValueKind}; +use crate::semantics::{AlphaVar, Value, ValueKind}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum NzVar { @@ -9,7 +9,7 @@ pub(crate) enum NzVar { } #[derive(Debug, Clone)] -enum NzEnvItem { +enum EnvItem { // Variable is bound with given type Kept(Type), // Variable has been replaced by corresponding value @@ -17,10 +17,12 @@ enum NzEnvItem { } #[derive(Debug, Clone)] -pub(crate) struct NzEnv { - items: Vec, +pub(crate) struct ValEnv { + items: Vec>, } +pub(crate) type NzEnv = ValEnv<()>; + impl NzVar { pub fn new(idx: usize) -> Self { NzVar::Bound(idx) @@ -44,37 +46,43 @@ impl NzVar { } } -impl NzEnv { +impl ValEnv { pub fn new() -> Self { - NzEnv { items: Vec::new() } + ValEnv { items: Vec::new() } + } + pub fn discard_types(&self) -> ValEnv<()> { + let items = self + .items + .iter() + .map(|i| match i { + EnvItem::Kept(_) => EnvItem::Kept(()), + EnvItem::Replaced(val, _) => EnvItem::Replaced(val.clone(), ()), + }) + .collect(); + ValEnv { items } } pub fn insert_type(&self, ty: Type) -> Self { let mut env = self.clone(); - env.items.push(NzEnvItem::Kept(ty)); + env.items.push(EnvItem::Kept(ty)); env } pub fn insert_value(&self, e: Value, ty: Type) -> Self { let mut env = self.clone(); - env.items.push(NzEnvItem::Replaced(e, ty)); + env.items.push(EnvItem::Replaced(e, ty)); env } - pub fn insert_value_noty(&self, e: Value) -> Self { - // TODO - let ty = Value::const_sort(); - self.insert_value(e, ty) - } pub fn lookup_val(&self, var: &AlphaVar) -> ValueKind { let idx = self.items.len() - 1 - var.idx(); match &self.items[idx] { - NzEnvItem::Kept(_) => ValueKind::Var(NzVar::new(idx)), - NzEnvItem::Replaced(x, _) => x.kind().clone(), + EnvItem::Kept(_) => ValueKind::Var(NzVar::new(idx)), + EnvItem::Replaced(x, _) => x.kind().clone(), } } - pub fn lookup_ty(&self, var: &AlphaVar) -> Value { + pub fn lookup_ty(&self, var: &AlphaVar) -> Type { let idx = self.items.len() - 1 - var.idx(); match &self.items[idx] { - NzEnvItem::Kept(ty) | NzEnvItem::Replaced(_, ty) => ty.clone(), + EnvItem::Kept(ty) | EnvItem::Replaced(_, ty) => ty.clone(), } } } diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index 981d894..d12146a 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -473,7 +473,7 @@ pub(crate) fn normalize_hir_whnf(env: &NzEnv, hir: &Hir) -> ValueKind { } HirKind::Expr(ExprKind::Let(_, None, val, body)) => { let val = val.eval(env); - body.eval(&env.insert_value_noty(val)).kind().clone() + body.eval(&env.insert_value(val, ())).kind().clone() } HirKind::Expr(e) => { let e = e.map_ref(|hir| hir.eval(env)); diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index 5a7b558..a60be9d 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -100,11 +100,8 @@ pub(crate) enum ValueKind { } impl Value { - pub(crate) fn const_sort() -> Value { - Value::from_const(Const::Sort) - } /// Construct a Value from a completely unnormalized expression. - pub(crate) fn new_thunk(env: &NzEnv, hir: Hir) -> Value { + pub(crate) fn new_thunk(env: NzEnv, hir: Hir) -> Value { let span = hir.span(); ValueInternal::from_thunk(Thunk::new(env, hir), span).into_value() } @@ -158,8 +155,8 @@ impl Value { self.to_tyexpr_noenv().to_expr(opts) } - pub(crate) fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { - self.to_hir(env.as_varenv()).to_expr_tyenv(env) + pub(crate) fn to_expr_tyenv(&self, tyenv: &TyEnv) -> NormalizedExpr { + self.to_hir(tyenv.as_varenv()).to_expr_tyenv(tyenv) } pub(crate) fn normalize(&self) { @@ -389,11 +386,8 @@ impl ValueKind { } impl Thunk { - fn new(env: &NzEnv, body: Hir) -> Self { - Thunk::Thunk { - env: env.clone(), - body, - } + fn new(env: NzEnv, body: Hir) -> Self { + Thunk::Thunk { env, body } } fn from_partial_expr( env: NzEnv, @@ -424,7 +418,7 @@ impl Closure { pub fn apply(&self, val: Value) -> Value { match self { Closure::Closure { env, body, .. } => { - body.eval(&env.insert_value_noty(val)) + body.eval(&env.insert_value(val, ())) } Closure::ConstantClosure { body, .. } => body.clone(), } diff --git a/dhall/src/semantics/tck/env.rs b/dhall/src/semantics/tck/env.rs index ba7fb73..7990059 100644 --- a/dhall/src/semantics/tck/env.rs +++ b/dhall/src/semantics/tck/env.rs @@ -1,4 +1,4 @@ -use crate::semantics::{AlphaVar, NzEnv, NzVar, Type, Value}; +use crate::semantics::{AlphaVar, NzEnv, NzVar, Type, ValEnv, Value}; use crate::syntax::{Label, V}; /// Environment for indexing variables. @@ -17,7 +17,7 @@ pub(crate) struct NameEnv { #[derive(Debug, Clone)] pub(crate) struct TyEnv { names: NameEnv, - items: NzEnv, + items: ValEnv, } impl VarEnv { @@ -91,14 +91,14 @@ impl TyEnv { pub fn new() -> Self { TyEnv { names: NameEnv::new(), - items: NzEnv::new(), + items: ValEnv::new(), } } pub fn as_varenv(&self) -> VarEnv { self.names.as_varenv() } - pub fn as_nzenv(&self) -> &NzEnv { - &self.items + pub fn to_nzenv(&self) -> NzEnv { + self.items.discard_types() } pub fn as_nameenv(&self) -> &NameEnv { &self.names @@ -121,8 +121,8 @@ impl TyEnv { } } -impl<'a> From<&'a TyEnv> for &'a NzEnv { +impl<'a> From<&'a TyEnv> for NzEnv { fn from(x: &'a TyEnv) -> Self { - x.as_nzenv() + x.to_nzenv() } } diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index edba477..a1666a4 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -56,13 +56,13 @@ impl TyExpr { } /// Eval the TyExpr. It will actually get evaluated only as needed on demand. - pub fn eval<'e>(&self, env: impl Into<&'e NzEnv>) -> Value { + pub fn eval(&self, env: impl Into) -> Value { Value::new_thunk(env.into(), self.to_hir()) } /// Eval a closed TyExpr (i.e. without free variables). It will actually get evaluated only as /// needed on demand. pub fn eval_closed_expr(&self) -> Value { - self.eval(&NzEnv::new()) + self.eval(NzEnv::new()) } /// Eval a closed TyExpr fully and recursively; pub fn rec_eval_closed_expr(&self) -> Value { -- cgit v1.2.3 From c3ed75dc4b354becac0821e4288105dc2a300c4c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 10 Feb 2020 19:14:07 +0000 Subject: Remove need for Embed This was an archaic leftover from copying the Haskell datatypes anyway --- dhall/src/semantics/hir.rs | 1 + dhall/src/semantics/nze/env.rs | 6 ++++++ dhall/src/semantics/resolve.rs | 25 ++++++++++++++----------- dhall/src/semantics/tck/typecheck.rs | 10 +--------- 4 files changed, 22 insertions(+), 20 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index 9ad7374..b45851f 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -11,6 +11,7 @@ pub struct AlphaVar { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) enum HirKind { + /// A resolved variable (i.e. a DeBruijn index) Var(AlphaVar), // Forbidden ExprKind variants: Var, Import, Embed Expr(ExprKind), diff --git a/dhall/src/semantics/nze/env.rs b/dhall/src/semantics/nze/env.rs index 5b036f0..241af40 100644 --- a/dhall/src/semantics/nze/env.rs +++ b/dhall/src/semantics/nze/env.rs @@ -86,3 +86,9 @@ impl ValEnv { } } } + +impl<'a> From<&'a NzEnv> for NzEnv { + fn from(x: &'a NzEnv) -> Self { + x.clone() + } +} diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index 8c9bb05..80e5132 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -16,7 +16,7 @@ pub(crate) enum ImportRoot { LocalDir(PathBuf), } -type ImportCache = HashMap; +type ImportCache = HashMap; pub(crate) type ImportStack = Vec; @@ -36,8 +36,8 @@ impl ResolveEnv { pub fn handle_import( &mut self, import: Import, - mut do_resolve: impl FnMut(&mut Self, &Import) -> Result, - ) -> Result { + mut do_resolve: impl FnMut(&mut Self, &Import) -> Result, + ) -> Result { if self.stack.contains(&import) { return Err( ImportError::ImportCycle(self.stack.clone(), import).into() @@ -68,7 +68,7 @@ fn resolve_one_import( env: &mut ResolveEnv, import: &Import, root: &ImportRoot, -) -> Result { +) -> Result { use self::ImportRoot::*; use syntax::FilePrefix::*; use syntax::ImportLocation::*; @@ -90,9 +90,12 @@ fn resolve_one_import( } } -fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { +fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { let parsed = Parsed::parse_file(f)?; - Ok(resolve_with_env(env, parsed)?.typecheck()?.normalize()) + Ok(resolve_with_env(env, parsed)? + .typecheck()? + .normalize() + .to_hir()) } /// Traverse the expression, handling import alternatives and passing @@ -100,7 +103,7 @@ fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { fn traverse_resolve_expr( name_env: &mut NameEnv, expr: &Expr, - f: &mut impl FnMut(Import) -> Result, + f: &mut impl FnMut(Import) -> Result, ) -> Result { let kind = match expr.kind() { ExprKind::Var(var) => match name_env.unlabel_var(&var) { @@ -134,10 +137,10 @@ fn traverse_resolve_expr( } Ok::<_, Error>(hir) })?; - HirKind::Expr(match kind { - ExprKind::Import(import) => ExprKind::Embed(f(import)?), - kind => kind, - }) + match kind { + ExprKind::Import(import) => f(import)?.kind().clone(), + kind => HirKind::Expr(kind), + } } }; diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 7f02832..4e45637 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -761,21 +761,13 @@ fn type_one_layer( /// `type_with` typechecks an expressio in the provided environment. pub(crate) fn type_with(env: &TyEnv, hir: &Hir) -> Result { let (tyekind, ty) = match hir.kind() { - HirKind::Var(var) => (TyExprKind::Var(*var), Some(env.lookup(&var))), + HirKind::Var(var) => (TyExprKind::Var(*var), Some(env.lookup(var))), HirKind::Expr(ExprKind::Var(_)) => { unreachable!("Hir should contain no unresolved variables") } HirKind::Expr(ExprKind::Const(Const::Sort)) => { (TyExprKind::Expr(ExprKind::Const(Const::Sort)), None) } - HirKind::Expr(ExprKind::Embed(p)) => { - let val = p.clone().into_value(); - ( - val.to_tyexpr_noenv().kind().clone(), - Some(val.get_type(&TyEnv::new())?), - ) - // return Ok(p.clone().into_value().to_tyexpr_noenv()) - } HirKind::Expr(ekind) => { let ekind = match ekind { ExprKind::Lam(binder, annot, body) => { -- cgit v1.2.3 From 5a2538d174fd36a8ed7f4fa344b9583fc48bd977 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 11 Feb 2020 13:12:13 +0000 Subject: Remove the Embed variant from ExprKind --- dhall/src/semantics/builtins.rs | 2 +- dhall/src/semantics/hir.rs | 8 ++++---- dhall/src/semantics/nze/normalize.rs | 6 ++---- dhall/src/semantics/nze/value.rs | 16 +++++----------- dhall/src/semantics/resolve.rs | 4 ++-- dhall/src/semantics/tck/tyexpr.rs | 3 +-- dhall/src/semantics/tck/typecheck.rs | 7 ++----- 7 files changed, 17 insertions(+), 29 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs index d9a3599..cbb5a6e 100644 --- a/dhall/src/semantics/builtins.rs +++ b/dhall/src/semantics/builtins.rs @@ -55,7 +55,7 @@ impl BuiltinClosure { } } -pub(crate) fn rc(x: UnspannedExpr) -> Expr { +pub(crate) fn rc(x: UnspannedExpr) -> Expr { Expr::new(x, Span::Artificial) } diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index b45851f..288031c 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use crate::semantics::{NameEnv, NzEnv, TyEnv, Value}; -use crate::syntax::{ExprKind, Span, V}; -use crate::{Expr, Normalized, NormalizedExpr, ToExprOptions}; +use crate::syntax::{Expr, ExprKind, Span, V}; +use crate::{NormalizedExpr, ToExprOptions}; /// Stores an alpha-normalized variable. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -13,8 +13,8 @@ pub struct AlphaVar { pub(crate) enum HirKind { /// A resolved variable (i.e. a DeBruijn index) Var(AlphaVar), - // Forbidden ExprKind variants: Var, Import, Embed - Expr(ExprKind), + // Forbidden ExprKind variants: Var, Import + Expr(ExprKind), } // An expression with resolved variables and imports. diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index d12146a..03b91a5 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -6,7 +6,6 @@ use crate::semantics::{ Binder, BuiltinClosure, Closure, Hir, HirKind, TextLit, Value, ValueKind, }; use crate::syntax::{BinOp, Builtin, ExprKind, InterpolatedTextContents}; -use crate::Normalized; pub(crate) fn apply_any(f: Value, a: Value) -> ValueKind { match f.kind() { @@ -90,7 +89,7 @@ enum Ret<'a> { ValueKind(ValueKind), Value(Value), ValueRef(&'a Value), - Expr(ExprKind), + Expr(ExprKind), } fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { @@ -215,7 +214,7 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { } pub(crate) fn normalize_one_layer( - expr: ExprKind, + expr: ExprKind, env: &NzEnv, ) -> ValueKind { use ValueKind::{ @@ -233,7 +232,6 @@ pub(crate) fn normalize_one_layer( ExprKind::Lam(..) | ExprKind::Pi(..) | ExprKind::Let(..) - | ExprKind::Embed(_) | ExprKind::Var(_) => { unreachable!("This case should have been handled in typecheck") } diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index a60be9d..0df3c74 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -12,7 +12,7 @@ use crate::syntax::{ BinOp, Builtin, Const, ExprKind, Integer, InterpolatedTextContents, Label, NaiveDouble, Natural, Span, }; -use crate::{Normalized, NormalizedExpr, ToExprOptions}; +use crate::{NormalizedExpr, ToExprOptions}; /// Stores a possibly unevaluated value. Gets (partially) normalized on-demand, sharing computation /// automatically. Uses a Rc to share computation. @@ -34,10 +34,7 @@ pub(crate) enum Thunk { /// A completely unnormalized expression. Thunk { env: NzEnv, body: Hir }, /// A partially normalized expression that may need to go through `normalize_one_layer`. - PartialExpr { - env: NzEnv, - expr: ExprKind, - }, + PartialExpr { env: NzEnv, expr: ExprKind }, } /// An unevaluated subexpression that takes an argument. @@ -96,7 +93,7 @@ pub(crate) enum ValueKind { TextLit(TextLit), Equivalence(Value, Value), /// Invariant: evaluation must not be able to progress with `normalize_one_layer`? - PartialExpr(ExprKind), + PartialExpr(ExprKind), } impl Value { @@ -106,7 +103,7 @@ impl Value { ValueInternal::from_thunk(Thunk::new(env, hir), span).into_value() } /// Construct a Value from a partially normalized expression that's not in WHNF. - pub(crate) fn from_partial_expr(e: ExprKind) -> Value { + pub(crate) fn from_partial_expr(e: ExprKind) -> Value { // TODO: env let env = NzEnv::new(); ValueInternal::from_thunk( @@ -389,10 +386,7 @@ impl Thunk { fn new(env: NzEnv, body: Hir) -> Self { Thunk::Thunk { env, body } } - fn from_partial_expr( - env: NzEnv, - expr: ExprKind, - ) -> Self { + fn from_partial_expr(env: NzEnv, expr: ExprKind) -> Self { Thunk::PartialExpr { env, expr } } fn eval(self) -> ValueKind { diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index 80e5132..fac88d2 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -6,7 +6,7 @@ use crate::error::{Error, ImportError}; use crate::semantics::{mkerr, Hir, HirKind, NameEnv}; use crate::syntax; use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; -use crate::{Normalized, Parsed, ParsedExpr, Resolved}; +use crate::{Parsed, ParsedExpr, Resolved}; type Import = syntax::Import; @@ -102,7 +102,7 @@ fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { /// found imports to the provided function. fn traverse_resolve_expr( name_env: &mut NameEnv, - expr: &Expr, + expr: &Expr, f: &mut impl FnMut(Import) -> Result, ) -> Result { let kind = match expr.kind() { diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index a1666a4..d46ab87 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -1,7 +1,6 @@ use crate::error::{TypeError, TypeMessage}; use crate::semantics::{AlphaVar, Hir, HirKind, NzEnv, Value}; use crate::syntax::{ExprKind, Span}; -use crate::Normalized; use crate::{NormalizedExpr, ToExprOptions}; pub(crate) type Type = Value; @@ -10,7 +9,7 @@ pub(crate) type Type = Value; pub(crate) enum TyExprKind { Var(AlphaVar), // Forbidden ExprKind variants: Var, Import, Embed - Expr(ExprKind), + Expr(ExprKind), } // An expression with inferred types at every node and resolved variables. diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 4e45637..f9ff3d3 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -11,7 +11,6 @@ use crate::semantics::{ use crate::syntax::{ BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, Span, }; -use crate::Normalized; fn type_of_recordtype<'a>( span: Span, @@ -51,7 +50,7 @@ pub fn mkerr(x: S) -> Result { /// layer. fn type_one_layer( env: &TyEnv, - ekind: ExprKind, + ekind: ExprKind, span: Span, ) -> Result { let span_err = |msg: &str| { @@ -66,9 +65,7 @@ fn type_one_layer( ExprKind::Import(..) => unreachable!( "There should remain no imports in a resolved expression" ), - ExprKind::Var(..) - | ExprKind::Const(Const::Sort) - | ExprKind::Embed(..) => unreachable!(), // Handled in type_with + ExprKind::Var(..) | ExprKind::Const(Const::Sort) => unreachable!(), // Handled in type_with ExprKind::Lam(binder, annot, body) => { let body_ty = body.get_type()?; -- cgit v1.2.3 From 40bee3cdcb9ac0c76996feeceb6ca160a6bd8b42 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 11 Feb 2020 19:04:44 +0000 Subject: Introduce LitKind to factor out common enum nodes --- dhall/src/semantics/builtins.rs | 119 ++++++++++++++++++----------------- dhall/src/semantics/nze/normalize.rs | 86 +++++++++++++------------ dhall/src/semantics/nze/value.rs | 21 ++----- dhall/src/semantics/tck/typecheck.rs | 16 +++-- 4 files changed, 124 insertions(+), 118 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs index cbb5a6e..752b25c 100644 --- a/dhall/src/semantics/builtins.rs +++ b/dhall/src/semantics/builtins.rs @@ -5,7 +5,8 @@ use crate::syntax::map::DupTreeMap; use crate::syntax::Const::Type; use crate::syntax::{ BinOp, Builtin, Const, Expr, ExprKind, InterpolatedText, - InterpolatedTextContents, Label, NaiveDouble, Span, UnspannedExpr, V, + InterpolatedTextContents, Label, LitKind, NaiveDouble, Span, UnspannedExpr, + V, }; use crate::Normalized; use std::collections::HashMap; @@ -240,7 +241,7 @@ macro_rules! make_closure { rc(ExprKind::BinOp( BinOp::NaturalPlus, make_closure!($($v)*), - rc(ExprKind::NaturalLit(1)) + rc(ExprKind::Lit(LitKind::Natural(1))) )) }; ([ $($head:tt)* ] # $($tail:tt)*) => {{ @@ -256,7 +257,7 @@ macro_rules! make_closure { #[allow(clippy::cognitive_complexity)] fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { - use Builtin::*; + use LitKind::{Bool, Double, Integer, Natural}; use ValueKind::*; // Small helper enum @@ -272,38 +273,40 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { }; let ret = match (b, args.as_slice()) { - (OptionalNone, [t]) => Ret::ValueKind(EmptyOptionalLit(t.clone())), - (NaturalIsZero, [n]) => match &*n.kind() { - NaturalLit(n) => Ret::ValueKind(BoolLit(*n == 0)), + (Builtin::OptionalNone, [t]) => { + Ret::ValueKind(EmptyOptionalLit(t.clone())) + } + (Builtin::NaturalIsZero, [n]) => match &*n.kind() { + Lit(Natural(n)) => Ret::ValueKind(Lit(Bool(*n == 0))), _ => Ret::DoneAsIs, }, - (NaturalEven, [n]) => match &*n.kind() { - NaturalLit(n) => Ret::ValueKind(BoolLit(*n % 2 == 0)), + (Builtin::NaturalEven, [n]) => match &*n.kind() { + Lit(Natural(n)) => Ret::ValueKind(Lit(Bool(*n % 2 == 0))), _ => Ret::DoneAsIs, }, - (NaturalOdd, [n]) => match &*n.kind() { - NaturalLit(n) => Ret::ValueKind(BoolLit(*n % 2 != 0)), + (Builtin::NaturalOdd, [n]) => match &*n.kind() { + Lit(Natural(n)) => Ret::ValueKind(Lit(Bool(*n % 2 != 0))), _ => Ret::DoneAsIs, }, - (NaturalToInteger, [n]) => match &*n.kind() { - NaturalLit(n) => Ret::ValueKind(IntegerLit(*n as isize)), + (Builtin::NaturalToInteger, [n]) => match &*n.kind() { + Lit(Natural(n)) => Ret::ValueKind(Lit(Integer(*n as isize))), _ => Ret::DoneAsIs, }, - (NaturalShow, [n]) => match &*n.kind() { - NaturalLit(n) => Ret::Value(Value::from_text(n)), + (Builtin::NaturalShow, [n]) => match &*n.kind() { + Lit(Natural(n)) => Ret::Value(Value::from_text(n)), _ => Ret::DoneAsIs, }, - (NaturalSubtract, [a, b]) => match (&*a.kind(), &*b.kind()) { - (NaturalLit(a), NaturalLit(b)) => { - Ret::ValueKind(NaturalLit(if b > a { b - a } else { 0 })) + (Builtin::NaturalSubtract, [a, b]) => match (&*a.kind(), &*b.kind()) { + (Lit(Natural(a)), Lit(Natural(b))) => { + Ret::ValueKind(Lit(Natural(if b > a { b - a } else { 0 }))) } - (NaturalLit(0), _) => Ret::Value(b.clone()), - (_, NaturalLit(0)) => Ret::ValueKind(NaturalLit(0)), - _ if a == b => Ret::ValueKind(NaturalLit(0)), + (Lit(Natural(0)), _) => Ret::Value(b.clone()), + (_, Lit(Natural(0))) => Ret::ValueKind(Lit(Natural(0))), + _ if a == b => Ret::ValueKind(Lit(Natural(0))), _ => Ret::DoneAsIs, }, - (IntegerShow, [n]) => match &*n.kind() { - IntegerLit(n) => { + (Builtin::IntegerShow, [n]) => match &*n.kind() { + Lit(Integer(n)) => { let s = if *n < 0 { n.to_string() } else { @@ -313,27 +316,27 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { } _ => Ret::DoneAsIs, }, - (IntegerToDouble, [n]) => match &*n.kind() { - IntegerLit(n) => { - Ret::ValueKind(DoubleLit(NaiveDouble::from(*n as f64))) + (Builtin::IntegerToDouble, [n]) => match &*n.kind() { + Lit(Integer(n)) => { + Ret::ValueKind(Lit(Double(NaiveDouble::from(*n as f64)))) } _ => Ret::DoneAsIs, }, - (IntegerNegate, [n]) => match &*n.kind() { - IntegerLit(n) => Ret::ValueKind(IntegerLit(-n)), + (Builtin::IntegerNegate, [n]) => match &*n.kind() { + Lit(Integer(n)) => Ret::ValueKind(Lit(Integer(-n))), _ => Ret::DoneAsIs, }, - (IntegerClamp, [n]) => match &*n.kind() { - IntegerLit(n) => { - Ret::ValueKind(NaturalLit((*n).try_into().unwrap_or(0))) + (Builtin::IntegerClamp, [n]) => match &*n.kind() { + Lit(Integer(n)) => { + Ret::ValueKind(Lit(Natural((*n).try_into().unwrap_or(0)))) } _ => Ret::DoneAsIs, }, - (DoubleShow, [n]) => match &*n.kind() { - DoubleLit(n) => Ret::Value(Value::from_text(n)), + (Builtin::DoubleShow, [n]) => match &*n.kind() { + Lit(Double(n)) => Ret::Value(Value::from_text(n)), _ => Ret::DoneAsIs, }, - (TextShow, [v]) => match &*v.kind() { + (Builtin::TextShow, [v]) => match &*v.kind() { TextLit(tlit) => { if let Some(s) = tlit.as_text() { // Printing InterpolatedText takes care of all the escaping @@ -347,38 +350,41 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { } _ => Ret::DoneAsIs, }, - (ListLength, [_, l]) => match &*l.kind() { - EmptyListLit(_) => Ret::ValueKind(NaturalLit(0)), - NEListLit(xs) => Ret::ValueKind(NaturalLit(xs.len())), + (Builtin::ListLength, [_, l]) => match &*l.kind() { + EmptyListLit(_) => Ret::ValueKind(Lit(Natural(0))), + NEListLit(xs) => Ret::ValueKind(Lit(Natural(xs.len()))), _ => Ret::DoneAsIs, }, - (ListHead, [_, l]) => match &*l.kind() { + (Builtin::ListHead, [_, l]) => match &*l.kind() { EmptyListLit(n) => Ret::ValueKind(EmptyOptionalLit(n.clone())), NEListLit(xs) => { Ret::ValueKind(NEOptionalLit(xs.iter().next().unwrap().clone())) } _ => Ret::DoneAsIs, }, - (ListLast, [_, l]) => match &*l.kind() { + (Builtin::ListLast, [_, l]) => match &*l.kind() { EmptyListLit(n) => Ret::ValueKind(EmptyOptionalLit(n.clone())), NEListLit(xs) => Ret::ValueKind(NEOptionalLit( xs.iter().rev().next().unwrap().clone(), )), _ => Ret::DoneAsIs, }, - (ListReverse, [_, l]) => match &*l.kind() { + (Builtin::ListReverse, [_, l]) => match &*l.kind() { EmptyListLit(n) => Ret::ValueKind(EmptyListLit(n.clone())), NEListLit(xs) => { Ret::ValueKind(NEListLit(xs.iter().rev().cloned().collect())) } _ => Ret::DoneAsIs, }, - (ListIndexed, [t, l]) => { + (Builtin::ListIndexed, [t, l]) => { match l.kind() { EmptyListLit(_) | NEListLit(_) => { // Construct the returned record type: { index: Natural, value: t } let mut kts = HashMap::new(); - kts.insert("index".into(), Value::from_builtin(Natural)); + kts.insert( + "index".into(), + Value::from_builtin(Builtin::Natural), + ); kts.insert("value".into(), t.clone()); let t = Value::from_kind(RecordType(kts)); @@ -392,7 +398,7 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { let mut kvs = HashMap::new(); kvs.insert( "index".into(), - Value::from_kind(NaturalLit(i)), + Value::from_kind(Lit(Natural(i))), ); kvs.insert("value".into(), e.clone()); Value::from_kind(RecordLit(kvs)) @@ -406,8 +412,8 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { _ => Ret::DoneAsIs, } } - (ListBuild, [t, f]) => { - let list_t = Value::from_builtin(List).app(t.clone()); + (Builtin::ListBuild, [t, f]) => { + let list_t = Value::from_builtin(Builtin::List).app(t.clone()); Ret::Value( f.app(list_t.clone()) .app( @@ -422,7 +428,7 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { .app(EmptyListLit(t.clone()).into_value()), ) } - (ListFold, [_, l, _, cons, nil]) => match &*l.kind() { + (Builtin::ListFold, [_, l, _, cons, nil]) => match &*l.kind() { EmptyListLit(_) => Ret::Value(nil.clone()), NEListLit(xs) => { let mut v = nil.clone(); @@ -433,8 +439,9 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { } _ => Ret::DoneAsIs, }, - (OptionalBuild, [t, f]) => { - let optional_t = Value::from_builtin(Optional).app(t.clone()); + (Builtin::OptionalBuild, [t, f]) => { + let optional_t = + Value::from_builtin(Builtin::Optional).app(t.clone()); Ret::Value( f.app(optional_t.clone()) .app( @@ -448,25 +455,25 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> ValueKind { .app(EmptyOptionalLit(t.clone()).into_value()), ) } - (OptionalFold, [_, v, _, just, nothing]) => match &*v.kind() { + (Builtin::OptionalFold, [_, v, _, just, nothing]) => match &*v.kind() { EmptyOptionalLit(_) => Ret::Value(nothing.clone()), NEOptionalLit(x) => Ret::Value(just.app(x.clone())), _ => Ret::DoneAsIs, }, - (NaturalBuild, [f]) => Ret::Value( - f.app(Value::from_builtin(Natural)) + (Builtin::NaturalBuild, [f]) => Ret::Value( + f.app(Value::from_builtin(Builtin::Natural)) .app(make_closure(make_closure!( λ(x : Natural) -> 1 + var(x) ))) - .app(NaturalLit(0).into_value()), + .app(Lit(Natural(0)).into_value()), ), - (NaturalFold, [n, t, succ, zero]) => match &*n.kind() { - NaturalLit(0) => Ret::Value(zero.clone()), - NaturalLit(n) => { - let fold = Value::from_builtin(NaturalFold) - .app(NaturalLit(n - 1).into_value()) + (Builtin::NaturalFold, [n, t, succ, zero]) => match &*n.kind() { + Lit(Natural(0)) => Ret::Value(zero.clone()), + Lit(Natural(n)) => { + let fold = Value::from_builtin(Builtin::NaturalFold) + .app(Lit(Natural(n - 1)).into_value()) .app(t.clone()) .app(succ.clone()) .app(zero.clone()); diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index 03b91a5..4111190 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -5,7 +5,9 @@ use crate::semantics::NzEnv; use crate::semantics::{ Binder, BuiltinClosure, Closure, Hir, HirKind, TextLit, Value, ValueKind, }; -use crate::syntax::{BinOp, Builtin, ExprKind, InterpolatedTextContents}; +use crate::syntax::{ + BinOp, Builtin, ExprKind, InterpolatedTextContents, LitKind, +}; pub(crate) fn apply_any(f: Value, a: Value) -> ValueKind { match f.kind() { @@ -98,40 +100,44 @@ fn apply_binop<'a>(o: BinOp, x: &'a Value, y: &'a Value) -> Option> { NaturalTimes, RecursiveRecordMerge, RecursiveRecordTypeMerge, RightBiasedRecordMerge, TextAppend, }; - use ValueKind::{ - BoolLit, EmptyListLit, NEListLit, NaturalLit, RecordLit, RecordType, - }; + use LitKind::{Bool, Natural}; + use ValueKind::{EmptyListLit, Lit, NEListLit, RecordLit, RecordType}; + Some(match (o, x.kind(), y.kind()) { - (BoolAnd, BoolLit(true), _) => Ret::ValueRef(y), - (BoolAnd, _, BoolLit(true)) => Ret::ValueRef(x), - (BoolAnd, BoolLit(false), _) => Ret::ValueKind(BoolLit(false)), - (BoolAnd, _, BoolLit(false)) => Ret::ValueKind(BoolLit(false)), + (BoolAnd, Lit(Bool(true)), _) => Ret::ValueRef(y), + (BoolAnd, _, Lit(Bool(true))) => Ret::ValueRef(x), + (BoolAnd, Lit(Bool(false)), _) => Ret::ValueKind(Lit(Bool(false))), + (BoolAnd, _, Lit(Bool(false))) => Ret::ValueKind(Lit(Bool(false))), (BoolAnd, _, _) if x == y => Ret::ValueRef(x), - (BoolOr, BoolLit(true), _) => Ret::ValueKind(BoolLit(true)), - (BoolOr, _, BoolLit(true)) => Ret::ValueKind(BoolLit(true)), - (BoolOr, BoolLit(false), _) => Ret::ValueRef(y), - (BoolOr, _, BoolLit(false)) => Ret::ValueRef(x), + (BoolOr, Lit(Bool(true)), _) => Ret::ValueKind(Lit(Bool(true))), + (BoolOr, _, Lit(Bool(true))) => Ret::ValueKind(Lit(Bool(true))), + (BoolOr, Lit(Bool(false)), _) => Ret::ValueRef(y), + (BoolOr, _, Lit(Bool(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::ValueKind(BoolLit(x == y)), - (BoolEQ, _, _) if x == y => Ret::ValueKind(BoolLit(true)), - (BoolNE, BoolLit(false), _) => Ret::ValueRef(y), - (BoolNE, _, BoolLit(false)) => Ret::ValueRef(x), - (BoolNE, BoolLit(x), BoolLit(y)) => Ret::ValueKind(BoolLit(x != y)), - (BoolNE, _, _) if x == y => Ret::ValueKind(BoolLit(false)), + (BoolEQ, Lit(Bool(true)), _) => Ret::ValueRef(y), + (BoolEQ, _, Lit(Bool(true))) => Ret::ValueRef(x), + (BoolEQ, Lit(Bool(x)), Lit(Bool(y))) => { + Ret::ValueKind(Lit(Bool(x == y))) + } + (BoolEQ, _, _) if x == y => Ret::ValueKind(Lit(Bool(true))), + (BoolNE, Lit(Bool(false)), _) => Ret::ValueRef(y), + (BoolNE, _, Lit(Bool(false))) => Ret::ValueRef(x), + (BoolNE, Lit(Bool(x)), Lit(Bool(y))) => { + Ret::ValueKind(Lit(Bool(x != y))) + } + (BoolNE, _, _) if x == y => Ret::ValueKind(Lit(Bool(false))), - (NaturalPlus, NaturalLit(0), _) => Ret::ValueRef(y), - (NaturalPlus, _, NaturalLit(0)) => Ret::ValueRef(x), - (NaturalPlus, NaturalLit(x), NaturalLit(y)) => { - Ret::ValueKind(NaturalLit(x + y)) - } - (NaturalTimes, NaturalLit(0), _) => Ret::ValueKind(NaturalLit(0)), - (NaturalTimes, _, NaturalLit(0)) => Ret::ValueKind(NaturalLit(0)), - (NaturalTimes, NaturalLit(1), _) => Ret::ValueRef(y), - (NaturalTimes, _, NaturalLit(1)) => Ret::ValueRef(x), - (NaturalTimes, NaturalLit(x), NaturalLit(y)) => { - Ret::ValueKind(NaturalLit(x * y)) + (NaturalPlus, Lit(Natural(0)), _) => Ret::ValueRef(y), + (NaturalPlus, _, Lit(Natural(0))) => Ret::ValueRef(x), + (NaturalPlus, Lit(Natural(x)), Lit(Natural(y))) => { + Ret::ValueKind(Lit(Natural(x + y))) + } + (NaturalTimes, Lit(Natural(0)), _) => Ret::ValueKind(Lit(Natural(0))), + (NaturalTimes, _, Lit(Natural(0))) => Ret::ValueKind(Lit(Natural(0))), + (NaturalTimes, Lit(Natural(1)), _) => Ret::ValueRef(y), + (NaturalTimes, _, Lit(Natural(1))) => Ret::ValueRef(x), + (NaturalTimes, Lit(Natural(x)), Lit(Natural(y))) => { + Ret::ValueKind(Lit(Natural(x * y))) } (ListAppend, EmptyListLit(_), _) => Ret::ValueRef(y), @@ -217,10 +223,11 @@ pub(crate) fn normalize_one_layer( expr: ExprKind, env: &NzEnv, ) -> ValueKind { + use LitKind::Bool; use ValueKind::{ - BoolLit, DoubleLit, EmptyListLit, EmptyOptionalLit, IntegerLit, - NEListLit, NEOptionalLit, NaturalLit, PartialExpr, RecordLit, - RecordType, UnionConstructor, UnionLit, UnionType, + EmptyListLit, EmptyOptionalLit, Lit, NEListLit, NEOptionalLit, + PartialExpr, RecordLit, RecordType, UnionConstructor, UnionLit, + UnionType, }; let ret = match expr { @@ -240,10 +247,7 @@ pub(crate) fn normalize_one_layer( ExprKind::Builtin(b) => Ret::Value(Value::from_builtin_env(b, env)), ExprKind::Assert(_) => Ret::Expr(expr), ExprKind::App(v, a) => Ret::Value(v.app(a)), - ExprKind::BoolLit(b) => Ret::ValueKind(BoolLit(b)), - ExprKind::NaturalLit(n) => Ret::ValueKind(NaturalLit(n)), - ExprKind::IntegerLit(n) => Ret::ValueKind(IntegerLit(n)), - ExprKind::DoubleLit(n) => Ret::ValueKind(DoubleLit(n)), + ExprKind::Lit(l) => Ret::ValueKind(Lit(l.clone())), ExprKind::SomeLit(e) => Ret::ValueKind(NEOptionalLit(e)), ExprKind::EmptyListLit(t) => { let arg = match t.kind() { @@ -279,12 +283,12 @@ pub(crate) fn normalize_one_layer( } ExprKind::BoolIf(ref b, ref e1, ref e2) => { match b.kind() { - BoolLit(true) => Ret::ValueRef(e1), - BoolLit(false) => Ret::ValueRef(e2), + Lit(Bool(true)) => Ret::ValueRef(e1), + Lit(Bool(false)) => Ret::ValueRef(e2), _ => { match (e1.kind(), e2.kind()) { // Simplify `if b then True else False` - (BoolLit(true), BoolLit(false)) => Ret::ValueRef(b), + (Lit(Bool(true)), Lit(Bool(false))) => Ret::ValueRef(b), _ if e1 == e2 => Ret::ValueRef(e1), _ => Ret::Expr(expr), } diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index 0df3c74..2ae6852 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -9,8 +9,8 @@ use crate::semantics::{ TyExpr, VarEnv, }; use crate::syntax::{ - BinOp, Builtin, Const, ExprKind, Integer, InterpolatedTextContents, Label, - NaiveDouble, Natural, Span, + BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, Label, LitKind, + Span, }; use crate::{NormalizedExpr, ToExprOptions}; @@ -76,10 +76,7 @@ pub(crate) enum ValueKind { Var(NzVar), Const(Const), - BoolLit(bool), - NaturalLit(Natural), - IntegerLit(Integer), - DoubleLit(NaiveDouble), + Lit(LitKind), EmptyOptionalLit(Value), NEOptionalLit(Value), // EmptyListLit(t) means `[] : List t`, not `[] : t` @@ -205,10 +202,7 @@ impl Value { closure.to_hir(venv), ), ValueKind::Const(c) => ExprKind::Const(*c), - ValueKind::BoolLit(b) => ExprKind::BoolLit(*b), - ValueKind::NaturalLit(n) => ExprKind::NaturalLit(*n), - ValueKind::IntegerLit(n) => ExprKind::IntegerLit(*n), - ValueKind::DoubleLit(n) => ExprKind::DoubleLit(*n), + ValueKind::Lit(l) => ExprKind::Lit(l.clone()), ValueKind::EmptyOptionalLit(n) => ExprKind::App( Value::from_builtin(Builtin::OptionalNone).to_hir(venv), n.to_hir(venv), @@ -317,12 +311,7 @@ impl ValueKind { pub(crate) fn normalize(&self) { match self { - ValueKind::Var(..) - | ValueKind::Const(_) - | ValueKind::BoolLit(_) - | ValueKind::NaturalLit(_) - | ValueKind::IntegerLit(_) - | ValueKind::DoubleLit(_) => {} + ValueKind::Var(..) | ValueKind::Const(_) | ValueKind::Lit(_) => {} ValueKind::EmptyOptionalLit(tth) | ValueKind::EmptyListLit(tth) => { tth.normalize(); diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index f9ff3d3..c52cfda 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -9,7 +9,7 @@ use crate::semantics::{ TyExpr, TyExprKind, Type, Value, ValueKind, }; use crate::syntax::{ - BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, Span, + BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, LitKind, Span, }; fn type_of_recordtype<'a>( @@ -115,10 +115,16 @@ fn type_one_layer( let t_tyexpr = typecheck(&t_hir)?; t_tyexpr.eval(env) } - ExprKind::BoolLit(_) => Value::from_builtin(Builtin::Bool), - ExprKind::NaturalLit(_) => Value::from_builtin(Builtin::Natural), - ExprKind::IntegerLit(_) => Value::from_builtin(Builtin::Integer), - ExprKind::DoubleLit(_) => Value::from_builtin(Builtin::Double), + ExprKind::Lit(LitKind::Bool(_)) => Value::from_builtin(Builtin::Bool), + ExprKind::Lit(LitKind::Natural(_)) => { + Value::from_builtin(Builtin::Natural) + } + ExprKind::Lit(LitKind::Integer(_)) => { + Value::from_builtin(Builtin::Integer) + } + ExprKind::Lit(LitKind::Double(_)) => { + Value::from_builtin(Builtin::Double) + } ExprKind::TextLit(interpolated) => { let text_type = Value::from_builtin(Builtin::Text); for contents in interpolated.iter() { -- cgit v1.2.3 From 7b649b8647c60f1c02050805520f307edff0a94f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 13 Feb 2020 19:48:11 +0000 Subject: Only store type at root node in tyexpr --- dhall/src/semantics/tck/tyexpr.rs | 43 +++++++++++++++--------------------- dhall/src/semantics/tck/typecheck.rs | 12 ++++++---- 2 files changed, 26 insertions(+), 29 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index d46ab87..b49ea3e 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -1,39 +1,30 @@ use crate::error::{TypeError, TypeMessage}; -use crate::semantics::{AlphaVar, Hir, HirKind, NzEnv, Value}; -use crate::syntax::{ExprKind, Span}; +use crate::semantics::{Hir, HirKind, NzEnv, Value,TyEnv}; +use crate::syntax::Span; use crate::{NormalizedExpr, ToExprOptions}; pub(crate) type Type = Value; -#[derive(Debug, Clone)] -pub(crate) enum TyExprKind { - Var(AlphaVar), - // Forbidden ExprKind variants: Var, Import, Embed - Expr(ExprKind), -} - -// An expression with inferred types at every node and resolved variables. +// A hir expression plus its inferred type. #[derive(Clone)] pub(crate) struct TyExpr { - kind: Box, + hir: Hir, ty: Option, - span: Span, } impl TyExpr { - pub fn new(kind: TyExprKind, ty: Option, span: Span) -> Self { + pub fn new(kind: HirKind, ty: Option, span: Span) -> Self { TyExpr { - kind: Box::new(kind), + hir: Hir::new(kind, span), ty, - span, } } - pub fn kind(&self) -> &TyExprKind { - &*self.kind + pub fn kind(&self) -> &HirKind { + self.hir.kind() } pub fn span(&self) -> Span { - self.span.clone() + self.as_hir().span() } pub fn get_type(&self) -> Result { match &self.ty { @@ -41,22 +32,24 @@ impl TyExpr { None => Err(TypeError::new(TypeMessage::Sort)), } } + pub fn get_type_tyexpr(&self, env: &TyEnv) -> Result { + Ok(self.get_type()?.to_tyexpr_tyenv(env)) + } pub fn to_hir(&self) -> Hir { - let kind = match self.kind() { - TyExprKind::Var(v) => HirKind::Var(v.clone()), - TyExprKind::Expr(e) => HirKind::Expr(e.map_ref(|tye| tye.to_hir())), - }; - Hir::new(kind, self.span()) + self.as_hir().clone() + } + pub fn as_hir(&self) -> &Hir { + &self.hir } /// Converts a value back to the corresponding AST expression. pub fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { - self.to_hir().to_expr(opts) + self.as_hir().to_expr(opts) } /// Eval the TyExpr. It will actually get evaluated only as needed on demand. pub fn eval(&self, env: impl Into) -> Value { - Value::new_thunk(env.into(), self.to_hir()) + self.as_hir().eval(&env.into()) } /// Eval a closed TyExpr (i.e. without free variables). It will actually get evaluated only as /// needed on demand. diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index c52cfda..c854552 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -6,7 +6,7 @@ use crate::error::{ErrorBuilder, TypeError, TypeMessage}; use crate::semantics::merge_maps; use crate::semantics::{ type_of_builtin, Binder, BuiltinClosure, Closure, Hir, HirKind, TyEnv, - TyExpr, TyExprKind, Type, Value, ValueKind, + TyExpr, Type, Value, ValueKind, }; use crate::syntax::{ BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, LitKind, Span, @@ -758,18 +758,22 @@ fn type_one_layer( } }; - Ok(TyExpr::new(TyExprKind::Expr(ekind), Some(ty), span)) + Ok(TyExpr::new( + HirKind::Expr(ekind.map_ref(|tye| tye.to_hir())), + Some(ty), + span, + )) } /// `type_with` typechecks an expressio in the provided environment. pub(crate) fn type_with(env: &TyEnv, hir: &Hir) -> Result { let (tyekind, ty) = match hir.kind() { - HirKind::Var(var) => (TyExprKind::Var(*var), Some(env.lookup(var))), + HirKind::Var(var) => (HirKind::Var(*var), Some(env.lookup(var))), HirKind::Expr(ExprKind::Var(_)) => { unreachable!("Hir should contain no unresolved variables") } HirKind::Expr(ExprKind::Const(Const::Sort)) => { - (TyExprKind::Expr(ExprKind::Const(Const::Sort)), None) + (HirKind::Expr(ExprKind::Const(Const::Sort)), None) } HirKind::Expr(ekind) => { let ekind = match ekind { -- cgit v1.2.3 From f29a40fb55b898b3a3cc51f198e8522eaecf0777 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 13 Feb 2020 20:17:41 +0000 Subject: Simplify conversions to/from TyExpr --- dhall/src/semantics/hir.rs | 8 +- dhall/src/semantics/nze/value.rs | 20 +---- dhall/src/semantics/tck/tyexpr.rs | 11 ++- dhall/src/semantics/tck/typecheck.rs | 157 ++++++++++++++++------------------- 4 files changed, 88 insertions(+), 108 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index 288031c..f91aa73 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -1,5 +1,6 @@ #![allow(dead_code)] -use crate::semantics::{NameEnv, NzEnv, TyEnv, Value}; +use crate::error::TypeError; +use crate::semantics::{type_with, NameEnv, NzEnv, TyEnv, TyExpr, Value}; use crate::syntax::{Expr, ExprKind, Span, V}; use crate::{NormalizedExpr, ToExprOptions}; @@ -69,6 +70,11 @@ impl Hir { hir_to_expr(self, opts, &mut env) } + /// Typecheck the Hir. + pub fn typecheck(&self, env: &TyEnv) -> Result { + type_with(env, self) + } + /// Eval the Hir. It will actually get evaluated only as needed on demand. pub fn eval(&self, env: &NzEnv) -> Value { Value::new_thunk(env.clone(), self.clone()) diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index 2ae6852..0603fb5 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -1,12 +1,10 @@ use std::collections::HashMap; use std::rc::Rc; -use crate::error::TypeError; use crate::semantics::nze::lazy; use crate::semantics::{ - apply_any, normalize_hir_whnf, normalize_one_layer, squash_textlit, - type_with, Binder, BuiltinClosure, Hir, HirKind, NzEnv, NzVar, TyEnv, - TyExpr, VarEnv, + apply_any, normalize_hir_whnf, normalize_one_layer, squash_textlit, Binder, + BuiltinClosure, Hir, HirKind, NzEnv, NzVar, TyEnv, VarEnv, }; use crate::syntax::{ BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, Label, LitKind, @@ -146,8 +144,7 @@ impl Value { if opts.normalize { self.normalize(); } - - self.to_tyexpr_noenv().to_expr(opts) + self.to_hir_noenv().to_expr(opts) } pub(crate) fn to_expr_tyenv(&self, tyenv: &TyEnv) -> NormalizedExpr { self.to_hir(tyenv.as_varenv()).to_expr_tyenv(tyenv) @@ -161,10 +158,6 @@ impl Value { Value::from_kind(apply_any(self.clone(), v)) } - pub(crate) fn get_type(&self, tyenv: &TyEnv) -> Result { - self.to_tyexpr_tyenv(tyenv).get_type() - } - pub fn to_hir(&self, venv: VarEnv) -> Hir { let map_uniontype = |kts: &HashMap>| { ExprKind::UnionType( @@ -270,13 +263,6 @@ impl Value { pub fn to_hir_noenv(&self) -> Hir { self.to_hir(VarEnv::new()) } - pub fn to_tyexpr_tyenv(&self, tyenv: &TyEnv) -> TyExpr { - let hir = self.to_hir(tyenv.as_varenv()); - type_with(tyenv, &hir).unwrap() - } - pub fn to_tyexpr_noenv(&self) -> TyExpr { - self.to_tyexpr_tyenv(&TyEnv::new()) - } } impl ValueInternal { diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index b49ea3e..dc14cd2 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -1,6 +1,6 @@ use crate::error::{TypeError, TypeMessage}; -use crate::semantics::{Hir, HirKind, NzEnv, Value,TyEnv}; -use crate::syntax::Span; +use crate::semantics::{Hir, HirKind, NzEnv, TyEnv, Value}; +use crate::syntax::{Const, Span}; use crate::{NormalizedExpr, ToExprOptions}; pub(crate) type Type = Value; @@ -33,7 +33,12 @@ impl TyExpr { } } pub fn get_type_tyexpr(&self, env: &TyEnv) -> Result { - Ok(self.get_type()?.to_tyexpr_tyenv(env)) + Ok(self.get_type()?.to_hir(env.as_varenv()).typecheck(env)?) + } + /// Get the kind (the type of the type) of this value + // TODO: avoid recomputing so much + pub fn get_kind(&self, env: &TyEnv) -> Result, TypeError> { + Ok(self.get_type_tyexpr(env)?.get_type()?.as_const()) } pub fn to_hir(&self) -> Hir { diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index c854552..794edcf 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -12,28 +12,6 @@ use crate::syntax::{ BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, LitKind, Span, }; -fn type_of_recordtype<'a>( - span: Span, - tys: impl Iterator>, -) -> Result { - let span_err = |msg: &str| { - mkerr( - ErrorBuilder::new(msg.to_string()) - .span_err(span.clone(), msg.to_string()) - .format(), - ) - }; - // An empty record type has type Type - let mut k = Const::Type; - for t in tys { - match t.get_type()?.as_const() { - Some(c) => k = max(k, c), - None => return span_err("InvalidFieldType"), - } - } - Ok(Value::from_const(k)) -} - fn function_check(a: Const, b: Const) -> Const { if b == Const::Type { Const::Type @@ -42,8 +20,19 @@ fn function_check(a: Const, b: Const) -> Const { } } -pub fn mkerr(x: S) -> Result { - Err(TypeError::new(TypeMessage::Custom(x.to_string()))) +pub fn mkerr(msg: S) -> Result { + Err(TypeError::new(TypeMessage::Custom(msg.to_string()))) +} + +pub fn mk_span_err( + span: &Span, + msg: S, +) -> Result { + mkerr( + ErrorBuilder::new(msg.to_string()) + .span_err(span.clone(), msg.to_string()) + .format(), + ) } /// When all sub-expressions have been typed, check the remaining toplevel @@ -53,13 +42,7 @@ fn type_one_layer( ekind: ExprKind, span: Span, ) -> Result { - let span_err = |msg: &str| { - mkerr( - ErrorBuilder::new(msg.to_string()) - .span_err(span.clone(), msg.to_string()) - .format(), - ) - }; + let span_err = |msg: &str| mk_span_err(&span, msg); let ty = match &ekind { ExprKind::Import(..) => unreachable!( @@ -68,10 +51,9 @@ fn type_one_layer( ExprKind::Var(..) | ExprKind::Const(Const::Sort) => unreachable!(), // Handled in type_with ExprKind::Lam(binder, annot, body) => { - let body_ty = body.get_type()?; - let body_ty = body_ty.to_tyexpr_tyenv( + let body_ty = body.get_type_tyexpr( &env.insert_type(&binder.clone(), annot.eval(env)), - ); + )?; let pi_ekind = ExprKind::Pi(binder.clone(), annot.clone(), body_ty); type_one_layer(env, pi_ekind, Span::Artificial)?.eval(env) } @@ -157,19 +139,19 @@ fn type_one_layer( return span_err("InvalidListElement"); } } - let t = x.get_type()?; - if t.get_type(env)?.as_const() != Some(Const::Type) { + if x.get_kind(env)? != Some(Const::Type) { return span_err("InvalidListType"); } + let t = x.get_type()?; Value::from_builtin(Builtin::List).app(t) } ExprKind::SomeLit(x) => { - let t = x.get_type()?; - if t.get_type(env)?.as_const() != Some(Const::Type) { + if x.get_kind(env)? != Some(Const::Type) { return span_err("InvalidOptionalType"); } + let t = x.get_type()?; Value::from_builtin(Builtin::Optional).app(t) } ExprKind::RecordLit(kvs) => { @@ -183,18 +165,23 @@ fn type_one_layer( } Entry::Vacant(e) => e.insert(v.get_type()?), }; + + // Check that the fields have a valid kind + match v.get_kind(env)? { + Some(_) => {} + None => return span_err("InvalidFieldType"), + } } - type_of_recordtype( - span.clone(), - kts.iter().map(|(_, t)| Cow::Owned(t.to_tyexpr_tyenv(env))), - )?; Value::from_kind(ValueKind::RecordType(kts)) } ExprKind::RecordType(kts) => { use std::collections::hash_map::Entry; let mut seen_fields = HashMap::new(); - for (x, _) in kts { + // An empty record type has type Type + let mut k = Const::Type; + + for (x, t) in kts { // Check for duplicated entries match seen_fields.entry(x.clone()) { Entry::Occupied(_) => { @@ -202,12 +189,15 @@ fn type_one_layer( } Entry::Vacant(e) => e.insert(()), }; + + // Check the type is a Const and compute final type + match t.get_type()?.as_const() { + Some(c) => k = max(k, c), + None => return span_err("InvalidFieldType"), + } } - type_of_recordtype( - span.clone(), - kts.iter().map(|(_, t)| Cow::Borrowed(t)), - )? + Value::from_const(k) } ExprKind::UnionType(kts) => { use std::collections::hash_map::Entry; @@ -337,9 +327,7 @@ fn type_one_layer( if *x.get_type()?.kind() != ValueKind::from_builtin(Builtin::Bool) { return span_err("InvalidPredicate"); } - let y_ty = y.get_type()?; - let y_ty = y_ty.to_tyexpr_tyenv(env); - if y_ty.get_type()?.as_const() != Some(Const::Type) { + if y.get_kind(env)? != Some(Const::Type) { return span_err("IfBranchMustBeTerm"); } if y.get_type()? != z.get_type()? { @@ -369,45 +357,44 @@ fn type_one_layer( Ok(r_t.clone()) })?; - // Construct the final record type - type_of_recordtype( - span.clone(), - kts.iter().map(|(_, t)| Cow::Owned(t.to_tyexpr_tyenv(env))), - )?; Value::from_kind(ValueKind::RecordType(kts)) } ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y) => { let ekind = ExprKind::BinOp( BinOp::RecursiveRecordTypeMerge, - x.get_type()?.to_tyexpr_tyenv(env), - y.get_type()?.to_tyexpr_tyenv(env), + x.get_type_tyexpr(env)?, + y.get_type_tyexpr(env)?, ); - type_one_layer(env, ekind, Span::Artificial)?.eval(env) + type_one_layer(env, ekind, span.clone())?.eval(env) } ExprKind::BinOp(BinOp::RecursiveRecordTypeMerge, x, y) => { - let x_val = x.eval(env); - let y_val = y.eval(env); - let kts_x = match x_val.kind() { - ValueKind::RecordType(kts) => kts, - _ => return span_err("RecordTypeMergeRequiresRecordType"), - }; - let kts_y = match y_val.kind() { - ValueKind::RecordType(kts) => kts, - _ => return span_err("RecordTypeMergeRequiresRecordType"), - }; - for (k, tx) in kts_x { - if let Some(ty) = kts_y.get(k) { - type_one_layer( - env, - ExprKind::BinOp( - BinOp::RecursiveRecordTypeMerge, - tx.to_tyexpr_tyenv(env), - ty.to_tyexpr_tyenv(env), - ), - Span::Artificial, - )?; + fn check_rectymerge( + span: &Span, + env: &TyEnv, + x: Type, + y: Type, + ) -> Result<(), TypeError> { + let kts_x = match x.kind() { + ValueKind::RecordType(kts) => kts, + _ => return mk_span_err(span, "RecordTypeMergeRequiresRecordType"), + }; + let kts_y = match y.kind() { + ValueKind::RecordType(kts) => kts, + _ => return mk_span_err(span, "RecordTypeMergeRequiresRecordType"), + }; + for (k, tx) in kts_x { + if let Some(ty) = kts_y.get(k) { + check_rectymerge( + span, + env, + tx.clone(), + ty.clone(), + )?; + } } + Ok(()) } + check_rectymerge(&span, env, x.eval(env), y.eval(env))?; // A RecordType's type is always a const let xk = x.get_type()?.as_const().unwrap(); @@ -434,9 +421,7 @@ fn type_one_layer( if l.get_type()? != r.get_type()? { return span_err("EquivalenceTypeMismatch"); } - if l.get_type()?.to_tyexpr_tyenv(env).get_type()?.as_const() - != Some(Const::Type) - { + if l.get_kind(env)? != Some(Const::Type) { return span_err("EquivalenceArgumentsMustBeTerms"); } @@ -605,6 +590,9 @@ fn type_one_layer( } } ExprKind::ToMap(record, annot) => { + if record.get_kind(env)? != Some(Const::Type) { + return span_err("`toMap` only accepts records of type `Type`"); + } let record_t = record.get_type()?; let kts = match record_t.kind() { ValueKind::RecordType(kts) => kts, @@ -652,11 +640,6 @@ fn type_one_layer( annot_val } else { let entry_type = kts.iter().next().unwrap().1.clone(); - if entry_type.get_type(env)?.as_const() != Some(Const::Type) { - return span_err( - "`toMap` only accepts records of type `Type`", - ); - } for (_, t) in kts.iter() { if *t != entry_type { return span_err( -- cgit v1.2.3 From e25b67906ce68e8726e8139c1d1855f3ab2518ce Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 13 Feb 2020 20:45:42 +0000 Subject: Rework annotation and Sort handling --- dhall/src/semantics/hir.rs | 2 +- dhall/src/semantics/tck/typecheck.rs | 143 ++++++++++++++++++----------------- 2 files changed, 76 insertions(+), 69 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index f91aa73..e4e2a5f 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -72,7 +72,7 @@ impl Hir { /// Typecheck the Hir. pub fn typecheck(&self, env: &TyEnv) -> Result { - type_with(env, self) + type_with(env, self, None) } /// Eval the Hir. It will actually get evaluated only as needed on demand. diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 794edcf..a4ab31f 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -24,13 +24,10 @@ pub fn mkerr(msg: S) -> Result { Err(TypeError::new(TypeMessage::Custom(msg.to_string()))) } -pub fn mk_span_err( - span: &Span, - msg: S, -) -> Result { +pub fn mk_span_err(span: Span, msg: S) -> Result { mkerr( ErrorBuilder::new(msg.to_string()) - .span_err(span.clone(), msg.to_string()) + .span_err(span, msg.to_string()) .format(), ) } @@ -40,22 +37,25 @@ pub fn mk_span_err( fn type_one_layer( env: &TyEnv, ekind: ExprKind, + annot: Option, span: Span, ) -> Result { - let span_err = |msg: &str| mk_span_err(&span, msg); + let span_err = |msg: &str| mk_span_err(span.clone(), msg); let ty = match &ekind { ExprKind::Import(..) => unreachable!( "There should remain no imports in a resolved expression" ), - ExprKind::Var(..) | ExprKind::Const(Const::Sort) => unreachable!(), // Handled in type_with + ExprKind::Var(..) + | ExprKind::Const(Const::Sort) + | ExprKind::Annot(..) => unreachable!(), // Handled in type_with ExprKind::Lam(binder, annot, body) => { let body_ty = body.get_type_tyexpr( &env.insert_type(&binder.clone(), annot.eval(env)), )?; let pi_ekind = ExprKind::Pi(binder.clone(), annot.clone(), body_ty); - type_one_layer(env, pi_ekind, Span::Artificial)?.eval(env) + type_one_layer(env, pi_ekind, None, Span::Artificial)?.eval(env) } ExprKind::Pi(_, annot, body) => { let ks = match annot.get_type()?.as_const() { @@ -253,18 +253,6 @@ fn type_one_layer( } // _ => span_err("NotARecord"), } } - ExprKind::Annot(x, t) => { - let t = t.eval(env); - let x_ty = x.get_type()?; - if x_ty != t { - return span_err(&format!( - "annot mismatch: {} != {}", - x_ty.to_expr_tyenv(env), - t.to_expr_tyenv(env) - )); - } - x_ty - } ExprKind::Assert(t) => { let t = t.eval(env); match &*t.kind() { @@ -365,7 +353,7 @@ fn type_one_layer( x.get_type_tyexpr(env)?, y.get_type_tyexpr(env)?, ); - type_one_layer(env, ekind, span.clone())?.eval(env) + type_one_layer(env, ekind, None, span.clone())?.eval(env) } ExprKind::BinOp(BinOp::RecursiveRecordTypeMerge, x, y) => { fn check_rectymerge( @@ -376,20 +364,25 @@ fn type_one_layer( ) -> Result<(), TypeError> { let kts_x = match x.kind() { ValueKind::RecordType(kts) => kts, - _ => return mk_span_err(span, "RecordTypeMergeRequiresRecordType"), + _ => { + return mk_span_err( + span.clone(), + "RecordTypeMergeRequiresRecordType", + ) + } }; let kts_y = match y.kind() { ValueKind::RecordType(kts) => kts, - _ => return mk_span_err(span, "RecordTypeMergeRequiresRecordType"), + _ => { + return mk_span_err( + span.clone(), + "RecordTypeMergeRequiresRecordType", + ) + } }; for (k, tx) in kts_x { if let Some(ty) = kts_y.get(k) { - check_rectymerge( - span, - env, - tx.clone(), - ty.clone(), - )?; + check_rectymerge(span, env, tx.clone(), ty.clone())?; } } Ok(()) @@ -717,30 +710,38 @@ fn type_one_layer( let ty_field_default = type_one_layer( env, ExprKind::Field(ty.clone(), "default".into()), + None, span.clone(), )?; let ty_field_type = type_one_layer( env, ExprKind::Field(ty.clone(), "Type".into()), + None, span.clone(), )?; - let merge = type_one_layer( + return type_one_layer( env, ExprKind::BinOp( BinOp::RightBiasedRecordMerge, ty_field_default, compl.clone(), ), - span.clone(), - )?; - return type_one_layer( - env, - ExprKind::Annot(merge, ty_field_type), + Some(ty_field_type.eval(env)), span.clone(), ); } }; + if let Some(annot) = annot { + if ty != annot { + return span_err(&format!( + "annot mismatch: {} != {}", + ty.to_expr_tyenv(env), + annot.to_expr_tyenv(env) + )); + } + } + Ok(TyExpr::new( HirKind::Expr(ekind.map_ref(|tye| tye.to_hir())), Some(ty), @@ -748,72 +749,78 @@ fn type_one_layer( )) } -/// `type_with` typechecks an expressio in the provided environment. -pub(crate) fn type_with(env: &TyEnv, hir: &Hir) -> Result { - let (tyekind, ty) = match hir.kind() { - HirKind::Var(var) => (HirKind::Var(*var), Some(env.lookup(var))), +/// `type_with` typechecks an expression in the provided environment. Optionally pass an annotation +/// to compare with. +pub(crate) fn type_with( + env: &TyEnv, + hir: &Hir, + annot: Option, +) -> Result { + match hir.kind() { + HirKind::Var(var) => Ok(TyExpr::new( + HirKind::Var(*var), + Some(env.lookup(var)), + hir.span(), + )), HirKind::Expr(ExprKind::Var(_)) => { unreachable!("Hir should contain no unresolved variables") } HirKind::Expr(ExprKind::Const(Const::Sort)) => { - (HirKind::Expr(ExprKind::Const(Const::Sort)), None) + mk_span_err(hir.span(), "Sort does not have a type") + } + HirKind::Expr(ExprKind::Annot(x, t)) => { + let t = match t.kind() { + HirKind::Expr(ExprKind::Const(Const::Sort)) => { + Value::from_const(Const::Sort) + } + _ => type_with(env, t, None)?.eval(env), + }; + type_with(env, x, Some(t)) } HirKind::Expr(ekind) => { let ekind = match ekind { ExprKind::Lam(binder, annot, body) => { - let annot = type_with(env, annot)?; + let annot = type_with(env, annot, None)?; let annot_nf = annot.eval(env); let body_env = env.insert_type(binder, annot_nf); - let body = type_with(&body_env, body)?; + let body = type_with(&body_env, body, None)?; ExprKind::Lam(binder.clone(), annot, body) } ExprKind::Pi(binder, annot, body) => { - let annot = type_with(env, annot)?; + let annot = type_with(env, annot, None)?; let annot_nf = annot.eval(env); let body_env = env.insert_type(binder, annot_nf); - let body = type_with(&body_env, body)?; + let body = type_with(&body_env, body, None)?; ExprKind::Pi(binder.clone(), annot, body) } ExprKind::Let(binder, annot, val, body) => { - let val = if let Some(t) = annot { - Hir::new( - HirKind::Expr(ExprKind::Annot( - val.clone(), - t.clone(), - )), - t.span(), - ) + let val_annot = if let Some(t) = annot { + Some(type_with(env, t, None)?.eval(env)) } else { - val.clone() + None }; - let val = type_with(env, &val)?; + let val = type_with(env, &val, val_annot)?; let val_ty = val.get_type()?; let val_nf = val.eval(env); let body_env = env.insert_value(&binder, val_nf, val_ty); - let body = type_with(&body_env, body)?; + let body = type_with(&body_env, body, None)?; ExprKind::Let(binder.clone(), None, val, body) } - _ => ekind.traverse_ref(|e| type_with(env, e))?, + _ => ekind.traverse_ref(|e| type_with(env, e, None))?, }; - return type_one_layer(env, ekind, hir.span()); + type_one_layer(env, ekind, annot, hir.span()) } - }; - - Ok(TyExpr::new(tyekind, ty, hir.span())) + } } /// Typecheck an expression and return the expression annotated with types if type-checking /// succeeded, or an error if type-checking failed. -pub(crate) fn typecheck(e: &Hir) -> Result { - let res = type_with(&TyEnv::new(), e)?; - // Ensure that the inferred type exists (i.e. this is not Sort) - res.get_type()?; - Ok(res) +pub(crate) fn typecheck(hir: &Hir) -> Result { + type_with(&TyEnv::new(), hir, None) } /// Like `typecheck`, but additionally checks that the expression's type matches the provided type. pub(crate) fn typecheck_with(hir: &Hir, ty: Hir) -> Result { - let hir = - Hir::new(HirKind::Expr(ExprKind::Annot(hir.clone(), ty)), hir.span()); - typecheck(&hir) + let ty = typecheck(&ty)?.eval(&TyEnv::new()); + type_with(&TyEnv::new(), hir, Some(ty)) } -- cgit v1.2.3 From 350d1cf7d9c114b1334b2743071b0b99ea64c1ec Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 13 Feb 2020 20:56:38 +0000 Subject: TyExpr always carries a type --- dhall/src/semantics/tck/tyexpr.rs | 41 ++++--------- dhall/src/semantics/tck/typecheck.rs | 112 +++++++++++++++++------------------ 2 files changed, 67 insertions(+), 86 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index dc14cd2..ac15ac5 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -1,4 +1,3 @@ -use crate::error::{TypeError, TypeMessage}; use crate::semantics::{Hir, HirKind, NzEnv, TyEnv, Value}; use crate::syntax::{Const, Span}; use crate::{NormalizedExpr, ToExprOptions}; @@ -6,39 +5,36 @@ use crate::{NormalizedExpr, ToExprOptions}; pub(crate) type Type = Value; // A hir expression plus its inferred type. -#[derive(Clone)] +#[derive(Debug, Clone)] pub(crate) struct TyExpr { hir: Hir, - ty: Option, + ty: Type, } impl TyExpr { - pub fn new(kind: HirKind, ty: Option, span: Span) -> Self { + pub fn new(kind: HirKind, ty: Type, span: Span) -> Self { TyExpr { hir: Hir::new(kind, span), ty, } } - pub fn kind(&self) -> &HirKind { - self.hir.kind() - } pub fn span(&self) -> Span { self.as_hir().span() } - pub fn get_type(&self) -> Result { - match &self.ty { - Some(t) => Ok(t.clone()), - None => Err(TypeError::new(TypeMessage::Sort)), - } + pub fn ty(&self) -> &Type { + &self.ty } - pub fn get_type_tyexpr(&self, env: &TyEnv) -> Result { - Ok(self.get_type()?.to_hir(env.as_varenv()).typecheck(env)?) + pub fn get_type_tyexpr(&self, env: &TyEnv) -> TyExpr { + self.ty() + .to_hir(env.as_varenv()) + .typecheck(env) + .expect("Internal type error") } /// Get the kind (the type of the type) of this value // TODO: avoid recomputing so much - pub fn get_kind(&self, env: &TyEnv) -> Result, TypeError> { - Ok(self.get_type_tyexpr(env)?.get_type()?.as_const()) + pub fn get_kind(&self, env: &TyEnv) -> Option { + self.get_type_tyexpr(env).ty().as_const() } pub fn to_hir(&self) -> Hir { @@ -68,16 +64,3 @@ impl TyExpr { val } } - -impl std::fmt::Debug for TyExpr { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut x = fmt.debug_struct("TyExpr"); - x.field("kind", self.kind()); - if let Some(ty) = self.ty.as_ref() { - x.field("type", &ty); - } else { - x.field("type", &None::<()>); - } - x.finish() - } -} diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index a4ab31f..b3c9353 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -53,24 +53,24 @@ fn type_one_layer( ExprKind::Lam(binder, annot, body) => { let body_ty = body.get_type_tyexpr( &env.insert_type(&binder.clone(), annot.eval(env)), - )?; + ); let pi_ekind = ExprKind::Pi(binder.clone(), annot.clone(), body_ty); type_one_layer(env, pi_ekind, None, Span::Artificial)?.eval(env) } ExprKind::Pi(_, annot, body) => { - let ks = match annot.get_type()?.as_const() { + let ks = match annot.ty().as_const() { Some(k) => k, _ => { return mkerr( ErrorBuilder::new(format!( "Invalid input type: `{}`", - annot.get_type()?.to_expr_tyenv(env), + annot.ty().to_expr_tyenv(env), )) .span_err( annot.span(), format!( "this has type: `{}`", - annot.get_type()?.to_expr_tyenv(env) + annot.ty().to_expr_tyenv(env) ), ) .help(format!( @@ -81,14 +81,14 @@ fn type_one_layer( ); } }; - let kt = match body.get_type()?.as_const() { + let kt = match body.ty().as_const() { Some(k) => k, _ => return span_err("Invalid output type"), }; Value::from_const(function_check(ks, kt)) } - ExprKind::Let(_, _, _, body) => body.get_type()?, + ExprKind::Let(_, _, _, body) => body.ty().clone(), ExprKind::Const(Const::Type) => Value::from_const(Const::Kind), ExprKind::Const(Const::Kind) => Value::from_const(Const::Sort), @@ -112,7 +112,7 @@ fn type_one_layer( for contents in interpolated.iter() { use InterpolatedTextContents::Expr; if let Expr(x) = contents { - if x.get_type()? != text_type { + if *x.ty() != text_type { return span_err("InvalidTextInterpolation"); } } @@ -121,7 +121,7 @@ fn type_one_layer( } ExprKind::EmptyListLit(t) => { let t = t.eval(env); - match &*t.kind() { + match t.kind() { ValueKind::AppliedBuiltin(BuiltinClosure { b: Builtin::List, args, @@ -135,23 +135,23 @@ fn type_one_layer( let mut iter = xs.iter(); let x = iter.next().unwrap(); for y in iter { - if x.get_type()? != y.get_type()? { + if x.ty() != y.ty() { return span_err("InvalidListElement"); } } - if x.get_kind(env)? != Some(Const::Type) { + if x.get_kind(env) != Some(Const::Type) { return span_err("InvalidListType"); } - let t = x.get_type()?; + let t = x.ty().clone(); Value::from_builtin(Builtin::List).app(t) } ExprKind::SomeLit(x) => { - if x.get_kind(env)? != Some(Const::Type) { + if x.get_kind(env) != Some(Const::Type) { return span_err("InvalidOptionalType"); } - let t = x.get_type()?; + let t = x.ty().clone(); Value::from_builtin(Builtin::Optional).app(t) } ExprKind::RecordLit(kvs) => { @@ -163,11 +163,11 @@ fn type_one_layer( Entry::Occupied(_) => { return span_err("RecordTypeDuplicateField") } - Entry::Vacant(e) => e.insert(v.get_type()?), + Entry::Vacant(e) => e.insert(v.ty().clone()), }; // Check that the fields have a valid kind - match v.get_kind(env)? { + match v.get_kind(env) { Some(_) => {} None => return span_err("InvalidFieldType"), } @@ -191,7 +191,7 @@ fn type_one_layer( }; // Check the type is a Const and compute final type - match t.get_type()?.as_const() { + match t.ty().as_const() { Some(c) => k = max(k, c), None => return span_err("InvalidFieldType"), } @@ -206,7 +206,7 @@ fn type_one_layer( let mut k = None; for (x, t) in kts { if let Some(t) = t { - match (k, t.get_type()?.as_const()) { + match (k, t.ty().as_const()) { (None, Some(k2)) => k = Some(k2), (Some(k1), Some(k2)) if k1 == k2 => {} _ => return span_err("InvalidFieldType"), @@ -227,12 +227,12 @@ fn type_one_layer( Value::from_const(k) } ExprKind::Field(scrut, x) => { - match &*scrut.get_type()?.kind() { + match scrut.ty().kind() { ValueKind::RecordType(kts) => match kts.get(&x) { Some(tth) => tth.clone(), None => return span_err("MissingRecordField"), }, - // TODO: branch here only when scrut.get_type() is a Const + // TODO: branch here only when scrut.ty() is a Const _ => { let scrut_nf = scrut.eval(env); match scrut_nf.kind() { @@ -255,7 +255,7 @@ fn type_one_layer( } ExprKind::Assert(t) => { let t = t.eval(env); - match &*t.kind() { + match t.kind() { ValueKind::Equivalence(x, y) if x == y => {} ValueKind::Equivalence(..) => { return span_err("AssertMismatch") @@ -265,9 +265,9 @@ fn type_one_layer( t } ExprKind::App(f, arg) => { - match f.get_type()?.kind() { + match f.ty().kind() { ValueKind::PiClosure { annot, closure, .. } => { - if arg.get_type()? != *annot { + if arg.ty() != annot { return mkerr( ErrorBuilder::new(format!( "wrong type of function argument" @@ -283,13 +283,13 @@ fn type_one_layer( arg.span(), format!( "but this has type: {}", - arg.get_type()?.to_expr_tyenv(env), + arg.ty().to_expr_tyenv(env), ), ) .note(format!( "expected type `{}`\n found type `{}`", annot.to_expr_tyenv(env), - arg.get_type()?.to_expr_tyenv(env), + arg.ty().to_expr_tyenv(env), )) .format(), ); @@ -301,7 +301,7 @@ fn type_one_layer( _ => return mkerr( ErrorBuilder::new(format!( "expected function, found `{}`", - f.get_type()?.to_expr_tyenv(env) + f.ty().to_expr_tyenv(env) )) .span_err( f.span(), @@ -312,21 +312,21 @@ fn type_one_layer( } } ExprKind::BoolIf(x, y, z) => { - if *x.get_type()?.kind() != ValueKind::from_builtin(Builtin::Bool) { + if *x.ty().kind() != ValueKind::from_builtin(Builtin::Bool) { return span_err("InvalidPredicate"); } - if y.get_kind(env)? != Some(Const::Type) { + if y.get_kind(env) != Some(Const::Type) { return span_err("IfBranchMustBeTerm"); } - if y.get_type()? != z.get_type()? { + if y.ty() != z.ty() { return span_err("IfBranchMismatch"); } - y.get_type()? + y.ty().clone() } ExprKind::BinOp(BinOp::RightBiasedRecordMerge, x, y) => { - let x_type = x.get_type()?; - let y_type = y.get_type()?; + let x_type = x.ty(); + let y_type = y.ty(); // Extract the LHS record type let kts_x = match x_type.kind() { @@ -350,8 +350,8 @@ fn type_one_layer( ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y) => { let ekind = ExprKind::BinOp( BinOp::RecursiveRecordTypeMerge, - x.get_type_tyexpr(env)?, - y.get_type_tyexpr(env)?, + x.get_type_tyexpr(env), + y.get_type_tyexpr(env), ); type_one_layer(env, ekind, None, span.clone())?.eval(env) } @@ -390,13 +390,12 @@ fn type_one_layer( check_rectymerge(&span, env, x.eval(env), y.eval(env))?; // A RecordType's type is always a const - let xk = x.get_type()?.as_const().unwrap(); - let yk = y.get_type()?.as_const().unwrap(); + let xk = x.ty().as_const().unwrap(); + let yk = y.ty().as_const().unwrap(); Value::from_const(max(xk, yk)) } ExprKind::BinOp(BinOp::ListAppend, l, r) => { - let l_ty = l.get_type()?; - match &*l_ty.kind() { + match l.ty().kind() { ValueKind::AppliedBuiltin(BuiltinClosure { b: Builtin::List, .. @@ -404,17 +403,17 @@ fn type_one_layer( _ => return span_err("BinOpTypeMismatch"), } - if l_ty != r.get_type()? { + if l.ty() != r.ty() { return span_err("BinOpTypeMismatch"); } - l_ty + l.ty().clone() } ExprKind::BinOp(BinOp::Equivalence, l, r) => { - if l.get_type()? != r.get_type()? { + if l.ty() != r.ty() { return span_err("EquivalenceTypeMismatch"); } - if l.get_kind(env)? != Some(Const::Type) { + if l.get_kind(env) != Some(Const::Type) { return span_err("EquivalenceArgumentsMustBeTerms"); } @@ -436,24 +435,24 @@ fn type_one_layer( BinOp::ImportAlt => unreachable!("ImportAlt leftover in tck"), }); - if l.get_type()? != t { + if *l.ty() != t { return span_err("BinOpTypeMismatch"); } - if r.get_type()? != t { + if *r.ty() != t { return span_err("BinOpTypeMismatch"); } t } ExprKind::Merge(record, union, type_annot) => { - let record_type = record.get_type()?; + let record_type = record.ty(); let handlers = match record_type.kind() { ValueKind::RecordType(kts) => kts, _ => return span_err("Merge1ArgMustBeRecord"), }; - let union_type = union.get_type()?; + let union_type = union.ty(); let variants = match union_type.kind() { ValueKind::UnionType(kts) => Cow::Borrowed(kts), ValueKind::AppliedBuiltin(BuiltinClosure { @@ -583,10 +582,10 @@ fn type_one_layer( } } ExprKind::ToMap(record, annot) => { - if record.get_kind(env)? != Some(Const::Type) { + if record.get_kind(env) != Some(Const::Type) { return span_err("`toMap` only accepts records of type `Type`"); } - let record_t = record.get_type()?; + let record_t = record.ty(); let kts = match record_t.kind() { ValueKind::RecordType(kts) => kts, _ => { @@ -656,7 +655,7 @@ fn type_one_layer( } } ExprKind::Projection(record, labels) => { - let record_type = record.get_type()?; + let record_type = record.ty(); let kts = match record_type.kind() { ValueKind::RecordType(kts) => kts, _ => return span_err("ProjectionMustBeRecord"), @@ -681,7 +680,7 @@ fn type_one_layer( Value::from_kind(ValueKind::RecordType(new_kts)) } ExprKind::ProjectionByExpr(record, selection) => { - let record_type = record.get_type()?; + let record_type = record.ty(); let rec_kts = match record_type.kind() { ValueKind::RecordType(kts) => kts, _ => return span_err("ProjectionMustBeRecord"), @@ -742,9 +741,10 @@ fn type_one_layer( } } + // TODO: avoid retraversing Ok(TyExpr::new( HirKind::Expr(ekind.map_ref(|tye| tye.to_hir())), - Some(ty), + ty, span, )) } @@ -757,11 +757,9 @@ pub(crate) fn type_with( annot: Option, ) -> Result { match hir.kind() { - HirKind::Var(var) => Ok(TyExpr::new( - HirKind::Var(*var), - Some(env.lookup(var)), - hir.span(), - )), + HirKind::Var(var) => { + Ok(TyExpr::new(HirKind::Var(*var), env.lookup(var), hir.span())) + } HirKind::Expr(ExprKind::Var(_)) => { unreachable!("Hir should contain no unresolved variables") } @@ -800,9 +798,9 @@ pub(crate) fn type_with( None }; let val = type_with(env, &val, val_annot)?; - let val_ty = val.get_type()?; let val_nf = val.eval(env); - let body_env = env.insert_value(&binder, val_nf, val_ty); + let body_env = + env.insert_value(&binder, val_nf, val.ty().clone()); let body = type_with(&body_env, body, None)?; ExprKind::Let(binder.clone(), None, val, body) } -- cgit v1.2.3 From 51cf6a28fa56031dbeae0ff378f0ef84eff7fd3e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 14 Feb 2020 18:55:27 +0000 Subject: Oops --- dhall/src/semantics/tck/tyexpr.rs | 12 +++++------- dhall/src/semantics/tck/typecheck.rs | 18 +++++++++--------- 2 files changed, 14 insertions(+), 16 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index ac15ac5..c7b8009 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -1,3 +1,4 @@ +use crate::error::TypeError; use crate::semantics::{Hir, HirKind, NzEnv, TyEnv, Value}; use crate::syntax::{Const, Span}; use crate::{NormalizedExpr, ToExprOptions}; @@ -25,16 +26,13 @@ impl TyExpr { pub fn ty(&self) -> &Type { &self.ty } - pub fn get_type_tyexpr(&self, env: &TyEnv) -> TyExpr { - self.ty() - .to_hir(env.as_varenv()) - .typecheck(env) - .expect("Internal type error") + pub fn get_type_tyexpr(&self, env: &TyEnv) -> Result { + Ok(self.ty().to_hir(env.as_varenv()).typecheck(env)?) } /// Get the kind (the type of the type) of this value // TODO: avoid recomputing so much - pub fn get_kind(&self, env: &TyEnv) -> Option { - self.get_type_tyexpr(env).ty().as_const() + pub fn get_kind(&self, env: &TyEnv) -> Result, TypeError> { + Ok(self.get_type_tyexpr(env)?.ty().as_const()) } pub fn to_hir(&self) -> Hir { diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index b3c9353..377b97e 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -53,7 +53,7 @@ fn type_one_layer( ExprKind::Lam(binder, annot, body) => { let body_ty = body.get_type_tyexpr( &env.insert_type(&binder.clone(), annot.eval(env)), - ); + )?; let pi_ekind = ExprKind::Pi(binder.clone(), annot.clone(), body_ty); type_one_layer(env, pi_ekind, None, Span::Artificial)?.eval(env) } @@ -139,7 +139,7 @@ fn type_one_layer( return span_err("InvalidListElement"); } } - if x.get_kind(env) != Some(Const::Type) { + if x.get_kind(env)? != Some(Const::Type) { return span_err("InvalidListType"); } @@ -147,7 +147,7 @@ fn type_one_layer( Value::from_builtin(Builtin::List).app(t) } ExprKind::SomeLit(x) => { - if x.get_kind(env) != Some(Const::Type) { + if x.get_kind(env)? != Some(Const::Type) { return span_err("InvalidOptionalType"); } @@ -167,7 +167,7 @@ fn type_one_layer( }; // Check that the fields have a valid kind - match v.get_kind(env) { + match v.get_kind(env)? { Some(_) => {} None => return span_err("InvalidFieldType"), } @@ -315,7 +315,7 @@ fn type_one_layer( if *x.ty().kind() != ValueKind::from_builtin(Builtin::Bool) { return span_err("InvalidPredicate"); } - if y.get_kind(env) != Some(Const::Type) { + if y.get_kind(env)? != Some(Const::Type) { return span_err("IfBranchMustBeTerm"); } if y.ty() != z.ty() { @@ -350,8 +350,8 @@ fn type_one_layer( ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y) => { let ekind = ExprKind::BinOp( BinOp::RecursiveRecordTypeMerge, - x.get_type_tyexpr(env), - y.get_type_tyexpr(env), + x.get_type_tyexpr(env)?, + y.get_type_tyexpr(env)?, ); type_one_layer(env, ekind, None, span.clone())?.eval(env) } @@ -413,7 +413,7 @@ fn type_one_layer( if l.ty() != r.ty() { return span_err("EquivalenceTypeMismatch"); } - if l.get_kind(env) != Some(Const::Type) { + if l.get_kind(env)? != Some(Const::Type) { return span_err("EquivalenceArgumentsMustBeTerms"); } @@ -582,7 +582,7 @@ fn type_one_layer( } } ExprKind::ToMap(record, annot) => { - if record.get_kind(env) != Some(Const::Type) { + if record.get_kind(env)? != Some(Const::Type) { return span_err("`toMap` only accepts records of type `Type`"); } let record_t = record.ty(); -- cgit v1.2.3 From d65d639ff93691adbf0a208edb99736003bc64bd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 15 Feb 2020 19:05:26 +0000 Subject: Factor some tck code to avoid needing get_type_tyexpr --- dhall/src/semantics/hir.rs | 4 +- dhall/src/semantics/nze/normalize.rs | 2 +- dhall/src/semantics/nze/value.rs | 4 +- dhall/src/semantics/tck/tyexpr.rs | 12 ++-- dhall/src/semantics/tck/typecheck.rs | 118 ++++++++++++++++++++++------------- 5 files changed, 88 insertions(+), 52 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index e4e2a5f..42f151e 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -76,8 +76,8 @@ impl Hir { } /// Eval the Hir. It will actually get evaluated only as needed on demand. - pub fn eval(&self, env: &NzEnv) -> Value { - Value::new_thunk(env.clone(), self.clone()) + pub fn eval(&self, env: impl Into) -> Value { + Value::new_thunk(env.into(), self.clone()) } /// Eval a closed Hir (i.e. without free variables). It will actually get evaluated only as /// needed on demand. diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index 4111190..c8dd5ae 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -475,7 +475,7 @@ pub(crate) fn normalize_hir_whnf(env: &NzEnv, hir: &Hir) -> ValueKind { } HirKind::Expr(ExprKind::Let(_, None, val, body)) => { let val = val.eval(env); - body.eval(&env.insert_value(val, ())).kind().clone() + body.eval(env.insert_value(val, ())).kind().clone() } HirKind::Expr(e) => { let e = e.map_ref(|hir| hir.eval(env)); diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index 0603fb5..3a5b5b5 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -87,7 +87,7 @@ pub(crate) enum ValueKind { UnionLit(Label, Value, HashMap>), TextLit(TextLit), Equivalence(Value, Value), - /// Invariant: evaluation must not be able to progress with `normalize_one_layer`? + /// Invariant: evaluation must not be able to progress with `normalize_one_layer`. PartialExpr(ExprKind), } @@ -387,7 +387,7 @@ impl Closure { pub fn apply(&self, val: Value) -> Value { match self { Closure::Closure { env, body, .. } => { - body.eval(&env.insert_value(val, ())) + body.eval(env.insert_value(val, ())) } Closure::ConstantClosure { body, .. } => body.clone(), } diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index c7b8009..dfb4397 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -26,13 +26,15 @@ impl TyExpr { pub fn ty(&self) -> &Type { &self.ty } - pub fn get_type_tyexpr(&self, env: &TyEnv) -> Result { - Ok(self.ty().to_hir(env.as_varenv()).typecheck(env)?) - } /// Get the kind (the type of the type) of this value // TODO: avoid recomputing so much pub fn get_kind(&self, env: &TyEnv) -> Result, TypeError> { - Ok(self.get_type_tyexpr(env)?.ty().as_const()) + Ok(self + .ty() + .to_hir(env.as_varenv()) + .typecheck(env)? + .ty() + .as_const()) } pub fn to_hir(&self) -> Hir { @@ -48,7 +50,7 @@ impl TyExpr { /// Eval the TyExpr. It will actually get evaluated only as needed on demand. pub fn eval(&self, env: impl Into) -> Value { - self.as_hir().eval(&env.into()) + self.as_hir().eval(env.into()) } /// Eval a closed TyExpr (i.e. without free variables). It will actually get evaluated only as /// needed on demand. diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 377b97e..a8a2d95 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -12,6 +12,38 @@ use crate::syntax::{ BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, LitKind, Span, }; +fn check_rectymerge( + span: &Span, + env: &TyEnv, + x: Type, + y: Type, +) -> Result<(), TypeError> { + let kts_x = match x.kind() { + ValueKind::RecordType(kts) => kts, + _ => { + return mk_span_err( + span.clone(), + "RecordTypeMergeRequiresRecordType", + ) + } + }; + let kts_y = match y.kind() { + ValueKind::RecordType(kts) => kts, + _ => { + return mk_span_err( + span.clone(), + "RecordTypeMergeRequiresRecordType", + ) + } + }; + for (k, tx) in kts_x { + if let Some(ty) = kts_y.get(k) { + check_rectymerge(span, env, tx.clone(), ty.clone())?; + } + } + Ok(()) +} + fn function_check(a: Const, b: Const) -> Const { if b == Const::Type { Const::Type @@ -51,11 +83,39 @@ fn type_one_layer( | ExprKind::Annot(..) => unreachable!(), // Handled in type_with ExprKind::Lam(binder, annot, body) => { - let body_ty = body.get_type_tyexpr( - &env.insert_type(&binder.clone(), annot.eval(env)), - )?; - let pi_ekind = ExprKind::Pi(binder.clone(), annot.clone(), body_ty); - type_one_layer(env, pi_ekind, None, Span::Artificial)?.eval(env) + if annot.ty().as_const().is_none() { + return mkerr( + ErrorBuilder::new(format!( + "Invalid input type: `{}`", + annot.ty().to_expr_tyenv(env), + )) + .span_err( + annot.span(), + format!( + "this has type: `{}`", + annot.ty().to_expr_tyenv(env) + ), + ) + .help(format!( + "The input type of a function must have type `Type`, \ + `Kind` or `Sort`", + )) + .format(), + ); + } + let body_env = env.insert_type(&binder, annot.eval(env)); + if body.get_kind(&body_env)?.is_none() { + return span_err("Invalid output type"); + } + Hir::new( + HirKind::Expr(ExprKind::Pi( + binder.clone(), + annot.to_hir(), + body.ty().to_hir(body_env.as_varenv()), + )), + span.clone(), + ) + .eval(env) } ExprKind::Pi(_, annot, body) => { let ks = match annot.ty().as_const() { @@ -348,45 +408,19 @@ fn type_one_layer( Value::from_kind(ValueKind::RecordType(kts)) } ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y) => { - let ekind = ExprKind::BinOp( - BinOp::RecursiveRecordTypeMerge, - x.get_type_tyexpr(env)?, - y.get_type_tyexpr(env)?, - ); - type_one_layer(env, ekind, None, span.clone())?.eval(env) + check_rectymerge(&span, env, x.ty().clone(), y.ty().clone())?; + + Hir::new( + HirKind::Expr(ExprKind::BinOp( + BinOp::RecursiveRecordTypeMerge, + x.ty().to_hir(env.as_varenv()), + y.ty().to_hir(env.as_varenv()), + )), + span.clone(), + ) + .eval(env) } ExprKind::BinOp(BinOp::RecursiveRecordTypeMerge, x, y) => { - fn check_rectymerge( - span: &Span, - env: &TyEnv, - x: Type, - y: Type, - ) -> Result<(), TypeError> { - let kts_x = match x.kind() { - ValueKind::RecordType(kts) => kts, - _ => { - return mk_span_err( - span.clone(), - "RecordTypeMergeRequiresRecordType", - ) - } - }; - let kts_y = match y.kind() { - ValueKind::RecordType(kts) => kts, - _ => { - return mk_span_err( - span.clone(), - "RecordTypeMergeRequiresRecordType", - ) - } - }; - for (k, tx) in kts_x { - if let Some(ty) = kts_y.get(k) { - check_rectymerge(span, env, tx.clone(), ty.clone())?; - } - } - Ok(()) - } check_rectymerge(&span, env, x.eval(env), y.eval(env))?; // A RecordType's type is always a const -- cgit v1.2.3 From 5057144ed99bc4e1a76a0840dd39fc1bd862665c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 15 Feb 2020 19:10:52 +0000 Subject: Desugar Completion during resolution --- dhall/src/semantics/hir.rs | 2 +- dhall/src/semantics/nze/normalize.rs | 20 ++++++++-------- dhall/src/semantics/resolve.rs | 45 ++++++++++++++++++++++++++---------- dhall/src/semantics/tck/typecheck.rs | 34 +++++---------------------- 4 files changed, 49 insertions(+), 52 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index 42f151e..c8258ff 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -14,7 +14,7 @@ pub struct AlphaVar { pub(crate) enum HirKind { /// A resolved variable (i.e. a DeBruijn index) Var(AlphaVar), - // Forbidden ExprKind variants: Var, Import + // Forbidden ExprKind variants: Var, Import, Completion Expr(ExprKind), } diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index c8dd5ae..0e09511 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -231,17 +231,16 @@ pub(crate) fn normalize_one_layer( }; let ret = match expr { - ExprKind::Import(_) => unreachable!( - "There should remain no imports in a resolved expression" - ), - // Those cases have already been completely handled in the typechecking phase (using - // `RetWhole`), so they won't appear here. - ExprKind::Lam(..) - | ExprKind::Pi(..) - | ExprKind::Let(..) - | ExprKind::Var(_) => { - unreachable!("This case should have been handled in typecheck") + ExprKind::Import(..) | ExprKind::Completion(..) => { + unreachable!("This case should have been handled in resolution") } + ExprKind::Var(..) + | ExprKind::Lam(..) + | ExprKind::Pi(..) + | ExprKind::Let(..) => unreachable!( + "This case should have been handled in normalize_hir_whnf" + ), + ExprKind::Annot(x, _) => Ret::Value(x), ExprKind::Const(c) => Ret::Value(Value::from_const(c)), ExprKind::Builtin(b) => Ret::Value(Value::from_builtin_env(b, env)), @@ -391,7 +390,6 @@ pub(crate) fn normalize_one_layer( ExprKind::ProjectionByExpr(_, _) => { unimplemented!("selection by expression") } - ExprKind::Completion(_, _) => unimplemented!("record completion"), ExprKind::Merge(ref handlers, ref variant, _) => { match handlers.kind() { diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index fac88d2..3038597 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -105,9 +105,9 @@ fn traverse_resolve_expr( expr: &Expr, f: &mut impl FnMut(Import) -> Result, ) -> Result { - let kind = match expr.kind() { + Ok(match expr.kind() { ExprKind::Var(var) => match name_env.unlabel_var(&var) { - Some(v) => HirKind::Var(v), + Some(v) => Hir::new(HirKind::Var(v), expr.span()), None => mkerr( ErrorBuilder::new(format!("unbound variable `{}`", var)) .span_err(expr.span(), "not found in this scope") @@ -115,16 +115,38 @@ fn traverse_resolve_expr( )?, }, ExprKind::BinOp(BinOp::ImportAlt, l, r) => { - return match traverse_resolve_expr(name_env, l, f) { - Ok(l) => Ok(l), + match traverse_resolve_expr(name_env, l, f) { + Ok(l) => l, Err(_) => { match traverse_resolve_expr(name_env, r, f) { - Ok(r) => Ok(r), + Ok(r) => r, // TODO: keep track of the other error too - Err(e) => Err(e), + Err(e) => return Err(e), } } - }; + } + } + // Desugar + ExprKind::Completion(ty, compl) => { + let ty_field_default = Expr::new( + ExprKind::Field(ty.clone(), "default".into()), + expr.span(), + ); + let merged = Expr::new( + ExprKind::BinOp( + BinOp::RightBiasedRecordMerge, + ty_field_default, + compl.clone(), + ), + expr.span(), + ); + let ty_field_type = Expr::new( + ExprKind::Field(ty.clone(), "Type".into()), + expr.span(), + ); + let desugared = + Expr::new(ExprKind::Annot(merged, ty_field_type), expr.span()); + traverse_resolve_expr(name_env, &desugared, f)? } kind => { let kind = kind.traverse_ref_maybe_binder(|l, e| { @@ -137,14 +159,13 @@ fn traverse_resolve_expr( } Ok::<_, Error>(hir) })?; - match kind { + let kind = match kind { ExprKind::Import(import) => f(import)?.kind().clone(), kind => HirKind::Expr(kind), - } + }; + Hir::new(kind, expr.span()) } - }; - - Ok(Hir::new(kind, expr.span())) + }) } fn resolve_with_env( diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index a8a2d95..36f7173 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -75,12 +75,14 @@ fn type_one_layer( let span_err = |msg: &str| mk_span_err(span.clone(), msg); let ty = match &ekind { - ExprKind::Import(..) => unreachable!( - "There should remain no imports in a resolved expression" - ), + ExprKind::Import(..) | ExprKind::Completion(..) => { + unreachable!("This case should have been handled in resolution") + } ExprKind::Var(..) | ExprKind::Const(Const::Sort) - | ExprKind::Annot(..) => unreachable!(), // Handled in type_with + | ExprKind::Annot(..) => { + unreachable!("This case should have been handled in type_with") + } ExprKind::Lam(binder, annot, body) => { if annot.ty().as_const().is_none() { @@ -739,30 +741,6 @@ fn type_one_layer( selection_val } - ExprKind::Completion(ty, compl) => { - let ty_field_default = type_one_layer( - env, - ExprKind::Field(ty.clone(), "default".into()), - None, - span.clone(), - )?; - let ty_field_type = type_one_layer( - env, - ExprKind::Field(ty.clone(), "Type".into()), - None, - span.clone(), - )?; - return type_one_layer( - env, - ExprKind::BinOp( - BinOp::RightBiasedRecordMerge, - ty_field_default, - compl.clone(), - ), - Some(ty_field_type.eval(env)), - span.clone(), - ); - } }; if let Some(annot) = annot { -- cgit v1.2.3 From aa867b21f57f9bef2ec2b9d8450736f9111189ee Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 15 Feb 2020 19:44:40 +0000 Subject: Introduce proper Type struct --- dhall/src/semantics/hir.rs | 6 +- dhall/src/semantics/nze/value.rs | 5 +- dhall/src/semantics/tck/tyexpr.rs | 54 +++++++++++++++-- dhall/src/semantics/tck/typecheck.rs | 111 +++++++++++++++++++---------------- 4 files changed, 120 insertions(+), 56 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index c8258ff..d0a8a96 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] use crate::error::TypeError; -use crate::semantics::{type_with, NameEnv, NzEnv, TyEnv, TyExpr, Value}; +use crate::semantics::{type_with, NameEnv, NzEnv, TyEnv, TyExpr, Type, Value}; use crate::syntax::{Expr, ExprKind, Span, V}; use crate::{NormalizedExpr, ToExprOptions}; @@ -79,6 +79,10 @@ impl Hir { pub fn eval(&self, env: impl Into) -> Value { Value::new_thunk(env.into(), self.clone()) } + /// Evaluate to a Type. + pub fn eval_to_type(&self, env: impl Into) -> Type { + self.eval(env).into() + } /// Eval a closed Hir (i.e. without free variables). It will actually get evaluated only as /// needed on demand. pub fn eval_closed_expr(&self) -> Value { diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index 3a5b5b5..f31fd6c 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -4,7 +4,7 @@ use std::rc::Rc; use crate::semantics::nze::lazy; use crate::semantics::{ apply_any, normalize_hir_whnf, normalize_one_layer, squash_textlit, Binder, - BuiltinClosure, Hir, HirKind, NzEnv, NzVar, TyEnv, VarEnv, + BuiltinClosure, Hir, HirKind, NzEnv, NzVar, TyEnv, Type, VarEnv, }; use crate::syntax::{ BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, Label, LitKind, @@ -139,6 +139,9 @@ impl Value { self.0.kind() } + pub(crate) fn to_type(&self) -> Type { + self.clone().into() + } /// Converts a value back to the corresponding AST expression. pub(crate) fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { if opts.normalize { diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index dfb4397..4999899 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -1,17 +1,53 @@ use crate::error::TypeError; -use crate::semantics::{Hir, HirKind, NzEnv, TyEnv, Value}; -use crate::syntax::{Const, Span}; +use crate::semantics::{Hir, HirKind, NzEnv, TyEnv, Value, ValueKind, VarEnv}; +use crate::syntax::{Builtin, Const, Span}; use crate::{NormalizedExpr, ToExprOptions}; -pub(crate) type Type = Value; +/// An expression representing a type +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct Type { + val: Value, +} -// A hir expression plus its inferred type. +/// A hir expression plus its inferred type. #[derive(Debug, Clone)] pub(crate) struct TyExpr { hir: Hir, ty: Type, } +impl Type { + pub fn from_const(c: Const) -> Self { + Value::from_const(c).into() + } + pub fn from_builtin(b: Builtin) -> Self { + Value::from_builtin(b).into() + } + + pub fn to_value(&self) -> Value { + self.val.clone() + } + pub fn as_value(&self) -> &Value { + &self.val + } + pub fn into_value(self) -> Value { + self.val + } + pub fn as_const(&self) -> Option { + self.val.as_const() + } + pub fn kind(&self) -> &ValueKind { + self.val.kind() + } + + pub fn to_hir(&self, venv: VarEnv) -> Hir { + self.val.to_hir(venv) + } + pub fn to_expr_tyenv(&self, tyenv: &TyEnv) -> NormalizedExpr { + self.val.to_hir(tyenv.as_varenv()).to_expr_tyenv(tyenv) + } +} + impl TyExpr { pub fn new(kind: HirKind, ty: Type, span: Span) -> Self { TyExpr { @@ -52,6 +88,10 @@ impl TyExpr { pub fn eval(&self, env: impl Into) -> Value { self.as_hir().eval(env.into()) } + /// Evaluate to a Type. + pub fn eval_to_type(&self, env: impl Into) -> Type { + self.eval(env).into() + } /// Eval a closed TyExpr (i.e. without free variables). It will actually get evaluated only as /// needed on demand. pub fn eval_closed_expr(&self) -> Value { @@ -64,3 +104,9 @@ impl TyExpr { val } } + +impl From for Type { + fn from(x: Value) -> Type { + Type { val: x } + } +} diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 36f7173..dd996ae 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -38,7 +38,8 @@ fn check_rectymerge( }; for (k, tx) in kts_x { if let Some(ty) = kts_y.get(k) { - check_rectymerge(span, env, tx.clone(), ty.clone())?; + // TODO: store Type in RecordType ? + check_rectymerge(span, env, tx.clone().into(), ty.clone().into())?; } } Ok(()) @@ -105,7 +106,7 @@ fn type_one_layer( .format(), ); } - let body_env = env.insert_type(&binder, annot.eval(env)); + let body_env = env.insert_type(&binder, annot.eval_to_type(env)); if body.get_kind(&body_env)?.is_none() { return span_err("Invalid output type"); } @@ -117,7 +118,7 @@ fn type_one_layer( )), span.clone(), ) - .eval(env) + .eval_to_type(env) } ExprKind::Pi(_, annot, body) => { let ks = match annot.ty().as_const() { @@ -148,29 +149,29 @@ fn type_one_layer( _ => return span_err("Invalid output type"), }; - Value::from_const(function_check(ks, kt)) + Type::from_const(function_check(ks, kt)) } ExprKind::Let(_, _, _, body) => body.ty().clone(), - ExprKind::Const(Const::Type) => Value::from_const(Const::Kind), - ExprKind::Const(Const::Kind) => Value::from_const(Const::Sort), + ExprKind::Const(Const::Type) => Type::from_const(Const::Kind), + ExprKind::Const(Const::Kind) => Type::from_const(Const::Sort), ExprKind::Builtin(b) => { let t_hir = type_of_builtin(*b); let t_tyexpr = typecheck(&t_hir)?; - t_tyexpr.eval(env) + t_tyexpr.eval_to_type(env) } - ExprKind::Lit(LitKind::Bool(_)) => Value::from_builtin(Builtin::Bool), + ExprKind::Lit(LitKind::Bool(_)) => Type::from_builtin(Builtin::Bool), ExprKind::Lit(LitKind::Natural(_)) => { - Value::from_builtin(Builtin::Natural) + Type::from_builtin(Builtin::Natural) } ExprKind::Lit(LitKind::Integer(_)) => { - Value::from_builtin(Builtin::Integer) + Type::from_builtin(Builtin::Integer) } ExprKind::Lit(LitKind::Double(_)) => { - Value::from_builtin(Builtin::Double) + Type::from_builtin(Builtin::Double) } ExprKind::TextLit(interpolated) => { - let text_type = Value::from_builtin(Builtin::Text); + let text_type = Type::from_builtin(Builtin::Text); for contents in interpolated.iter() { use InterpolatedTextContents::Expr; if let Expr(x) = contents { @@ -182,7 +183,7 @@ fn type_one_layer( text_type } ExprKind::EmptyListLit(t) => { - let t = t.eval(env); + let t = t.eval_to_type(env); match t.kind() { ValueKind::AppliedBuiltin(BuiltinClosure { b: Builtin::List, @@ -205,16 +206,16 @@ fn type_one_layer( return span_err("InvalidListType"); } - let t = x.ty().clone(); - Value::from_builtin(Builtin::List).app(t) + let t = x.ty().to_value(); + Value::from_builtin(Builtin::List).app(t).to_type() } ExprKind::SomeLit(x) => { if x.get_kind(env)? != Some(Const::Type) { return span_err("InvalidOptionalType"); } - let t = x.ty().clone(); - Value::from_builtin(Builtin::Optional).app(t) + let t = x.ty().to_value(); + Value::from_builtin(Builtin::Optional).app(t).to_type() } ExprKind::RecordLit(kvs) => { use std::collections::hash_map::Entry; @@ -225,7 +226,7 @@ fn type_one_layer( Entry::Occupied(_) => { return span_err("RecordTypeDuplicateField") } - Entry::Vacant(e) => e.insert(v.ty().clone()), + Entry::Vacant(e) => e.insert(v.ty().to_value()), }; // Check that the fields have a valid kind @@ -235,7 +236,7 @@ fn type_one_layer( } } - Value::from_kind(ValueKind::RecordType(kts)) + Value::from_kind(ValueKind::RecordType(kts)).to_type() } ExprKind::RecordType(kts) => { use std::collections::hash_map::Entry; @@ -259,7 +260,7 @@ fn type_one_layer( } } - Value::from_const(k) + Type::from_const(k) } ExprKind::UnionType(kts) => { use std::collections::hash_map::Entry; @@ -286,17 +287,17 @@ fn type_one_layer( // an union type with only unary variants also has type Type let k = k.unwrap_or(Const::Type); - Value::from_const(k) + Type::from_const(k) } ExprKind::Field(scrut, x) => { match scrut.ty().kind() { ValueKind::RecordType(kts) => match kts.get(&x) { - Some(tth) => tth.clone(), + Some(val) => val.clone().to_type(), None => return span_err("MissingRecordField"), }, // TODO: branch here only when scrut.ty() is a Const _ => { - let scrut_nf = scrut.eval(env); + let scrut_nf = scrut.eval_to_type(env); match scrut_nf.kind() { ValueKind::UnionType(kts) => match kts.get(x) { // Constructor has type T -> < x: T, ... > @@ -304,8 +305,11 @@ fn type_one_layer( Value::from_kind(ValueKind::PiClosure { binder: Binder::new(x.clone()), annot: ty.clone(), - closure: Closure::new_constant(scrut_nf), + closure: Closure::new_constant( + scrut_nf.into_value(), + ), }) + .to_type() } Some(None) => scrut_nf, None => return span_err("MissingUnionField"), @@ -316,7 +320,7 @@ fn type_one_layer( } } ExprKind::Assert(t) => { - let t = t.eval(env); + let t = t.eval_to_type(env); match t.kind() { ValueKind::Equivalence(x, y) if x == y => {} ValueKind::Equivalence(..) => { @@ -328,8 +332,9 @@ fn type_one_layer( } ExprKind::App(f, arg) => { match f.ty().kind() { + // TODO: store Type in closure ValueKind::PiClosure { annot, closure, .. } => { - if arg.ty() != annot { + if arg.ty().as_value() != annot { return mkerr( ErrorBuilder::new(format!( "wrong type of function argument" @@ -358,7 +363,7 @@ fn type_one_layer( } let arg_nf = arg.eval(env); - closure.apply(arg_nf) + closure.apply(arg_nf).to_type() } _ => return mkerr( ErrorBuilder::new(format!( @@ -407,7 +412,7 @@ fn type_one_layer( Ok(r_t.clone()) })?; - Value::from_kind(ValueKind::RecordType(kts)) + Value::from_kind(ValueKind::RecordType(kts)).to_type() } ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y) => { check_rectymerge(&span, env, x.ty().clone(), y.ty().clone())?; @@ -420,15 +425,20 @@ fn type_one_layer( )), span.clone(), ) - .eval(env) + .eval_to_type(env) } ExprKind::BinOp(BinOp::RecursiveRecordTypeMerge, x, y) => { - check_rectymerge(&span, env, x.eval(env), y.eval(env))?; + check_rectymerge( + &span, + env, + x.eval_to_type(env), + y.eval_to_type(env), + )?; // A RecordType's type is always a const let xk = x.ty().as_const().unwrap(); let yk = y.ty().as_const().unwrap(); - Value::from_const(max(xk, yk)) + Type::from_const(max(xk, yk)) } ExprKind::BinOp(BinOp::ListAppend, l, r) => { match l.ty().kind() { @@ -453,10 +463,10 @@ fn type_one_layer( return span_err("EquivalenceArgumentsMustBeTerms"); } - Value::from_const(Const::Type) + Type::from_const(Const::Type) } ExprKind::BinOp(o, l, r) => { - let t = Value::from_builtin(match o { + let t = Type::from_builtin(match o { BinOp::BoolAnd | BinOp::BoolOr | BinOp::BoolEQ @@ -507,7 +517,7 @@ fn type_one_layer( let mut inferred_type = None; for (x, handler_type) in handlers { - let handler_return_type = match variants.get(x) { + let handler_return_type: Type = match variants.get(x) { // Union alternative with type Some(Some(variant_type)) => match handler_type.kind() { ValueKind::PiClosure { closure, annot, .. } => { @@ -542,7 +552,7 @@ fn type_one_layer( } match closure.remove_binder() { - Ok(v) => v, + Ok(v) => v.to_type(), Err(()) => { return span_err( "MergeReturnTypeIsDependent", @@ -586,7 +596,7 @@ fn type_one_layer( } }, // Union alternative without type - Some(None) => handler_type.clone(), + Some(None) => handler_type.clone().to_type(), None => return span_err("MergeHandlerMissingVariant"), }; match &inferred_type { @@ -604,7 +614,7 @@ fn type_one_layer( } } - let type_annot = type_annot.as_ref().map(|t| t.eval(env)); + let type_annot = type_annot.as_ref().map(|t| t.eval_to_type(env)); match (inferred_type, type_annot) { (Some(t1), Some(t2)) => { if t1 != t2 { @@ -638,7 +648,7 @@ fn type_one_layer( annotation", ); }; - let annot_val = annot.eval(env); + let annot_val = annot.eval_to_type(env); let err_msg = "The type of `toMap x` must be of the form \ `List { mapKey : Text, mapValue : T }`"; @@ -679,10 +689,11 @@ fn type_one_layer( let mut kts = HashMap::new(); kts.insert("mapKey".into(), Value::from_builtin(Builtin::Text)); kts.insert("mapValue".into(), entry_type); - let output_type = Value::from_builtin(Builtin::List) - .app(Value::from_kind(ValueKind::RecordType(kts))); + let output_type: Type = Value::from_builtin(Builtin::List) + .app(Value::from_kind(ValueKind::RecordType(kts))) + .to_type(); if let Some(annot) = annot { - let annot_val = annot.eval(env); + let annot_val = annot.eval_to_type(env); if output_type != annot_val { return span_err("Annotation mismatch"); } @@ -713,7 +724,7 @@ fn type_one_layer( }; } - Value::from_kind(ValueKind::RecordType(new_kts)) + Value::from_kind(ValueKind::RecordType(new_kts)).to_type() } ExprKind::ProjectionByExpr(record, selection) => { let record_type = record.ty(); @@ -722,7 +733,7 @@ fn type_one_layer( _ => return span_err("ProjectionMustBeRecord"), }; - let selection_val = selection.eval(env); + let selection_val = selection.eval_to_type(env); let sel_kts = match selection_val.kind() { ValueKind::RecordType(kts) => kts, _ => return span_err("ProjectionByExprTakesRecordType"), @@ -781,9 +792,9 @@ pub(crate) fn type_with( HirKind::Expr(ExprKind::Annot(x, t)) => { let t = match t.kind() { HirKind::Expr(ExprKind::Const(Const::Sort)) => { - Value::from_const(Const::Sort) + Type::from_const(Const::Sort) } - _ => type_with(env, t, None)?.eval(env), + _ => type_with(env, t, None)?.eval_to_type(env), }; type_with(env, x, Some(t)) } @@ -791,21 +802,21 @@ pub(crate) fn type_with( let ekind = match ekind { ExprKind::Lam(binder, annot, body) => { let annot = type_with(env, annot, None)?; - let annot_nf = annot.eval(env); + let annot_nf = annot.eval_to_type(env); let body_env = env.insert_type(binder, annot_nf); let body = type_with(&body_env, body, None)?; ExprKind::Lam(binder.clone(), annot, body) } ExprKind::Pi(binder, annot, body) => { let annot = type_with(env, annot, None)?; - let annot_nf = annot.eval(env); - let body_env = env.insert_type(binder, annot_nf); + let annot_val = annot.eval_to_type(env); + let body_env = env.insert_type(binder, annot_val); let body = type_with(&body_env, body, None)?; ExprKind::Pi(binder.clone(), annot, body) } ExprKind::Let(binder, annot, val, body) => { let val_annot = if let Some(t) = annot { - Some(type_with(env, t, None)?.eval(env)) + Some(type_with(env, t, None)?.eval_to_type(env)) } else { None }; @@ -831,6 +842,6 @@ pub(crate) fn typecheck(hir: &Hir) -> Result { /// Like `typecheck`, but additionally checks that the expression's type matches the provided type. pub(crate) fn typecheck_with(hir: &Hir, ty: Hir) -> Result { - let ty = typecheck(&ty)?.eval(&TyEnv::new()); + let ty = typecheck(&ty)?.eval_to_type(&TyEnv::new()); type_with(&TyEnv::new(), hir, Some(ty)) } -- cgit v1.2.3 From 130de8cea49c848a06174c61c747d9414a5c71b7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 16 Feb 2020 19:06:23 +0000 Subject: Start requiring Universe to build a Type --- dhall/src/semantics/nze/normalize.rs | 2 +- dhall/src/semantics/tck/tyexpr.rs | 117 +++++++++++++--- dhall/src/semantics/tck/typecheck.rs | 263 ++++++++++++++--------------------- 3 files changed, 206 insertions(+), 176 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index 0e09511..c2d2dc2 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -471,7 +471,7 @@ pub(crate) fn normalize_hir_whnf(env: &NzEnv, hir: &Hir) -> ValueKind { closure: Closure::new(env, body.clone()), } } - HirKind::Expr(ExprKind::Let(_, None, val, body)) => { + HirKind::Expr(ExprKind::Let(_, _, val, body)) => { let val = val.eval(env); body.eval(env.insert_value(val, ())).kind().clone() } diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index 4999899..3c47a81 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -1,8 +1,12 @@ -use crate::error::TypeError; -use crate::semantics::{Hir, HirKind, NzEnv, TyEnv, Value, ValueKind, VarEnv}; +use crate::error::{ErrorBuilder, TypeError}; +use crate::semantics::{mkerr, Hir, NzEnv, TyEnv, Value, ValueKind, VarEnv}; use crate::syntax::{Builtin, Const, Span}; use crate::{NormalizedExpr, ToExprOptions}; +/// The type of a type. 0 is `Type`, 1 is `Kind`, etc... +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] +pub(crate) struct Universe(u8); + /// An expression representing a type #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct Type { @@ -16,12 +20,64 @@ pub(crate) struct TyExpr { ty: Type, } +impl Universe { + pub fn from_const(c: Const) -> Self { + Universe(match c { + Const::Type => 0, + Const::Kind => 1, + Const::Sort => 2, + }) + } + pub fn as_const(self) -> Option { + match self.0 { + 0 => Some(Const::Type), + 1 => Some(Const::Kind), + 2 => Some(Const::Sort), + _ => None, + } + } + pub fn next(self) -> Self { + Universe(self.0 + 1) + } + pub fn previous(self) -> Option { + if self.0 == 0 { + None + } else { + Some(Universe(self.0 - 1)) + } + } +} + impl Type { + pub fn new(val: Value, _u: Universe) -> Self { + Type { val } + } pub fn from_const(c: Const) -> Self { - Value::from_const(c).into() + Self::new(Value::from_const(c), c.to_universe().next()) } pub fn from_builtin(b: Builtin) -> Self { - Value::from_builtin(b).into() + use Builtin::*; + match b { + Bool | Natural | Integer | Double | Text => {} + _ => unreachable!("this builtin is not a type: {}", b), + } + + Self::new(Value::from_builtin(b), Universe::from_const(Const::Type)) + } + + /// Get the type of this type + // TODO: avoid recomputing so much + pub fn ty(&self, env: &TyEnv) -> Result, TypeError> { + Ok(self.to_hir(env.as_varenv()).typecheck(env)?.ty().as_const()) + } + /// Get the type of this type + // TODO: avoid recomputing so much + pub fn ty_univ(&self, env: &TyEnv) -> Result { + Ok(match self.ty(env)? { + Some(c) => c.to_universe(), + // TODO: hack, might explode + None => Const::Sort.to_universe().next(), + }) } pub fn to_value(&self) -> Value { @@ -49,9 +105,9 @@ impl Type { } impl TyExpr { - pub fn new(kind: HirKind, ty: Type, span: Span) -> Self { + pub fn from_hir(hir: &Hir, ty: Type) -> Self { TyExpr { - hir: Hir::new(kind, span), + hir: hir.clone(), ty, } } @@ -62,16 +118,6 @@ impl TyExpr { pub fn ty(&self) -> &Type { &self.ty } - /// Get the kind (the type of the type) of this value - // TODO: avoid recomputing so much - pub fn get_kind(&self, env: &TyEnv) -> Result, TypeError> { - Ok(self - .ty() - .to_hir(env.as_varenv()) - .typecheck(env)? - .ty() - .as_const()) - } pub fn to_hir(&self) -> Hir { self.as_hir().clone() @@ -79,18 +125,51 @@ impl TyExpr { pub fn as_hir(&self) -> &Hir { &self.hir } - /// Converts a value back to the corresponding AST expression. + /// Converts a closed expression back to the corresponding AST expression. pub fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { self.as_hir().to_expr(opts) } + pub fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { + self.as_hir().to_expr_tyenv(env) + } /// Eval the TyExpr. It will actually get evaluated only as needed on demand. pub fn eval(&self, env: impl Into) -> Value { self.as_hir().eval(env.into()) } + pub fn ensure_is_type(&self, env: &TyEnv) -> Result<(), TypeError> { + if self.ty().as_const().is_none() { + return mkerr( + ErrorBuilder::new(format!( + "Expected a type, found: `{}`", + self.to_expr_tyenv(env), + )) + .span_err( + self.span(), + format!( + "this has type: `{}`", + self.ty().to_expr_tyenv(env) + ), + ) + .help(format!( + "An expression in type position must have type `Type`, \ + `Kind` or `Sort`", + )) + .format(), + ); + } + Ok(()) + } /// Evaluate to a Type. - pub fn eval_to_type(&self, env: impl Into) -> Type { - self.eval(env).into() + pub fn eval_to_type(&self, env: &TyEnv) -> Result { + self.ensure_is_type(env)?; + Ok(Type::new( + self.eval(env), + self.ty() + .as_const() + .expect("case handled in ensure_is_type") + .to_universe(), + )) } /// Eval a closed TyExpr (i.e. without free variables). It will actually get evaluated only as /// needed on demand. diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index dd996ae..1281045 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -15,8 +15,8 @@ use crate::syntax::{ fn check_rectymerge( span: &Span, env: &TyEnv, - x: Type, - y: Type, + x: Value, + y: Value, ) -> Result<(), TypeError> { let kts_x = match x.kind() { ValueKind::RecordType(kts) => kts, @@ -39,7 +39,7 @@ fn check_rectymerge( for (k, tx) in kts_x { if let Some(ty) = kts_y.get(k) { // TODO: store Type in RecordType ? - check_rectymerge(span, env, tx.clone().into(), ty.clone().into())?; + check_rectymerge(span, env, tx.clone(), ty.clone())?; } } Ok(()) @@ -70,9 +70,8 @@ pub fn mk_span_err(span: Span, msg: S) -> Result { fn type_one_layer( env: &TyEnv, ekind: ExprKind, - annot: Option, span: Span, -) -> Result { +) -> Result { let span_err = |msg: &str| mk_span_err(span.clone(), msg); let ty = match &ekind { @@ -81,84 +80,19 @@ fn type_one_layer( } ExprKind::Var(..) | ExprKind::Const(Const::Sort) + | ExprKind::Lam(..) + | ExprKind::Pi(..) + | ExprKind::Let(..) | ExprKind::Annot(..) => { unreachable!("This case should have been handled in type_with") } - ExprKind::Lam(binder, annot, body) => { - if annot.ty().as_const().is_none() { - return mkerr( - ErrorBuilder::new(format!( - "Invalid input type: `{}`", - annot.ty().to_expr_tyenv(env), - )) - .span_err( - annot.span(), - format!( - "this has type: `{}`", - annot.ty().to_expr_tyenv(env) - ), - ) - .help(format!( - "The input type of a function must have type `Type`, \ - `Kind` or `Sort`", - )) - .format(), - ); - } - let body_env = env.insert_type(&binder, annot.eval_to_type(env)); - if body.get_kind(&body_env)?.is_none() { - return span_err("Invalid output type"); - } - Hir::new( - HirKind::Expr(ExprKind::Pi( - binder.clone(), - annot.to_hir(), - body.ty().to_hir(body_env.as_varenv()), - )), - span.clone(), - ) - .eval_to_type(env) - } - ExprKind::Pi(_, annot, body) => { - let ks = match annot.ty().as_const() { - Some(k) => k, - _ => { - return mkerr( - ErrorBuilder::new(format!( - "Invalid input type: `{}`", - annot.ty().to_expr_tyenv(env), - )) - .span_err( - annot.span(), - format!( - "this has type: `{}`", - annot.ty().to_expr_tyenv(env) - ), - ) - .help(format!( - "The input type of a function must have type \ - `Type`, `Kind` or `Sort`", - )) - .format(), - ); - } - }; - let kt = match body.ty().as_const() { - Some(k) => k, - _ => return span_err("Invalid output type"), - }; - - Type::from_const(function_check(ks, kt)) - } - ExprKind::Let(_, _, _, body) => body.ty().clone(), - ExprKind::Const(Const::Type) => Type::from_const(Const::Kind), ExprKind::Const(Const::Kind) => Type::from_const(Const::Sort), ExprKind::Builtin(b) => { let t_hir = type_of_builtin(*b); let t_tyexpr = typecheck(&t_hir)?; - t_tyexpr.eval_to_type(env) + t_tyexpr.eval_to_type(env)? } ExprKind::Lit(LitKind::Bool(_)) => Type::from_builtin(Builtin::Bool), ExprKind::Lit(LitKind::Natural(_)) => { @@ -183,7 +117,7 @@ fn type_one_layer( text_type } ExprKind::EmptyListLit(t) => { - let t = t.eval_to_type(env); + let t = t.eval_to_type(env)?; match t.kind() { ValueKind::AppliedBuiltin(BuiltinClosure { b: Builtin::List, @@ -202,7 +136,7 @@ fn type_one_layer( return span_err("InvalidListElement"); } } - if x.get_kind(env)? != Some(Const::Type) { + if x.ty().ty(env)? != Some(Const::Type) { return span_err("InvalidListType"); } @@ -210,7 +144,7 @@ fn type_one_layer( Value::from_builtin(Builtin::List).app(t).to_type() } ExprKind::SomeLit(x) => { - if x.get_kind(env)? != Some(Const::Type) { + if x.ty().ty(env)? != Some(Const::Type) { return span_err("InvalidOptionalType"); } @@ -230,7 +164,7 @@ fn type_one_layer( }; // Check that the fields have a valid kind - match v.get_kind(env)? { + match v.ty().ty(env)? { Some(_) => {} None => return span_err("InvalidFieldType"), } @@ -297,7 +231,7 @@ fn type_one_layer( }, // TODO: branch here only when scrut.ty() is a Const _ => { - let scrut_nf = scrut.eval_to_type(env); + let scrut_nf = scrut.eval(env); match scrut_nf.kind() { ValueKind::UnionType(kts) => match kts.get(x) { // Constructor has type T -> < x: T, ... > @@ -305,13 +239,11 @@ fn type_one_layer( Value::from_kind(ValueKind::PiClosure { binder: Binder::new(x.clone()), annot: ty.clone(), - closure: Closure::new_constant( - scrut_nf.into_value(), - ), + closure: Closure::new_constant(scrut_nf), }) .to_type() } - Some(None) => scrut_nf, + Some(None) => scrut_nf.to_type(), None => return span_err("MissingUnionField"), }, _ => return span_err("NotARecord"), @@ -320,7 +252,7 @@ fn type_one_layer( } } ExprKind::Assert(t) => { - let t = t.eval_to_type(env); + let t = t.eval_to_type(env)?; match t.kind() { ValueKind::Equivalence(x, y) if x == y => {} ValueKind::Equivalence(..) => { @@ -382,7 +314,7 @@ fn type_one_layer( if *x.ty().kind() != ValueKind::from_builtin(Builtin::Bool) { return span_err("InvalidPredicate"); } - if y.get_kind(env)? != Some(Const::Type) { + if y.ty().ty(env)? != Some(Const::Type) { return span_err("IfBranchMustBeTerm"); } if y.ty() != z.ty() { @@ -415,25 +347,22 @@ fn type_one_layer( Value::from_kind(ValueKind::RecordType(kts)).to_type() } ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y) => { - check_rectymerge(&span, env, x.ty().clone(), y.ty().clone())?; + check_rectymerge(&span, env, x.ty().to_value(), y.ty().to_value())?; - Hir::new( + let hir = Hir::new( HirKind::Expr(ExprKind::BinOp( BinOp::RecursiveRecordTypeMerge, x.ty().to_hir(env.as_varenv()), y.ty().to_hir(env.as_varenv()), )), span.clone(), - ) - .eval_to_type(env) + ); + let x_u = x.ty().ty_univ(env)?; + let y_u = y.ty().ty_univ(env)?; + Type::new(hir.eval(env), max(x_u, y_u)) } ExprKind::BinOp(BinOp::RecursiveRecordTypeMerge, x, y) => { - check_rectymerge( - &span, - env, - x.eval_to_type(env), - y.eval_to_type(env), - )?; + check_rectymerge(&span, env, x.eval(env), y.eval(env))?; // A RecordType's type is always a const let xk = x.ty().as_const().unwrap(); @@ -459,7 +388,7 @@ fn type_one_layer( if l.ty() != r.ty() { return span_err("EquivalenceTypeMismatch"); } - if l.get_kind(env)? != Some(Const::Type) { + if l.ty().ty(env)? != Some(Const::Type) { return span_err("EquivalenceArgumentsMustBeTerms"); } @@ -614,7 +543,10 @@ fn type_one_layer( } } - let type_annot = type_annot.as_ref().map(|t| t.eval_to_type(env)); + let type_annot = type_annot + .as_ref() + .map(|t| t.eval_to_type(env)) + .transpose()?; match (inferred_type, type_annot) { (Some(t1), Some(t2)) => { if t1 != t2 { @@ -628,7 +560,7 @@ fn type_one_layer( } } ExprKind::ToMap(record, annot) => { - if record.get_kind(env)? != Some(Const::Type) { + if record.ty().ty(env)? != Some(Const::Type) { return span_err("`toMap` only accepts records of type `Type`"); } let record_t = record.ty(); @@ -648,7 +580,7 @@ fn type_one_layer( annotation", ); }; - let annot_val = annot.eval_to_type(env); + let annot_val = annot.eval_to_type(env)?; let err_msg = "The type of `toMap x` must be of the form \ `List { mapKey : Text, mapValue : T }`"; @@ -693,7 +625,7 @@ fn type_one_layer( .app(Value::from_kind(ValueKind::RecordType(kts))) .to_type(); if let Some(annot) = annot { - let annot_val = annot.eval_to_type(env); + let annot_val = annot.eval_to_type(env)?; if output_type != annot_val { return span_err("Annotation mismatch"); } @@ -733,7 +665,7 @@ fn type_one_layer( _ => return span_err("ProjectionMustBeRecord"), }; - let selection_val = selection.eval_to_type(env); + let selection_val = selection.eval_to_type(env)?; let sel_kts = match selection_val.kind() { ValueKind::RecordType(kts) => kts, _ => return span_err("ProjectionByExprTakesRecordType"), @@ -754,22 +686,7 @@ fn type_one_layer( } }; - if let Some(annot) = annot { - if ty != annot { - return span_err(&format!( - "annot mismatch: {} != {}", - ty.to_expr_tyenv(env), - annot.to_expr_tyenv(env) - )); - } - } - - // TODO: avoid retraversing - Ok(TyExpr::new( - HirKind::Expr(ekind.map_ref(|tye| tye.to_hir())), - ty, - span, - )) + Ok(ty) } /// `type_with` typechecks an expression in the provided environment. Optionally pass an annotation @@ -779,59 +696,93 @@ pub(crate) fn type_with( hir: &Hir, annot: Option, ) -> Result { - match hir.kind() { - HirKind::Var(var) => { - Ok(TyExpr::new(HirKind::Var(*var), env.lookup(var), hir.span())) - } + let tyexpr = match hir.kind() { + HirKind::Var(var) => TyExpr::from_hir(hir, env.lookup(var)), HirKind::Expr(ExprKind::Var(_)) => { unreachable!("Hir should contain no unresolved variables") } HirKind::Expr(ExprKind::Const(Const::Sort)) => { - mk_span_err(hir.span(), "Sort does not have a type") + return mk_span_err(hir.span(), "Sort does not have a type") } HirKind::Expr(ExprKind::Annot(x, t)) => { let t = match t.kind() { HirKind::Expr(ExprKind::Const(Const::Sort)) => { Type::from_const(Const::Sort) } - _ => type_with(env, t, None)?.eval_to_type(env), + _ => type_with(env, t, None)?.eval_to_type(env)?, }; - type_with(env, x, Some(t)) + type_with(env, x, Some(t))? } - HirKind::Expr(ekind) => { - let ekind = match ekind { - ExprKind::Lam(binder, annot, body) => { - let annot = type_with(env, annot, None)?; - let annot_nf = annot.eval_to_type(env); - let body_env = env.insert_type(binder, annot_nf); - let body = type_with(&body_env, body, None)?; - ExprKind::Lam(binder.clone(), annot, body) - } - ExprKind::Pi(binder, annot, body) => { - let annot = type_with(env, annot, None)?; - let annot_val = annot.eval_to_type(env); - let body_env = env.insert_type(binder, annot_val); - let body = type_with(&body_env, body, None)?; - ExprKind::Pi(binder.clone(), annot, body) - } - ExprKind::Let(binder, annot, val, body) => { - let val_annot = if let Some(t) = annot { - Some(type_with(env, t, None)?.eval_to_type(env)) - } else { - None - }; - let val = type_with(env, &val, val_annot)?; - let val_nf = val.eval(env); - let body_env = - env.insert_value(&binder, val_nf, val.ty().clone()); - let body = type_with(&body_env, body, None)?; - ExprKind::Let(binder.clone(), None, val, body) - } - _ => ekind.traverse_ref(|e| type_with(env, e, None))?, + + HirKind::Expr(ExprKind::Lam(binder, annot, body)) => { + let annot = type_with(env, annot, None)?; + let annot_nf = annot.eval_to_type(env)?; + let body_env = env.insert_type(binder, annot_nf); + let body = type_with(&body_env, body, None)?; + + let u_annot = annot.ty().as_const().unwrap(); + let u_body = match body.ty().ty(&body_env)? { + Some(k) => k, + _ => return mk_span_err(hir.span(), "Invalid output type"), }; - type_one_layer(env, ekind, annot, hir.span()) + let u = function_check(u_annot, u_body).to_universe(); + let ty_hir = Hir::new( + HirKind::Expr(ExprKind::Pi( + binder.clone(), + annot.to_hir(), + body.ty().to_hir(body_env.as_varenv()), + )), + hir.span(), + ); + let ty = Type::new(ty_hir.eval(env), u); + + TyExpr::from_hir(hir, ty) + } + HirKind::Expr(ExprKind::Pi(binder, annot, body)) => { + let annot = type_with(env, annot, None)?; + let annot_val = annot.eval_to_type(env)?; + let body_env = env.insert_type(binder, annot_val); + let body = type_with(&body_env, body, None)?; + body.ensure_is_type(env)?; + + let ks = annot.ty().as_const().unwrap(); + let kt = body.ty().as_const().unwrap(); + let ty = Type::from_const(function_check(ks, kt)); + TyExpr::from_hir(hir, ty) + } + HirKind::Expr(ExprKind::Let(binder, annot, val, body)) => { + let val_annot = annot + .as_ref() + .map(|t| Ok(type_with(env, t, None)?.eval_to_type(env)?)) + .transpose()?; + let val = type_with(env, &val, val_annot)?; + let val_nf = val.eval(env); + let body_env = env.insert_value(&binder, val_nf, val.ty().clone()); + let body = type_with(&body_env, body, None)?; + let ty = body.ty().clone(); + TyExpr::from_hir(hir, ty) + } + HirKind::Expr(ekind) => { + let ekind = ekind.traverse_ref(|e| type_with(env, e, None))?; + let ty = type_one_layer(env, ekind, hir.span())?; + TyExpr::from_hir(hir, ty) + } + }; + + if let Some(annot) = annot { + if *tyexpr.ty() != annot { + return mk_span_err( + hir.span(), + &format!( + "annot mismatch: {} != {}", + tyexpr.ty().to_expr_tyenv(env), + annot.to_expr_tyenv(env) + ), + ); } } + + Ok(tyexpr) } /// Typecheck an expression and return the expression annotated with types if type-checking @@ -842,6 +793,6 @@ pub(crate) fn typecheck(hir: &Hir) -> Result { /// Like `typecheck`, but additionally checks that the expression's type matches the provided type. pub(crate) fn typecheck_with(hir: &Hir, ty: Hir) -> Result { - let ty = typecheck(&ty)?.eval_to_type(&TyEnv::new()); + let ty = typecheck(&ty)?.eval_to_type(&TyEnv::new())?; type_with(&TyEnv::new(), hir, Some(ty)) } -- cgit v1.2.3 From 80722b6da21a79cc2f00b2944244b28a04c5e169 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 16 Feb 2020 19:15:29 +0000 Subject: Oops, leftover #![allow(dead_code)] --- dhall/src/semantics/hir.rs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index d0a8a96..b5db66f 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -1,6 +1,5 @@ -#![allow(dead_code)] use crate::error::TypeError; -use crate::semantics::{type_with, NameEnv, NzEnv, TyEnv, TyExpr, Type, Value}; +use crate::semantics::{type_with, NameEnv, NzEnv, TyEnv, TyExpr, Value}; use crate::syntax::{Expr, ExprKind, Span, V}; use crate::{NormalizedExpr, ToExprOptions}; @@ -79,21 +78,6 @@ impl Hir { pub fn eval(&self, env: impl Into) -> Value { Value::new_thunk(env.into(), self.clone()) } - /// Evaluate to a Type. - pub fn eval_to_type(&self, env: impl Into) -> Type { - self.eval(env).into() - } - /// Eval a closed Hir (i.e. without free variables). It will actually get evaluated only as - /// needed on demand. - pub fn eval_closed_expr(&self) -> Value { - self.eval(&NzEnv::new()) - } - /// Eval a closed Hir fully and recursively (TODO: ish, need to fix under lambdas) - pub fn rec_eval_closed_expr(&self) -> Value { - let val = self.eval_closed_expr(); - val.normalize(); - val - } } fn hir_to_expr( -- cgit v1.2.3 From c451c18103b871e563b12c524bc3feec5451154c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 16 Feb 2020 19:48:35 +0000 Subject: Avoid recomputing universes in tck --- dhall/src/semantics/nze/value.rs | 6 +-- dhall/src/semantics/tck/tyexpr.rs | 49 ++++++++++++------------ dhall/src/semantics/tck/typecheck.rs | 73 ++++++++++++++++++++++-------------- 3 files changed, 73 insertions(+), 55 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index f31fd6c..7084af6 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -4,7 +4,7 @@ use std::rc::Rc; use crate::semantics::nze::lazy; use crate::semantics::{ apply_any, normalize_hir_whnf, normalize_one_layer, squash_textlit, Binder, - BuiltinClosure, Hir, HirKind, NzEnv, NzVar, TyEnv, Type, VarEnv, + BuiltinClosure, Hir, HirKind, NzEnv, NzVar, TyEnv, Type, Universe, VarEnv, }; use crate::syntax::{ BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, Label, LitKind, @@ -139,8 +139,8 @@ impl Value { self.0.kind() } - pub(crate) fn to_type(&self) -> Type { - self.clone().into() + pub(crate) fn to_type(&self, u: impl Into) -> Type { + Type::new(self.clone(), u.into()) } /// Converts a value back to the corresponding AST expression. pub(crate) fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index 3c47a81..f6591ba 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -11,6 +11,7 @@ pub(crate) struct Universe(u8); #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct Type { val: Value, + univ: Universe, } /// A hir expression plus its inferred type. @@ -39,18 +40,28 @@ impl Universe { pub fn next(self) -> Self { Universe(self.0 + 1) } - pub fn previous(self) -> Option { - if self.0 == 0 { - None - } else { - Some(Universe(self.0 - 1)) - } - } } impl Type { - pub fn new(val: Value, _u: Universe) -> Self { - Type { val } + pub fn new(val: Value, univ: Universe) -> Self { + Type { val, univ } + } + /// Creates a new Type and infers its universe by re-typechecking its value. + /// TODO: ideally avoid this function altogether. Would need to store types in RecordType and + /// PiClosure. + pub fn new_infer_universe( + env: &TyEnv, + val: Value, + ) -> Result { + let c = val.to_hir(env.as_varenv()).typecheck(env)?.ty().as_const(); + let u = match c { + Some(c) => c.to_universe(), + None => unreachable!( + "internal type error: this is not a type: {:?}", + val + ), + }; + Ok(Type::new(val, u)) } pub fn from_const(c: Const) -> Self { Self::new(Value::from_const(c), c.to_universe().next()) @@ -66,18 +77,8 @@ impl Type { } /// Get the type of this type - // TODO: avoid recomputing so much - pub fn ty(&self, env: &TyEnv) -> Result, TypeError> { - Ok(self.to_hir(env.as_varenv()).typecheck(env)?.ty().as_const()) - } - /// Get the type of this type - // TODO: avoid recomputing so much - pub fn ty_univ(&self, env: &TyEnv) -> Result { - Ok(match self.ty(env)? { - Some(c) => c.to_universe(), - // TODO: hack, might explode - None => Const::Sort.to_universe().next(), - }) + pub fn ty(&self) -> Universe { + self.univ } pub fn to_value(&self) -> Value { @@ -184,8 +185,8 @@ impl TyExpr { } } -impl From for Type { - fn from(x: Value) -> Type { - Type { val: x } +impl From for Universe { + fn from(x: Const) -> Universe { + Universe::from_const(x) } } diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 1281045..45b3168 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -136,24 +136,30 @@ fn type_one_layer( return span_err("InvalidListElement"); } } - if x.ty().ty(env)? != Some(Const::Type) { + if x.ty().ty().as_const() != Some(Const::Type) { return span_err("InvalidListType"); } let t = x.ty().to_value(); - Value::from_builtin(Builtin::List).app(t).to_type() + Value::from_builtin(Builtin::List) + .app(t) + .to_type(Const::Type) } ExprKind::SomeLit(x) => { - if x.ty().ty(env)? != Some(Const::Type) { + if x.ty().ty().as_const() != Some(Const::Type) { return span_err("InvalidOptionalType"); } let t = x.ty().to_value(); - Value::from_builtin(Builtin::Optional).app(t).to_type() + Value::from_builtin(Builtin::Optional) + .app(t) + .to_type(Const::Type) } ExprKind::RecordLit(kvs) => { use std::collections::hash_map::Entry; let mut kts = HashMap::new(); + // An empty record type has type Type + let mut k = Const::Type; for (x, v) in kvs { // Check for duplicated entries match kts.entry(x.clone()) { @@ -164,13 +170,13 @@ fn type_one_layer( }; // Check that the fields have a valid kind - match v.ty().ty(env)? { - Some(_) => {} + match v.ty().ty().as_const() { + Some(c) => k = max(k, c), None => return span_err("InvalidFieldType"), } } - Value::from_kind(ValueKind::RecordType(kts)).to_type() + Value::from_kind(ValueKind::RecordType(kts)).to_type(k) } ExprKind::RecordType(kts) => { use std::collections::hash_map::Entry; @@ -226,29 +232,31 @@ fn type_one_layer( ExprKind::Field(scrut, x) => { match scrut.ty().kind() { ValueKind::RecordType(kts) => match kts.get(&x) { - Some(val) => val.clone().to_type(), + Some(val) => Type::new_infer_universe(env, val.clone())?, None => return span_err("MissingRecordField"), }, - // TODO: branch here only when scrut.ty() is a Const - _ => { - let scrut_nf = scrut.eval(env); - match scrut_nf.kind() { + ValueKind::Const(_) => { + let scrut = scrut.eval_to_type(env)?; + match scrut.kind() { ValueKind::UnionType(kts) => match kts.get(x) { // Constructor has type T -> < x: T, ... > Some(Some(ty)) => { Value::from_kind(ValueKind::PiClosure { binder: Binder::new(x.clone()), annot: ty.clone(), - closure: Closure::new_constant(scrut_nf), + closure: Closure::new_constant( + scrut.to_value(), + ), }) - .to_type() + .to_type(scrut.ty()) } - Some(None) => scrut_nf.to_type(), + Some(None) => scrut, None => return span_err("MissingUnionField"), }, _ => return span_err("NotARecord"), } - } // _ => span_err("NotARecord"), + } + _ => return span_err("NotARecord"), } } ExprKind::Assert(t) => { @@ -295,7 +303,7 @@ fn type_one_layer( } let arg_nf = arg.eval(env); - closure.apply(arg_nf).to_type() + Type::new_infer_universe(env, closure.apply(arg_nf))? } _ => return mkerr( ErrorBuilder::new(format!( @@ -314,7 +322,7 @@ fn type_one_layer( if *x.ty().kind() != ValueKind::from_builtin(Builtin::Bool) { return span_err("InvalidPredicate"); } - if y.ty().ty(env)? != Some(Const::Type) { + if y.ty().ty().as_const() != Some(Const::Type) { return span_err("IfBranchMustBeTerm"); } if y.ty() != z.ty() { @@ -344,7 +352,8 @@ fn type_one_layer( Ok(r_t.clone()) })?; - Value::from_kind(ValueKind::RecordType(kts)).to_type() + let u = max(x.ty().ty(), y.ty().ty()); + Value::from_kind(ValueKind::RecordType(kts)).to_type(u) } ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y) => { check_rectymerge(&span, env, x.ty().to_value(), y.ty().to_value())?; @@ -357,8 +366,8 @@ fn type_one_layer( )), span.clone(), ); - let x_u = x.ty().ty_univ(env)?; - let y_u = y.ty().ty_univ(env)?; + let x_u = x.ty().ty(); + let y_u = y.ty().ty(); Type::new(hir.eval(env), max(x_u, y_u)) } ExprKind::BinOp(BinOp::RecursiveRecordTypeMerge, x, y) => { @@ -388,7 +397,7 @@ fn type_one_layer( if l.ty() != r.ty() { return span_err("EquivalenceTypeMismatch"); } - if l.ty().ty(env)? != Some(Const::Type) { + if l.ty().ty().as_const() != Some(Const::Type) { return span_err("EquivalenceArgumentsMustBeTerms"); } @@ -480,8 +489,11 @@ fn type_one_layer( ); } + // TODO: this actually doesn't check anything yet match closure.remove_binder() { - Ok(v) => v.to_type(), + Ok(v) => { + Type::new_infer_universe(env, v.clone())? + } Err(()) => { return span_err( "MergeReturnTypeIsDependent", @@ -525,7 +537,9 @@ fn type_one_layer( } }, // Union alternative without type - Some(None) => handler_type.clone().to_type(), + Some(None) => { + Type::new_infer_universe(env, handler_type.clone())? + } None => return span_err("MergeHandlerMissingVariant"), }; match &inferred_type { @@ -560,7 +574,7 @@ fn type_one_layer( } } ExprKind::ToMap(record, annot) => { - if record.ty().ty(env)? != Some(Const::Type) { + if record.ty().ty().as_const() != Some(Const::Type) { return span_err("`toMap` only accepts records of type `Type`"); } let record_t = record.ty(); @@ -623,7 +637,7 @@ fn type_one_layer( kts.insert("mapValue".into(), entry_type); let output_type: Type = Value::from_builtin(Builtin::List) .app(Value::from_kind(ValueKind::RecordType(kts))) - .to_type(); + .to_type(Const::Type); if let Some(annot) = annot { let annot_val = annot.eval_to_type(env)?; if output_type != annot_val { @@ -656,7 +670,10 @@ fn type_one_layer( }; } - Value::from_kind(ValueKind::RecordType(new_kts)).to_type() + Type::new_infer_universe( + env, + Value::from_kind(ValueKind::RecordType(new_kts)), + )? } ExprKind::ProjectionByExpr(record, selection) => { let record_type = record.ty(); @@ -721,7 +738,7 @@ pub(crate) fn type_with( let body = type_with(&body_env, body, None)?; let u_annot = annot.ty().as_const().unwrap(); - let u_body = match body.ty().ty(&body_env)? { + let u_body = match body.ty().ty().as_const() { Some(k) => k, _ => return mk_span_err(hir.span(), "Invalid output type"), }; -- cgit v1.2.3 From 8264df65c21b5ad508c5faf96c4a1f9d732449cc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 17 Feb 2020 17:50:22 +0000 Subject: Move hir and resolve into a module --- dhall/src/semantics/hir.rs | 130 ---------------- dhall/src/semantics/mod.rs | 2 - dhall/src/semantics/resolve.rs | 264 --------------------------------- dhall/src/semantics/resolve/env.rs | 0 dhall/src/semantics/resolve/hir.rs | 130 ++++++++++++++++ dhall/src/semantics/resolve/mod.rs | 6 + dhall/src/semantics/resolve/resolve.rs | 264 +++++++++++++++++++++++++++++++++ 7 files changed, 400 insertions(+), 396 deletions(-) delete mode 100644 dhall/src/semantics/hir.rs delete mode 100644 dhall/src/semantics/resolve.rs create mode 100644 dhall/src/semantics/resolve/env.rs create mode 100644 dhall/src/semantics/resolve/hir.rs create mode 100644 dhall/src/semantics/resolve/mod.rs create mode 100644 dhall/src/semantics/resolve/resolve.rs (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs deleted file mode 100644 index b5db66f..0000000 --- a/dhall/src/semantics/hir.rs +++ /dev/null @@ -1,130 +0,0 @@ -use crate::error::TypeError; -use crate::semantics::{type_with, NameEnv, NzEnv, TyEnv, TyExpr, Value}; -use crate::syntax::{Expr, ExprKind, Span, V}; -use crate::{NormalizedExpr, ToExprOptions}; - -/// Stores an alpha-normalized variable. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct AlphaVar { - idx: usize, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) enum HirKind { - /// A resolved variable (i.e. a DeBruijn index) - Var(AlphaVar), - // Forbidden ExprKind variants: Var, Import, Completion - Expr(ExprKind), -} - -// An expression with resolved variables and imports. -#[derive(Debug, Clone)] -pub(crate) struct Hir { - kind: Box, - span: Span, -} - -impl AlphaVar { - pub(crate) fn new(idx: usize) -> Self { - AlphaVar { idx } - } - pub(crate) fn idx(&self) -> usize { - self.idx - } -} - -impl Hir { - pub fn new(kind: HirKind, span: Span) -> Self { - Hir { - kind: Box::new(kind), - span, - } - } - - pub fn kind(&self) -> &HirKind { - &*self.kind - } - pub fn span(&self) -> Span { - self.span.clone() - } - - /// Converts a HIR expr back to the corresponding AST expression. - pub fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { - hir_to_expr(self, opts, &mut NameEnv::new()) - } - /// Converts a HIR expr back to the corresponding AST expression. - pub fn to_expr_noopts(&self) -> NormalizedExpr { - let opts = ToExprOptions { - normalize: false, - alpha: false, - }; - self.to_expr(opts) - } - pub fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { - let opts = ToExprOptions { - normalize: true, - alpha: false, - }; - let mut env = env.as_nameenv().clone(); - hir_to_expr(self, opts, &mut env) - } - - /// Typecheck the Hir. - pub fn typecheck(&self, env: &TyEnv) -> Result { - type_with(env, self, None) - } - - /// Eval the Hir. It will actually get evaluated only as needed on demand. - pub fn eval(&self, env: impl Into) -> Value { - Value::new_thunk(env.into(), self.clone()) - } -} - -fn hir_to_expr( - hir: &Hir, - opts: ToExprOptions, - env: &mut NameEnv, -) -> NormalizedExpr { - let kind = match hir.kind() { - HirKind::Var(v) if opts.alpha => ExprKind::Var(V("_".into(), v.idx())), - HirKind::Var(v) => ExprKind::Var(env.label_var(v)), - HirKind::Expr(e) => { - let e = e.map_ref_maybe_binder(|l, hir| { - if let Some(l) = l { - env.insert_mut(l); - } - let e = hir_to_expr(hir, opts, env); - if let Some(_) = l { - env.remove_mut(); - } - e - }); - - match e { - ExprKind::Lam(_, t, e) if opts.alpha => { - ExprKind::Lam("_".into(), t, e) - } - ExprKind::Pi(_, t, e) if opts.alpha => { - ExprKind::Pi("_".into(), t, e) - } - e => e, - } - } - }; - Expr::new(kind, hir.span()) -} - -impl std::cmp::PartialEq for Hir { - fn eq(&self, other: &Self) -> bool { - self.kind == other.kind - } -} -impl std::cmp::Eq for Hir {} -impl std::hash::Hash for Hir { - fn hash(&self, state: &mut H) - where - H: std::hash::Hasher, - { - self.kind.hash(state) - } -} diff --git a/dhall/src/semantics/mod.rs b/dhall/src/semantics/mod.rs index ffa16ca..87033c9 100644 --- a/dhall/src/semantics/mod.rs +++ b/dhall/src/semantics/mod.rs @@ -1,11 +1,9 @@ pub mod builtins; -pub mod hir; pub mod nze; pub mod parse; pub mod resolve; pub mod tck; pub(crate) use self::builtins::*; -pub(crate) use self::hir::*; pub(crate) use self::nze::*; pub(crate) use self::resolve::*; pub(crate) use self::tck::*; diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs deleted file mode 100644 index 3038597..0000000 --- a/dhall/src/semantics/resolve.rs +++ /dev/null @@ -1,264 +0,0 @@ -use std::collections::HashMap; -use std::path::{Path, PathBuf}; - -use crate::error::ErrorBuilder; -use crate::error::{Error, ImportError}; -use crate::semantics::{mkerr, Hir, HirKind, NameEnv}; -use crate::syntax; -use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; -use crate::{Parsed, ParsedExpr, Resolved}; - -type Import = syntax::Import; - -/// A root from which to resolve relative imports. -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum ImportRoot { - LocalDir(PathBuf), -} - -type ImportCache = HashMap; - -pub(crate) type ImportStack = Vec; - -struct ResolveEnv { - cache: ImportCache, - stack: ImportStack, -} - -impl ResolveEnv { - pub fn new() -> Self { - ResolveEnv { - cache: HashMap::new(), - stack: Vec::new(), - } - } - - pub fn handle_import( - &mut self, - import: Import, - mut do_resolve: impl FnMut(&mut Self, &Import) -> Result, - ) -> Result { - if self.stack.contains(&import) { - return Err( - ImportError::ImportCycle(self.stack.clone(), import).into() - ); - } - Ok(match self.cache.get(&import) { - Some(expr) => expr.clone(), - None => { - // Push the current import on the stack - self.stack.push(import.clone()); - - // Resolve the import recursively - let expr = do_resolve(self, &import)?; - - // Remove import from the stack. - self.stack.pop(); - - // Add the import to the cache - self.cache.insert(import, expr.clone()); - - expr - } - }) - } -} - -fn resolve_one_import( - env: &mut ResolveEnv, - import: &Import, - root: &ImportRoot, -) -> Result { - use self::ImportRoot::*; - use syntax::FilePrefix::*; - use syntax::ImportLocation::*; - let cwd = match root { - LocalDir(cwd) => cwd, - }; - match &import.location { - Local(prefix, path) => { - let path_buf: PathBuf = path.file_path.iter().collect(); - let path_buf = match prefix { - // TODO: fail gracefully - Parent => cwd.parent().unwrap().join(path_buf), - Here => cwd.join(path_buf), - _ => unimplemented!("{:?}", import), - }; - Ok(load_import(env, &path_buf)?) - } - _ => unimplemented!("{:?}", import), - } -} - -fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { - let parsed = Parsed::parse_file(f)?; - Ok(resolve_with_env(env, parsed)? - .typecheck()? - .normalize() - .to_hir()) -} - -/// Traverse the expression, handling import alternatives and passing -/// found imports to the provided function. -fn traverse_resolve_expr( - name_env: &mut NameEnv, - expr: &Expr, - f: &mut impl FnMut(Import) -> Result, -) -> Result { - Ok(match expr.kind() { - ExprKind::Var(var) => match name_env.unlabel_var(&var) { - Some(v) => Hir::new(HirKind::Var(v), expr.span()), - None => mkerr( - ErrorBuilder::new(format!("unbound variable `{}`", var)) - .span_err(expr.span(), "not found in this scope") - .format(), - )?, - }, - ExprKind::BinOp(BinOp::ImportAlt, l, r) => { - match traverse_resolve_expr(name_env, l, f) { - Ok(l) => l, - Err(_) => { - match traverse_resolve_expr(name_env, r, f) { - Ok(r) => r, - // TODO: keep track of the other error too - Err(e) => return Err(e), - } - } - } - } - // Desugar - ExprKind::Completion(ty, compl) => { - let ty_field_default = Expr::new( - ExprKind::Field(ty.clone(), "default".into()), - expr.span(), - ); - let merged = Expr::new( - ExprKind::BinOp( - BinOp::RightBiasedRecordMerge, - ty_field_default, - compl.clone(), - ), - expr.span(), - ); - let ty_field_type = Expr::new( - ExprKind::Field(ty.clone(), "Type".into()), - expr.span(), - ); - let desugared = - Expr::new(ExprKind::Annot(merged, ty_field_type), expr.span()); - traverse_resolve_expr(name_env, &desugared, f)? - } - kind => { - let kind = kind.traverse_ref_maybe_binder(|l, e| { - if let Some(l) = l { - name_env.insert_mut(l); - } - let hir = traverse_resolve_expr(name_env, e, f)?; - if let Some(_) = l { - name_env.remove_mut(); - } - Ok::<_, Error>(hir) - })?; - let kind = match kind { - ExprKind::Import(import) => f(import)?.kind().clone(), - kind => HirKind::Expr(kind), - }; - Hir::new(kind, expr.span()) - } - }) -} - -fn resolve_with_env( - env: &mut ResolveEnv, - parsed: Parsed, -) -> Result { - let Parsed(expr, root) = parsed; - let resolved = - traverse_resolve_expr(&mut NameEnv::new(), &expr, &mut |import| { - env.handle_import(import, |env, import| { - resolve_one_import(env, import, &root) - }) - })?; - Ok(Resolved(resolved)) -} - -pub(crate) fn resolve(parsed: Parsed) -> Result { - resolve_with_env(&mut ResolveEnv::new(), parsed) -} - -pub(crate) fn skip_resolve(expr: &ParsedExpr) -> Result { - traverse_resolve_expr(&mut NameEnv::new(), expr, &mut |import| { - Err(ImportError::UnexpectedImport(import).into()) - }) -} - -pub trait Canonicalize { - fn canonicalize(&self) -> Self; -} - -impl Canonicalize for FilePath { - fn canonicalize(&self) -> FilePath { - let mut file_path = Vec::new(); - let mut file_path_components = self.file_path.clone().into_iter(); - - loop { - let component = file_path_components.next(); - match component.as_ref() { - // ─────────────────── - // canonicalize(ε) = ε - None => break, - - // canonicalize(directory₀) = directory₁ - // ─────────────────────────────────────── - // canonicalize(directory₀/.) = directory₁ - Some(c) if c == "." => continue, - - Some(c) if c == ".." => match file_path_components.next() { - // canonicalize(directory₀) = ε - // ──────────────────────────── - // canonicalize(directory₀/..) = /.. - None => file_path.push("..".to_string()), - - // canonicalize(directory₀) = directory₁/.. - // ────────────────────────────────────────────── - // canonicalize(directory₀/..) = directory₁/../.. - Some(ref c) if c == ".." => { - file_path.push("..".to_string()); - file_path.push("..".to_string()); - } - - // canonicalize(directory₀) = directory₁/component - // ─────────────────────────────────────────────── ; If "component" is not - // canonicalize(directory₀/..) = directory₁ ; ".." - Some(_) => continue, - }, - - // canonicalize(directory₀) = directory₁ - // ───────────────────────────────────────────────────────── ; If no other - // canonicalize(directory₀/component) = directory₁/component ; rule matches - Some(c) => file_path.push(c.clone()), - } - } - - FilePath { file_path } - } -} - -impl Canonicalize for ImportLocation { - fn canonicalize(&self) -> ImportLocation { - match self { - ImportLocation::Local(prefix, file) => { - ImportLocation::Local(*prefix, file.canonicalize()) - } - ImportLocation::Remote(url) => ImportLocation::Remote(URL { - scheme: url.scheme, - authority: url.authority.clone(), - path: url.path.canonicalize(), - query: url.query.clone(), - headers: url.headers.clone(), - }), - ImportLocation::Env(name) => ImportLocation::Env(name.to_string()), - ImportLocation::Missing => ImportLocation::Missing, - } - } -} diff --git a/dhall/src/semantics/resolve/env.rs b/dhall/src/semantics/resolve/env.rs new file mode 100644 index 0000000..e69de29 diff --git a/dhall/src/semantics/resolve/hir.rs b/dhall/src/semantics/resolve/hir.rs new file mode 100644 index 0000000..b5db66f --- /dev/null +++ b/dhall/src/semantics/resolve/hir.rs @@ -0,0 +1,130 @@ +use crate::error::TypeError; +use crate::semantics::{type_with, NameEnv, NzEnv, TyEnv, TyExpr, Value}; +use crate::syntax::{Expr, ExprKind, Span, V}; +use crate::{NormalizedExpr, ToExprOptions}; + +/// Stores an alpha-normalized variable. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct AlphaVar { + idx: usize, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) enum HirKind { + /// A resolved variable (i.e. a DeBruijn index) + Var(AlphaVar), + // Forbidden ExprKind variants: Var, Import, Completion + Expr(ExprKind), +} + +// An expression with resolved variables and imports. +#[derive(Debug, Clone)] +pub(crate) struct Hir { + kind: Box, + span: Span, +} + +impl AlphaVar { + pub(crate) fn new(idx: usize) -> Self { + AlphaVar { idx } + } + pub(crate) fn idx(&self) -> usize { + self.idx + } +} + +impl Hir { + pub fn new(kind: HirKind, span: Span) -> Self { + Hir { + kind: Box::new(kind), + span, + } + } + + pub fn kind(&self) -> &HirKind { + &*self.kind + } + pub fn span(&self) -> Span { + self.span.clone() + } + + /// Converts a HIR expr back to the corresponding AST expression. + pub fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { + hir_to_expr(self, opts, &mut NameEnv::new()) + } + /// Converts a HIR expr back to the corresponding AST expression. + pub fn to_expr_noopts(&self) -> NormalizedExpr { + let opts = ToExprOptions { + normalize: false, + alpha: false, + }; + self.to_expr(opts) + } + pub fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { + let opts = ToExprOptions { + normalize: true, + alpha: false, + }; + let mut env = env.as_nameenv().clone(); + hir_to_expr(self, opts, &mut env) + } + + /// Typecheck the Hir. + pub fn typecheck(&self, env: &TyEnv) -> Result { + type_with(env, self, None) + } + + /// Eval the Hir. It will actually get evaluated only as needed on demand. + pub fn eval(&self, env: impl Into) -> Value { + Value::new_thunk(env.into(), self.clone()) + } +} + +fn hir_to_expr( + hir: &Hir, + opts: ToExprOptions, + env: &mut NameEnv, +) -> NormalizedExpr { + let kind = match hir.kind() { + HirKind::Var(v) if opts.alpha => ExprKind::Var(V("_".into(), v.idx())), + HirKind::Var(v) => ExprKind::Var(env.label_var(v)), + HirKind::Expr(e) => { + let e = e.map_ref_maybe_binder(|l, hir| { + if let Some(l) = l { + env.insert_mut(l); + } + let e = hir_to_expr(hir, opts, env); + if let Some(_) = l { + env.remove_mut(); + } + e + }); + + match e { + ExprKind::Lam(_, t, e) if opts.alpha => { + ExprKind::Lam("_".into(), t, e) + } + ExprKind::Pi(_, t, e) if opts.alpha => { + ExprKind::Pi("_".into(), t, e) + } + e => e, + } + } + }; + Expr::new(kind, hir.span()) +} + +impl std::cmp::PartialEq for Hir { + fn eq(&self, other: &Self) -> bool { + self.kind == other.kind + } +} +impl std::cmp::Eq for Hir {} +impl std::hash::Hash for Hir { + fn hash(&self, state: &mut H) + where + H: std::hash::Hasher, + { + self.kind.hash(state) + } +} diff --git a/dhall/src/semantics/resolve/mod.rs b/dhall/src/semantics/resolve/mod.rs new file mode 100644 index 0000000..c0486dd --- /dev/null +++ b/dhall/src/semantics/resolve/mod.rs @@ -0,0 +1,6 @@ +pub mod env; +pub mod resolve; +pub mod hir; +pub(crate) use env::*; +pub(crate) use resolve::*; +pub(crate) use hir::*; diff --git a/dhall/src/semantics/resolve/resolve.rs b/dhall/src/semantics/resolve/resolve.rs new file mode 100644 index 0000000..3038597 --- /dev/null +++ b/dhall/src/semantics/resolve/resolve.rs @@ -0,0 +1,264 @@ +use std::collections::HashMap; +use std::path::{Path, PathBuf}; + +use crate::error::ErrorBuilder; +use crate::error::{Error, ImportError}; +use crate::semantics::{mkerr, Hir, HirKind, NameEnv}; +use crate::syntax; +use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; +use crate::{Parsed, ParsedExpr, Resolved}; + +type Import = syntax::Import; + +/// A root from which to resolve relative imports. +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum ImportRoot { + LocalDir(PathBuf), +} + +type ImportCache = HashMap; + +pub(crate) type ImportStack = Vec; + +struct ResolveEnv { + cache: ImportCache, + stack: ImportStack, +} + +impl ResolveEnv { + pub fn new() -> Self { + ResolveEnv { + cache: HashMap::new(), + stack: Vec::new(), + } + } + + pub fn handle_import( + &mut self, + import: Import, + mut do_resolve: impl FnMut(&mut Self, &Import) -> Result, + ) -> Result { + if self.stack.contains(&import) { + return Err( + ImportError::ImportCycle(self.stack.clone(), import).into() + ); + } + Ok(match self.cache.get(&import) { + Some(expr) => expr.clone(), + None => { + // Push the current import on the stack + self.stack.push(import.clone()); + + // Resolve the import recursively + let expr = do_resolve(self, &import)?; + + // Remove import from the stack. + self.stack.pop(); + + // Add the import to the cache + self.cache.insert(import, expr.clone()); + + expr + } + }) + } +} + +fn resolve_one_import( + env: &mut ResolveEnv, + import: &Import, + root: &ImportRoot, +) -> Result { + use self::ImportRoot::*; + use syntax::FilePrefix::*; + use syntax::ImportLocation::*; + let cwd = match root { + LocalDir(cwd) => cwd, + }; + match &import.location { + Local(prefix, path) => { + let path_buf: PathBuf = path.file_path.iter().collect(); + let path_buf = match prefix { + // TODO: fail gracefully + Parent => cwd.parent().unwrap().join(path_buf), + Here => cwd.join(path_buf), + _ => unimplemented!("{:?}", import), + }; + Ok(load_import(env, &path_buf)?) + } + _ => unimplemented!("{:?}", import), + } +} + +fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { + let parsed = Parsed::parse_file(f)?; + Ok(resolve_with_env(env, parsed)? + .typecheck()? + .normalize() + .to_hir()) +} + +/// Traverse the expression, handling import alternatives and passing +/// found imports to the provided function. +fn traverse_resolve_expr( + name_env: &mut NameEnv, + expr: &Expr, + f: &mut impl FnMut(Import) -> Result, +) -> Result { + Ok(match expr.kind() { + ExprKind::Var(var) => match name_env.unlabel_var(&var) { + Some(v) => Hir::new(HirKind::Var(v), expr.span()), + None => mkerr( + ErrorBuilder::new(format!("unbound variable `{}`", var)) + .span_err(expr.span(), "not found in this scope") + .format(), + )?, + }, + ExprKind::BinOp(BinOp::ImportAlt, l, r) => { + match traverse_resolve_expr(name_env, l, f) { + Ok(l) => l, + Err(_) => { + match traverse_resolve_expr(name_env, r, f) { + Ok(r) => r, + // TODO: keep track of the other error too + Err(e) => return Err(e), + } + } + } + } + // Desugar + ExprKind::Completion(ty, compl) => { + let ty_field_default = Expr::new( + ExprKind::Field(ty.clone(), "default".into()), + expr.span(), + ); + let merged = Expr::new( + ExprKind::BinOp( + BinOp::RightBiasedRecordMerge, + ty_field_default, + compl.clone(), + ), + expr.span(), + ); + let ty_field_type = Expr::new( + ExprKind::Field(ty.clone(), "Type".into()), + expr.span(), + ); + let desugared = + Expr::new(ExprKind::Annot(merged, ty_field_type), expr.span()); + traverse_resolve_expr(name_env, &desugared, f)? + } + kind => { + let kind = kind.traverse_ref_maybe_binder(|l, e| { + if let Some(l) = l { + name_env.insert_mut(l); + } + let hir = traverse_resolve_expr(name_env, e, f)?; + if let Some(_) = l { + name_env.remove_mut(); + } + Ok::<_, Error>(hir) + })?; + let kind = match kind { + ExprKind::Import(import) => f(import)?.kind().clone(), + kind => HirKind::Expr(kind), + }; + Hir::new(kind, expr.span()) + } + }) +} + +fn resolve_with_env( + env: &mut ResolveEnv, + parsed: Parsed, +) -> Result { + let Parsed(expr, root) = parsed; + let resolved = + traverse_resolve_expr(&mut NameEnv::new(), &expr, &mut |import| { + env.handle_import(import, |env, import| { + resolve_one_import(env, import, &root) + }) + })?; + Ok(Resolved(resolved)) +} + +pub(crate) fn resolve(parsed: Parsed) -> Result { + resolve_with_env(&mut ResolveEnv::new(), parsed) +} + +pub(crate) fn skip_resolve(expr: &ParsedExpr) -> Result { + traverse_resolve_expr(&mut NameEnv::new(), expr, &mut |import| { + Err(ImportError::UnexpectedImport(import).into()) + }) +} + +pub trait Canonicalize { + fn canonicalize(&self) -> Self; +} + +impl Canonicalize for FilePath { + fn canonicalize(&self) -> FilePath { + let mut file_path = Vec::new(); + let mut file_path_components = self.file_path.clone().into_iter(); + + loop { + let component = file_path_components.next(); + match component.as_ref() { + // ─────────────────── + // canonicalize(ε) = ε + None => break, + + // canonicalize(directory₀) = directory₁ + // ─────────────────────────────────────── + // canonicalize(directory₀/.) = directory₁ + Some(c) if c == "." => continue, + + Some(c) if c == ".." => match file_path_components.next() { + // canonicalize(directory₀) = ε + // ──────────────────────────── + // canonicalize(directory₀/..) = /.. + None => file_path.push("..".to_string()), + + // canonicalize(directory₀) = directory₁/.. + // ────────────────────────────────────────────── + // canonicalize(directory₀/..) = directory₁/../.. + Some(ref c) if c == ".." => { + file_path.push("..".to_string()); + file_path.push("..".to_string()); + } + + // canonicalize(directory₀) = directory₁/component + // ─────────────────────────────────────────────── ; If "component" is not + // canonicalize(directory₀/..) = directory₁ ; ".." + Some(_) => continue, + }, + + // canonicalize(directory₀) = directory₁ + // ───────────────────────────────────────────────────────── ; If no other + // canonicalize(directory₀/component) = directory₁/component ; rule matches + Some(c) => file_path.push(c.clone()), + } + } + + FilePath { file_path } + } +} + +impl Canonicalize for ImportLocation { + fn canonicalize(&self) -> ImportLocation { + match self { + ImportLocation::Local(prefix, file) => { + ImportLocation::Local(*prefix, file.canonicalize()) + } + ImportLocation::Remote(url) => ImportLocation::Remote(URL { + scheme: url.scheme, + authority: url.authority.clone(), + path: url.path.canonicalize(), + query: url.query.clone(), + headers: url.headers.clone(), + }), + ImportLocation::Env(name) => ImportLocation::Env(name.to_string()), + ImportLocation::Missing => ImportLocation::Missing, + } + } +} -- cgit v1.2.3 From 8da4445e6d06cf79d43112042b69c798f86884f3 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 17 Feb 2020 17:58:03 +0000 Subject: Extract resolve-relevant envs together --- dhall/src/semantics/resolve/env.rs | 104 +++++++++++++++++++++++++++++++++ dhall/src/semantics/resolve/mod.rs | 4 +- dhall/src/semantics/resolve/resolve.rs | 63 +++----------------- dhall/src/semantics/tck/env.rs | 59 ++----------------- 4 files changed, 118 insertions(+), 112 deletions(-) (limited to 'dhall/src/semantics') diff --git a/dhall/src/semantics/resolve/env.rs b/dhall/src/semantics/resolve/env.rs index e69de29..ff743d3 100644 --- a/dhall/src/semantics/resolve/env.rs +++ b/dhall/src/semantics/resolve/env.rs @@ -0,0 +1,104 @@ +use std::collections::HashMap; + +use crate::error::{Error, ImportError}; +use crate::semantics::{AlphaVar, Hir, Import, VarEnv}; +use crate::syntax::{Label, V}; + +/// Environment for resolving names. +#[derive(Debug, Clone)] +pub(crate) struct NameEnv { + names: Vec