summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadrieril2019-04-10 19:16:11 +0200
committerNadrieril2019-04-10 19:16:11 +0200
commite1a30c6f248c0c17c97598290a0d94993dbb0325 (patch)
tree960eb4029f2ba9a824e34219915e942b1b65e4cd
parent982f86c34f69bb78b45a4b8b37a5bf5731f881eb (diff)
Add SimpleType and SimpeStaticType. Derive the latter
-rw-r--r--dhall/src/expr.rs21
-rw-r--r--dhall/src/lib.rs3
-rw-r--r--dhall/src/traits.rs109
-rw-r--r--dhall/src/typecheck.rs21
-rw-r--r--dhall/tests/traits.rs54
-rw-r--r--dhall_generator/src/derive.rs35
-rw-r--r--dhall_generator/src/lib.rs6
7 files changed, 173 insertions, 76 deletions
diff --git a/dhall/src/expr.rs b/dhall/src/expr.rs
index 7baf628..5ff097b 100644
--- a/dhall/src/expr.rs
+++ b/dhall/src/expr.rs
@@ -36,6 +36,11 @@ derive_other_traits!(Typed);
pub struct Normalized(pub(crate) SubExpr<X, X>, pub(crate) Type);
derive_other_traits!(Normalized);
+/// An expression of type `Type` (like `Bool` or `Natural -> Text`, but not `Type`)
+#[derive(Debug, Clone, Eq)]
+pub struct SimpleType(pub(crate) SubExpr<X, X>);
+derive_other_traits!(SimpleType);
+
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Type(pub(crate) TypeInternal);
@@ -44,3 +49,19 @@ pub(crate) enum TypeInternal {
Expr(Box<Normalized>),
Untyped,
}
+
+// Exposed for the macros
+#[doc(hidden)]
+impl From<SimpleType> for SubExpr<X, X> {
+ fn from(x: SimpleType) -> SubExpr<X, X> {
+ x.0
+ }
+}
+
+// Exposed for the macros
+#[doc(hidden)]
+impl From<SubExpr<X, X>> for SimpleType {
+ fn from(x: SubExpr<X, X>) -> SimpleType {
+ SimpleType(x)
+ }
+}
diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs
index 5c5a641..3bfc46f 100644
--- a/dhall/src/lib.rs
+++ b/dhall/src/lib.rs
@@ -21,6 +21,7 @@ mod imports;
mod normalize;
mod traits;
mod typecheck;
+pub use crate::traits::SimpleStaticType;
pub use crate::traits::StaticType;
-pub use dhall_generator::StaticType;
+pub use dhall_generator::SimpleStaticType;
pub mod expr;
diff --git a/dhall/src/traits.rs b/dhall/src/traits.rs
index 64e07d9..4925457 100644
--- a/dhall/src/traits.rs
+++ b/dhall/src/traits.rs
@@ -1,77 +1,108 @@
+use crate::expr::*;
use dhall_core::*;
use dhall_generator::*;
+use std::borrow::Cow;
#[derive(Debug, Clone)]
pub enum ConversionError {}
pub trait StaticType {
- fn get_type() -> DhallExpr;
- // fn as_dhall(&self) -> DhallExpr;
- // fn from_dhall(e: DhallExpr) -> Result<Self, DhallConversionError>;
+ fn get_static_type() -> Type;
}
-impl StaticType for bool {
- fn get_type() -> DhallExpr {
- dhall_expr!(Bool)
+/// Trait for rust types that can be represented in dhall in
+/// a single way, independent of the value. A typical example is `Option<bool>`,
+/// represented by the dhall expression `Optional Bool`. A typical counterexample
+/// is `HashMap<Text, bool>` because dhall cannot represent records with a
+/// variable number of fields.
+pub trait SimpleStaticType {
+ fn get_simple_static_type() -> SimpleType;
+}
+
+fn mktype(x: SubExpr<X, X>) -> SimpleType {
+ SimpleType(x)
+}
+
+impl<T: SimpleStaticType> StaticType for T {
+ fn get_static_type() -> Type {
+ crate::expr::Normalized(
+ T::get_simple_static_type().into(),
+ Type::const_type(),
+ )
+ .into_type()
+ }
+}
+
+impl StaticType for SimpleType {
+ fn get_static_type() -> Type {
+ Type::const_type()
+ }
+}
+
+impl SimpleStaticType for bool {
+ fn get_simple_static_type() -> SimpleType {
+ mktype(dhall_expr!(Bool))
}
}
-impl StaticType for Natural {
- fn get_type() -> DhallExpr {
- dhall_expr!(Natural)
+impl SimpleStaticType for Natural {
+ fn get_simple_static_type() -> SimpleType {
+ mktype(dhall_expr!(Natural))
}
}
-impl StaticType for Integer {
- fn get_type() -> DhallExpr {
- dhall_expr!(Integer)
+impl SimpleStaticType for Integer {
+ fn get_simple_static_type() -> SimpleType {
+ mktype(dhall_expr!(Integer))
}
}
-impl StaticType for String {
- fn get_type() -> DhallExpr {
- dhall_expr!(Text)
+impl SimpleStaticType for String {
+ fn get_simple_static_type() -> SimpleType {
+ mktype(dhall_expr!(Text))
}
}
-impl<A: StaticType, B: StaticType> StaticType for (A, B) {
- fn get_type() -> DhallExpr {
- let ta = A::get_type();
- let tb = B::get_type();
- dhall_expr!({ _1: ta, _2: tb })
+impl<A: SimpleStaticType, B: SimpleStaticType> SimpleStaticType for (A, B) {
+ fn get_simple_static_type() -> SimpleType {
+ let ta: SubExpr<_, _> = A::get_simple_static_type().into();
+ let tb: SubExpr<_, _> = B::get_simple_static_type().into();
+ mktype(dhall_expr!({ _1: ta, _2: tb }))
}
}
-impl<T: StaticType> StaticType for Option<T> {
- fn get_type() -> DhallExpr {
- let t = T::get_type();
- dhall_expr!(Optional t)
+impl<T: SimpleStaticType> SimpleStaticType for Option<T> {
+ fn get_simple_static_type() -> SimpleType {
+ let t: SubExpr<_, _> = T::get_simple_static_type().into();
+ mktype(dhall_expr!(Optional t))
}
}
-impl<T: StaticType> StaticType for Vec<T> {
- fn get_type() -> DhallExpr {
- let t = T::get_type();
- dhall_expr!(List t)
+impl<T: SimpleStaticType> SimpleStaticType for Vec<T> {
+ fn get_simple_static_type() -> SimpleType {
+ let t: SubExpr<_, _> = T::get_simple_static_type().into();
+ mktype(dhall_expr!(List t))
}
}
-impl<'a, T: StaticType> StaticType for &'a T {
- fn get_type() -> DhallExpr {
- T::get_type()
+impl<'a, T: SimpleStaticType> SimpleStaticType for &'a T {
+ fn get_simple_static_type() -> SimpleType {
+ T::get_simple_static_type()
}
}
-impl<T> StaticType for std::marker::PhantomData<T> {
- fn get_type() -> DhallExpr {
- dhall_expr!({})
+impl<T> SimpleStaticType for std::marker::PhantomData<T> {
+ fn get_simple_static_type() -> SimpleType {
+ mktype(dhall_expr!({}))
}
}
-impl<T: StaticType, E: StaticType> StaticType for Result<T, E> {
- fn get_type() -> DhallExpr {
- let tt = T::get_type();
- let te = E::get_type();
- dhall_expr!(< Ok: tt | Err: te>)
+impl<T: SimpleStaticType, E: SimpleStaticType> SimpleStaticType
+ for std::result::Result<T, E>
+{
+ fn get_simple_static_type() -> SimpleType {
+ let tt: SubExpr<_, _> = T::get_simple_static_type().into();
+ let te: SubExpr<_, _> = E::get_simple_static_type().into();
+ mktype(dhall_expr!(< Ok: tt | Err: te>))
}
}
diff --git a/dhall/src/typecheck.rs b/dhall/src/typecheck.rs
index 998d3ca..f51f1b6 100644
--- a/dhall/src/typecheck.rs
+++ b/dhall/src/typecheck.rs
@@ -42,7 +42,7 @@ impl Normalized {
&self.0
}
#[inline(always)]
- fn into_expr(self) -> SubExpr<X, X> {
+ pub(crate) fn into_expr(self) -> SubExpr<X, X> {
self.0
}
#[inline(always)]
@@ -50,7 +50,7 @@ impl Normalized {
&self.1
}
#[inline(always)]
- fn into_type(self) -> Type {
+ pub(crate) fn into_type(self) -> Type {
crate::expr::Type(TypeInternal::Expr(Box::new(self)))
}
// Expose the outermost constructor
@@ -78,7 +78,7 @@ impl Type {
}
}
#[inline(always)]
- fn into_normalized(self) -> Result<Normalized, TypeError<X>> {
+ pub(crate) fn into_normalized(self) -> Result<Normalized, TypeError<X>> {
use TypeInternal::*;
match self.0 {
Expr(e) => Ok(*e),
@@ -110,6 +110,21 @@ impl Type {
Untyped => Untyped,
})
}
+
+ #[inline(always)]
+ pub fn const_sort() -> Self {
+ Normalized(rc(ExprF::Const(Const::Sort)), UNTYPE).into_type()
+ }
+ #[inline(always)]
+ pub fn const_kind() -> Self {
+ Normalized(rc(ExprF::Const(Const::Kind)), Type::const_sort())
+ .into_type()
+ }
+ #[inline(always)]
+ pub fn const_type() -> Self {
+ Normalized(rc(ExprF::Const(Const::Type)), Type::const_kind())
+ .into_type()
+ }
}
const UNTYPE: Type = Type(TypeInternal::Untyped);
diff --git a/dhall/tests/traits.rs b/dhall/tests/traits.rs
index ac6b5e6..1e9b3c2 100644
--- a/dhall/tests/traits.rs
+++ b/dhall/tests/traits.rs
@@ -1,53 +1,71 @@
#![feature(proc_macro_hygiene)]
-use dhall::StaticType;
+use dhall::SimpleStaticType;
+use dhall_core::{SubExpr, X};
use dhall_generator::dhall_expr;
#[test]
-fn test_dhall_type() {
- assert_eq!(bool::get_type(), dhall_expr!(Bool));
- assert_eq!(String::get_type(), dhall_expr!(Text));
+fn test_static_type() {
+ fn mktype(x: SubExpr<X, X>) -> dhall::expr::SimpleType {
+ x.into()
+ }
+
+ assert_eq!(bool::get_simple_static_type(), mktype(dhall_expr!(Bool)));
+ assert_eq!(String::get_simple_static_type(), mktype(dhall_expr!(Text)));
assert_eq!(
- <(bool, Option<String>)>::get_type(),
- dhall_expr!({ _1: Bool, _2: Optional Text })
+ <Option<bool>>::get_simple_static_type(),
+ mktype(dhall_expr!(Optional Bool))
+ );
+ assert_eq!(
+ <(bool, Option<String>)>::get_simple_static_type(),
+ mktype(dhall_expr!({ _1: Bool, _2: Optional Text }))
);
- #[derive(dhall::StaticType)]
+ #[derive(dhall::SimpleStaticType)]
#[allow(dead_code)]
struct A {
field1: bool,
field2: Option<bool>,
}
assert_eq!(
- <A as dhall::StaticType>::get_type(),
- dhall_expr!({ field1: Bool, field2: Optional Bool })
+ <A as dhall::SimpleStaticType>::get_simple_static_type(),
+ mktype(dhall_expr!({ field1: Bool, field2: Optional Bool }))
);
- #[derive(StaticType)]
+ #[derive(SimpleStaticType)]
#[allow(dead_code)]
struct B<'a, T: 'a> {
field1: &'a T,
field2: Option<T>,
}
- assert_eq!(<B<'static, bool>>::get_type(), A::get_type());
+ assert_eq!(
+ <B<'static, bool>>::get_simple_static_type(),
+ A::get_simple_static_type()
+ );
- #[derive(StaticType)]
+ #[derive(SimpleStaticType)]
#[allow(dead_code)]
struct C<T>(T, Option<String>);
- assert_eq!(<C<bool>>::get_type(), <(bool, Option<String>)>::get_type());
+ assert_eq!(
+ <C<bool>>::get_simple_static_type(),
+ <(bool, Option<String>)>::get_simple_static_type()
+ );
- #[derive(StaticType)]
+ #[derive(SimpleStaticType)]
#[allow(dead_code)]
struct D();
assert_eq!(
- <C<D>>::get_type(),
- dhall_expr!({ _1: {}, _2: Optional Text })
+ <C<D>>::get_simple_static_type(),
+ mktype(dhall_expr!({ _1: {}, _2: Optional Text }))
);
- #[derive(StaticType)]
+ #[derive(SimpleStaticType)]
#[allow(dead_code)]
enum E<T> {
A(T),
B(String),
};
- assert_eq!(<E<bool>>::get_type(), dhall_expr!(< A: Bool | B: Text >));
+ assert_eq!(
+ <E<bool>>::get_simple_static_type(),
+ mktype(dhall_expr!(< A: Bool | B: Text >))
+ );
}
diff --git a/dhall_generator/src/derive.rs b/dhall_generator/src/derive.rs
index 159ff5c..c911be5 100644
--- a/dhall_generator/src/derive.rs
+++ b/dhall_generator/src/derive.rs
@@ -6,14 +6,23 @@ use syn::spanned::Spanned;
use syn::Error;
use syn::{parse_quote, DeriveInput};
-pub fn derive_type(input: TokenStream) -> TokenStream {
- TokenStream::from(match derive_type_inner(input) {
+pub fn derive_simple_static_type(input: TokenStream) -> TokenStream {
+ TokenStream::from(match derive_simple_static_type_inner(input) {
Ok(tokens) => tokens,
Err(err) => err.to_compile_error(),
})
}
-pub fn derive_for_struct(
+fn get_simple_static_type<T>(ty: T) -> proc_macro2::TokenStream
+where
+ T: quote::ToTokens,
+{
+ quote!(
+ <#ty as dhall::SimpleStaticType>::get_simple_static_type()
+ )
+}
+
+fn derive_for_struct(
data: &syn::DataStruct,
constraints: &mut Vec<syn::Type>,
) -> Result<proc_macro2::TokenStream, Error> {
@@ -44,7 +53,8 @@ pub fn derive_for_struct(
.map(|(name, ty)| {
let name = dhall_core::Label::from(name);
constraints.push(ty.clone());
- (name, quote!(<#ty as dhall::StaticType>::get_type()))
+ let ty = get_simple_static_type(ty);
+ (name, quote!(#ty.into()))
})
.collect();
let record =
@@ -52,7 +62,7 @@ pub fn derive_for_struct(
Ok(quote! { dhall_core::rc(#record) })
}
-pub fn derive_for_enum(
+fn derive_for_enum(
data: &syn::DataEnum,
constraints: &mut Vec<syn::Type>,
) -> Result<proc_macro2::TokenStream, Error> {
@@ -88,7 +98,8 @@ pub fn derive_for_enum(
};
let ty = ty?;
constraints.push(ty.clone());
- Ok((name, quote!(<#ty as dhall::StaticType>::get_type())))
+ let ty = get_simple_static_type(ty);
+ Ok((name, quote!(#ty.into())))
})
.collect::<Result<_, Error>>()?;
@@ -97,7 +108,7 @@ pub fn derive_for_enum(
Ok(quote! { dhall_core::rc(#union) })
}
-pub fn derive_type_inner(
+pub fn derive_simple_static_type_inner(
input: TokenStream,
) -> Result<proc_macro2::TokenStream, Error> {
let input: DeriveInput = syn::parse_macro_input::parse(input)?;
@@ -136,7 +147,7 @@ pub fn derive_type_inner(
let mut local_where_clause = orig_where_clause.clone();
local_where_clause
.predicates
- .push(parse_quote!(#ty: dhall::StaticType));
+ .push(parse_quote!(#ty: dhall::SimpleStaticType));
let phantoms = generics.params.iter().map(|param| match param {
syn::GenericParam::Type(syn::TypeParam { ident, .. }) => {
quote!(#ident)
@@ -158,16 +169,16 @@ pub fn derive_type_inner(
for ty in constraints.iter() {
where_clause
.predicates
- .push(parse_quote!(#ty: dhall::StaticType));
+ .push(parse_quote!(#ty: dhall::SimpleStaticType));
}
let ident = &input.ident;
let tokens = quote! {
- impl #impl_generics dhall::StaticType for #ident #ty_generics
+ impl #impl_generics dhall::SimpleStaticType for #ident #ty_generics
#where_clause {
- fn get_type() -> dhall_core::DhallExpr {
+ fn get_simple_static_type() -> dhall::expr::SimpleType {
#(#assertions)*
- #get_type
+ dhall::expr::SimpleType::from(#get_type)
}
}
};
diff --git a/dhall_generator/src/lib.rs b/dhall_generator/src/lib.rs
index b422834..e67f2aa 100644
--- a/dhall_generator/src/lib.rs
+++ b/dhall_generator/src/lib.rs
@@ -21,7 +21,7 @@ pub fn subexpr(input: TokenStream) -> TokenStream {
quote::subexpr(input)
}
-#[proc_macro_derive(StaticType)]
-pub fn derive_type(input: TokenStream) -> TokenStream {
- derive::derive_type(input)
+#[proc_macro_derive(SimpleStaticType)]
+pub fn derive_simple_static_type(input: TokenStream) -> TokenStream {
+ derive::derive_simple_static_type(input)
}