#![allow(non_snake_case)] use std::borrow::Borrow; use std::borrow::Cow; use std::fmt; use std::marker::PhantomData; use crate::expr::*; use crate::traits::DynamicType; use dhall_core; use dhall_core::context::Context; use dhall_core::*; use dhall_generator as dhall; use self::TypeMessage::*; impl<'a> Resolved<'a> { pub fn typecheck(self) -> Result, TypeError> { type_of(self.0.unnote()) } pub fn typecheck_with( self, ty: &Type, ) -> Result, TypeError> { let expr: SubExpr<_, _> = self.0.unnote(); let ty: SubExpr<_, _> = ty.clone().unnote().embed()?; type_of(dhall::subexpr!(expr: ty)) } /// Pretends this expression has been typechecked. Use with care. #[allow(dead_code)] pub fn skip_typecheck(self) -> Typed<'a> { Typed(self.0.unnote(), None, TypecheckContext::new(), PhantomData) } } impl<'a> Typed<'a> { fn normalize_to_type( self, ctx: &TypecheckContext, ) -> Result, TypeError> { Ok(self.normalize().into_type_ctx(ctx)?) } fn get_type_move(self) -> Result, TypeError> { let (expr, ty) = (self.0, self.1); ty.ok_or_else(|| { TypeError::new(&TypecheckContext::new(), expr, TypeMessage::Untyped) }) } } impl<'a> Normalized<'a> { // Expose the outermost constructor fn unroll_ref(&self) -> &Expr { self.as_expr().as_ref() } fn shift0(&self, delta: isize, label: &Label) -> Self { Normalized( shift0(delta, label, &self.0), self.1.as_ref().map(|t| t.shift0(delta, label)), self.2, ) } pub(crate) fn into_type(self) -> Result, TypeError> { self.into_type_ctx(&TypecheckContext::new()) } pub(crate) fn into_type_ctx( self, ctx: &TypecheckContext, ) -> Result, TypeError> { Ok(Type(match self.0.as_ref() { ExprF::Const(c) => TypeInternal::Const(*c), ExprF::Pi(_, _, _) => { return Ok(type_with(ctx, self.0.embed_absurd())? .normalize_to_type(ctx)?) } _ => TypeInternal::Expr(Box::new(self)), })) } fn get_type_move(self) -> Result, TypeError> { let (expr, ty) = (self.0, self.1); ty.ok_or_else(|| { TypeError::new( &TypecheckContext::new(), expr.embed_absurd(), TypeMessage::Untyped, ) }) } } impl Normalized<'static> { fn embed(self) -> SubExpr> { rc(ExprF::Embed(self)) } } impl<'a> Type<'a> { pub(crate) fn as_normalized( &self, ) -> Result>, TypeError> { Ok(Cow::Owned(self.0.clone().into_normalized()?)) // match &self.0 { // TypeInternal::Expr(e) => Ok(Cow::Borrowed(e)), // TypeInternal::Const(c) => Ok(Cow::Owned(const_to_normalized(*c))), // TypeInternal::SuperType => Err(TypeError::new( // &TypecheckContext::new(), // rc(ExprF::Const(Const::Sort)), // TypeMessage::Untyped, // )), // } } pub(crate) fn into_normalized(self) -> Result, TypeError> { self.0.into_normalized() } // Expose the outermost constructor fn unroll_ref(&self) -> Result>, TypeError> { match self.as_normalized()? { Cow::Borrowed(e) => Ok(Cow::Borrowed(e.unroll_ref())), Cow::Owned(e) => Ok(Cow::Owned(e.into_expr().unroll())), } } fn internal(&self) -> &TypeInternal { &self.0 } fn shift0(&self, delta: isize, label: &Label) -> Self { use TypeInternal::*; Type(match &self.0 { Expr(e) => Expr(Box::new(e.shift0(delta, label))), Pi(ctx, c, x, t, e) => Pi( ctx.clone(), *c, x.clone(), Box::new(t.shift0(delta, label)), Box::new(e.shift0(delta, label)), ), Const(c) => Const(*c), SuperType => SuperType, }) } fn const_sort() -> Self { Type(TypeInternal::Const(Const::Sort)) } fn const_kind() -> Self { Type(TypeInternal::Const(Const::Kind)) } pub(crate) fn const_type() -> Self { Type(TypeInternal::Const(Const::Type)) } } impl Type<'static> { fn embed(self) -> Result>, TypeError> { Ok(self.into_normalized()?.embed()) } } /// A semantic type. This is partially redundant with `dhall_core::Expr`, on purpose. `TypeInternal` should /// be limited to syntactic expressions: either written by the user or meant to be printed. /// The rule is the following: we must _not_ construct values of type `Expr` while typechecking, /// but only construct `TypeInternal`s. #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum TypeInternal<'a> { Const(Const), Pi( TypecheckContext, Const, Label, Box>, Box>, ), /// The type of `Sort` SuperType, /// This must not contain a value captured by one of the variants above. Expr(Box>), } impl<'a> TypeInternal<'a> { pub(crate) fn into_normalized(self) -> Result, TypeError> { match self { TypeInternal::Expr(e) => Ok(*e), TypeInternal::Pi(ctx, c, x, t, e) => Ok(Typed( rc(ExprF::Pi( x, t.into_normalized()?.embed(), e.into_normalized()?.embed(), )), Some(const_to_type(c)), ctx, PhantomData, ) .normalize()), TypeInternal::Const(c) => Ok(const_to_normalized(c)), TypeInternal::SuperType => Err(TypeError::new( &TypecheckContext::new(), rc(ExprF::Const(Const::Sort)), TypeMessage::Untyped, )), } } } #[derive(Debug, Clone)] pub(crate) enum TypedImproved { Pi(TypecheckContext, Const, Label, Type<'static>, Type<'static>), Expr(Typed<'static>), } impl TypedImproved { fn into_typed(self) -> Result, TypeError> { match self { TypedImproved::Pi(ctx, c, x, t, e) => Ok(Typed( rc(ExprF::Pi( x, t.into_normalized()?.embed(), e.into_normalized()?.embed(), )), Some(const_to_type(c)), ctx, PhantomData, )), TypedImproved::Expr(e) => Ok(e), } } fn normalize_to_type( self, ctx: &TypecheckContext, ) -> Result, TypeError> { match self { TypedImproved::Expr(e) => Ok(e.normalize_to_type(ctx)?), // TypedImproved::Pi(ctx, c, x, t, e) => Ok(Typed( // rc(ExprF::Pi( // x, // t.into_normalized()?.embed(), // e.into_normalized()?.embed(), // )), // Some(const_to_type(c)), // ctx, // PhantomData, // ) // .normalize() // .into_type()?), TypedImproved::Pi(ctx, c, x, t, e) => { Ok(Type(TypeInternal::Pi(ctx, c, x, Box::new(t), Box::new(e)))) } } // Ok(self.into_typed()?.normalize_to_type()) } fn get_type(&self) -> Result>, TypeError> { Ok(Cow::Owned(self.clone().get_type_move()?)) } fn get_type_move(self) -> Result, TypeError> { Ok(self.into_typed()?.get_type_move()?) } fn normalize(self) -> Result, TypeError> { Ok(self.into_typed()?.normalize()) } } #[derive(Debug, Clone)] pub(crate) enum EnvItem { Type(V