summaryrefslogtreecommitdiff
path: root/dhall/src/semantics/tck/tyexpr.rs
diff options
context:
space:
mode:
authorNadrieril2020-02-16 19:06:23 +0000
committerNadrieril2020-02-16 19:49:44 +0000
commit130de8cea49c848a06174c61c747d9414a5c71b7 (patch)
tree201ee2cdb8725e1bdc8e8fcdf3c7c6bcce2063f4 /dhall/src/semantics/tck/tyexpr.rs
parentaa867b21f57f9bef2ec2b9d8450736f9111189ee (diff)
Start requiring Universe to build a Type
Diffstat (limited to '')
-rw-r--r--dhall/src/semantics/tck/tyexpr.rs117
1 files changed, 98 insertions, 19 deletions
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<Const> {
+ 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<Self> {
+ 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<Option<Const>, 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<Universe, TypeError> {
+ 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<Option<Const>, 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<NzEnv>) -> 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<NzEnv>) -> Type {
- self.eval(env).into()
+ pub fn eval_to_type(&self, env: &TyEnv) -> Result<Type, TypeError> {
+ 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.