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/tck/tyexpr.rs | 117 +++++++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 19 deletions(-) (limited to 'dhall/src/semantics/tck/tyexpr.rs') 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. -- cgit v1.2.3