├── .gitignore ├── Cargo.toml ├── LICENSE.txt ├── README.md ├── src ├── common.rs ├── env.rs ├── lib.rs ├── parse.rs ├── trans │ ├── assign.rs │ ├── binop.rs │ ├── block.rs │ ├── enum_.rs │ ├── fn_.rs │ ├── if_.rs │ ├── impl_.rs │ ├── lit.rs │ ├── match_.rs │ ├── misc.rs │ ├── mod.rs │ ├── struct_.rs │ └── unary.rs ├── tyint.rs ├── utils.rs └── var.rs └── tests └── macro ├── binop.rs ├── common.rs ├── fail_match_attribute.rs ├── fail_match_attribute.stderr ├── if_.rs ├── main.rs ├── match_.rs ├── misc.rs └── recursion.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # rust 2 | /target 3 | Cargo.lock 4 | 5 | # editor 6 | *~ 7 | .*~ 8 | *.swp 9 | *.swo 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "typ" 3 | description = "Type-level programming in Rust" 4 | version = "0.1.1" 5 | authors = ["jerry73204 "] 6 | edition = "2018" 7 | documentation = "https://docs.rs/typ/" 8 | repository = "https://github.com/jerry73204/typ.git" 9 | homepage = "https://github.com/jerry73204/typ" 10 | readme = "README.md" 11 | license = "MIT" 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [lib] 16 | proc-macro = true 17 | 18 | [dependencies] 19 | syn = { version = "1.0", features = ["full", "extra-traits", "visit-mut"] } 20 | quote = "1.0" 21 | proc-macro2 = "1.0" 22 | itertools = "0.9" 23 | radix_trie = "0.2" 24 | by_address = "1.0" 25 | indexmap = "1.5" 26 | 27 | [dev-dependencies] 28 | typenum = "1.12" 29 | trybuild = "1.0.34" 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Hsiang-Jui Lin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TYP: type-level programming in Rust 2 | 3 | [[Book](https://github.com/jerry73204/typ-book/) | [Doc](https://docs.rs/typ)] 4 | 5 | TYP enables you to write _type operators_, the functions that translates types, in Rust syntax. 6 | 7 | It is re-design of [willcrichton/Tyrade](https://github.com/willcrichton/tyrade) and was inspired by [jerry73204/type-freak](https://github.com/jerry73204/rust-type-freak). 8 | 9 | ## Features 10 | 11 | ### Rusty syntax 12 | 13 | TYP adopts Rust-like syntax, where values become types, and types become trait bounds. The core concept is the type operator, which is a function that takes type arguments and produce types. Trait bounds are optionally added to input and output types. 14 | 15 | ```rust 16 | fn TypeOperatorName(type1: _, type2: Trait1 + Trait2) -> TraitBound { ... } 17 | ``` 18 | 19 | - `` lists the generic identifiers that helps disginguishing from public types. 20 | - `type1` and `type2` are input types composed of generics and public types. 21 | - `type1: _` means the type has no trait bound. 22 | - The output trait bound `fn() -> TraitBound` is optional. 23 | 24 | 25 | The snipplet demonstrates a simple type operator. 26 | 27 | ```rust 28 | typ! { 29 | use typenum::Unsigned; 30 | 31 | fn Add(lhs: Unsigned, rhs: Unsigned) -> Unsigned { 32 | lhs + rhs 33 | } 34 | } 35 | ``` 36 | 37 | ### Built-in typenum support 38 | 39 | TYP provides first-class support to [typenum](https://github.com/paholg/typenum). Integer literals are translated to typenum types. The following literals are understood by TYP. 40 | 41 | - Signed integers: `7` or `7i` 42 | - Unsigned integers: `7u` 43 | - Bits: `true` and `false` 44 | 45 | Common binary and unary operators applies on types with appropriate traits. For example, `A + B` expands to `>::Output`. 46 | 47 | ```rust 48 | typ! { 49 | use typenum::{Integer, Bit}; 50 | 51 | fn IsOdd(value: Integer) -> Bit { 52 | if value % 2 == 1 { 53 | true 54 | } else { 55 | false 56 | } 57 | } 58 | } 59 | ``` 60 | 61 | ### Type matching 62 | 63 | Like normal Rust, the `match` syntax lets you match and unpack types. You can bind new generics on a pattern using `#[generics(...)]` attribute. 64 | 65 | The example demonstrates a type operator that appends a type at the end of type-level list. It's done by recursively unpack the list into `Cons` nodes and `Nil` end-of-list marker. 66 | 67 | ```rust 68 | pub trait List {} 69 | 70 | pub struct Cons { /* omit */ } 71 | impl List for Cons {} 72 | 73 | pub struct Nil; 74 | impl List for Nil {} 75 | 76 | typ! { 77 | fn Append(input: List, value: _) -> List { 78 | match input { 79 | #[generics(head, tail: List)] 80 | Cons:: => { 81 | let new_tail = Append(tail, value); 82 | Cons:: 83 | } 84 | Nil => { 85 | Cons:: 86 | } 87 | } 88 | } 89 | } 90 | 91 | ``` 92 | 93 | ## Examples 94 | 95 | More advanced examples can be found in [tests/](tests) directory. 96 | 97 | - [if/else](tests/macro/if_.rs) 98 | - [match](tests/macro/match_.rs) 99 | - [binary GCD](tests/macro/recursion.rs) 100 | 101 | ## License 102 | 103 | MIT license. See [LICENSE.txt](LICENSE.txt). 104 | -------------------------------------------------------------------------------- /src/common.rs: -------------------------------------------------------------------------------- 1 | pub use by_address::ByAddress; 2 | pub use indexmap::{IndexMap, IndexSet}; 3 | pub use itertools::Itertools; 4 | pub use proc_macro2::{Span, TokenStream}; 5 | pub use quote::{format_ident, quote, quote_spanned, ToTokens}; 6 | pub use radix_trie::{Trie, TrieCommon, TrieKey}; 7 | pub use std::{ 8 | borrow::{Borrow, BorrowMut, Cow}, 9 | cell::{Cell, Ref, RefCell, RefMut}, 10 | cmp::Ordering, 11 | collections::{BTreeMap, BTreeSet, HashMap, HashSet}, 12 | convert::{TryFrom, TryInto}, 13 | fmt::Debug, 14 | hash::Hash, 15 | hash::Hasher, 16 | iter::{self, Extend, FromIterator, Sum}, 17 | mem, 18 | ops::{Add, AddAssign, Deref, DerefMut}, 19 | rc::{Rc, Weak}, 20 | }; 21 | pub use syn::{ 22 | parse::{Parse, ParseStream}, 23 | parse_macro_input, 24 | punctuated::Punctuated, 25 | spanned::Spanned, 26 | token, 27 | visit_mut::VisitMut, 28 | Arm, AttrStyle, Attribute, BinOp, Block, ConstParam, Error, Expr, ExprAssign, ExprBinary, 29 | ExprBlock, ExprCall, ExprIf, ExprIndex, ExprLet, ExprLit, ExprMatch, ExprMethodCall, ExprPath, 30 | ExprReturn, ExprTuple, ExprUnary, Field, Fields, FnArg, GenericArgument, GenericParam, 31 | Generics, Ident, ImplItem, ImplItemMethod, ImplItemType, Item, ItemEnum, ItemFn, ItemImpl, 32 | ItemMod, ItemStruct, ItemTrait, ItemUse, Lifetime, LifetimeDef, Lit, LitBool, LitInt, Local, 33 | Pat, PatIdent, PatPath, PatTuple, PatType, Path, PathArguments, PathSegment, PredicateType, 34 | QSelf, Receiver, ReturnType, Signature, Stmt, Token, TraitBound, TraitBoundModifier, Type, 35 | TypeParam, TypeParamBound, TypeParen, TypePath, TypeTraitObject, TypeTuple, UnOp, Variant, 36 | Visibility, WherePredicate, 37 | }; 38 | 39 | pub const IDENT_PREFIX: &str = "__TYP_"; 40 | -------------------------------------------------------------------------------- /src/env.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | common::*, 3 | utils::{IntoRc, Shared, SharedCell}, 4 | var::{PredicateTypeVar, TypeParamBoundVar, TypeVar, WherePredicateVar}, 5 | }; 6 | 7 | pub use env::*; 8 | 9 | mod env { 10 | use super::*; 11 | 12 | #[derive(Debug)] 13 | pub struct Env { 14 | self_name: Rc, 15 | variables: IndexSet>, 16 | type_predicates: HashMap>, 17 | namespace: Vec, Shared>>, 18 | trait_name_prefixes: SharedCell>, 19 | } 20 | 21 | impl Env { 22 | pub fn new(self_name: Ident) -> Self { 23 | Self { 24 | self_name: Rc::new(self_name), 25 | variables: IndexSet::new(), 26 | type_predicates: HashMap::new(), 27 | namespace: vec![HashMap::new()], 28 | trait_name_prefixes: SharedCell::new(Trie::new()), 29 | } 30 | } 31 | 32 | pub fn get_variable(&self, ident: &Ident) -> Option> { 33 | // locale the variable 34 | self.namespace 35 | .iter() 36 | .rev() 37 | .find_map(|variables| variables.get(ident).cloned()) 38 | } 39 | 40 | pub fn branch(&self) -> Self { 41 | let self_name = self.self_name.clone(); 42 | let variables = self.variables.clone(); 43 | let type_predicates = self.type_predicates.clone(); 44 | let mut namespace = self.namespace.clone(); 45 | let trait_name_prefixes = self.trait_name_prefixes.clone(); 46 | 47 | // add one extra scope 48 | namespace.push(HashMap::new()); 49 | 50 | Self { 51 | self_name, 52 | variables, 53 | type_predicates, 54 | namespace, 55 | trait_name_prefixes, 56 | } 57 | } 58 | 59 | pub fn insert_free_quantifier(&mut self, ident: Ident) -> Shared { 60 | // create a new variable 61 | let ident = Rc::new(ident); 62 | let var = Shared::new(Variable { 63 | is_mut: false, 64 | value: None, 65 | }); 66 | 67 | // insert to var list 68 | self.variables.insert(var.clone()); 69 | 70 | // insert to namespace 71 | self.namespace 72 | .last_mut() 73 | .unwrap() 74 | .insert(ident.clone(), var.clone()); 75 | 76 | var 77 | } 78 | 79 | pub fn insert_bounded_quantifier( 80 | &mut self, 81 | ident: Ident, 82 | is_mut: bool, 83 | value: T, 84 | ) -> Shared 85 | where 86 | T: IntoRc, 87 | { 88 | // create a new variable 89 | let ident = Rc::new(ident); 90 | let var = Shared::new(Variable { 91 | is_mut, 92 | value: Some(value.into_rc()), 93 | }); 94 | 95 | // insert to var list 96 | self.variables.insert(var.clone()); 97 | 98 | // insert to namespace 99 | self.namespace 100 | .last_mut() 101 | .unwrap() 102 | .insert(ident.clone(), var.clone()); 103 | 104 | var 105 | } 106 | 107 | pub fn insert_predicate(&mut self, predicate: WherePredicateVar) { 108 | match predicate { 109 | WherePredicateVar::Type(PredicateTypeVar { bounded_ty, bounds }) => { 110 | self.type_predicates 111 | .entry(bounded_ty) 112 | .or_insert_with(|| HashSet::new()) 113 | .extend(bounds); 114 | } 115 | } 116 | } 117 | 118 | pub fn assign_quantifier(&mut self, ident: &Ident, value: T) -> syn::Result<()> 119 | where 120 | T: IntoRc, 121 | { 122 | // locate the variable in namespace 123 | let opt = 124 | self.namespace 125 | .iter() 126 | .enumerate() 127 | .rev() 128 | .find_map(|(scope_index, variables)| { 129 | variables 130 | .get(ident) 131 | .cloned() 132 | .map(|var| (scope_index, var.is_mut)) 133 | }); 134 | 135 | match opt { 136 | Some((scope_index, true)) => { 137 | let ident = Rc::new(ident.to_owned()); 138 | let var = Shared::new(Variable { 139 | is_mut: true, 140 | value: Some(value.into_rc()), 141 | }); 142 | self.namespace[scope_index].insert(ident.clone(), var); 143 | Ok(()) 144 | } 145 | Some((_, false)) => Err(Error::new(ident.span(), "the variable is not mutable")), 146 | None => Err(Error::new(ident.span(), "the variable is not defined")), 147 | } 148 | } 149 | 150 | pub fn mutable_quantifiers(&self) -> HashMap, Shared> { 151 | let (_shadowed, output) = self.namespace.iter().rev().fold( 152 | (HashSet::new(), HashMap::new()), 153 | |mut state, variables| { 154 | let (shadowed, output) = &mut state; 155 | 156 | variables.iter().for_each(|(ident, var)| { 157 | if shadowed.insert(ident.to_owned()) { 158 | if var.is_mut { 159 | output.insert(ident.to_owned(), var.clone()); 160 | } 161 | } 162 | }); 163 | 164 | state 165 | }, 166 | ); 167 | output 168 | } 169 | 170 | pub fn free_quantifiers(&self) -> Vec> { 171 | self.variables 172 | .iter() 173 | .filter_map(|var| { 174 | if var.is_free() { 175 | Some(var.clone()) 176 | } else { 177 | None 178 | } 179 | }) 180 | .collect() 181 | } 182 | 183 | pub fn predicates(&self) -> Vec { 184 | let type_predicates = self.type_predicates.iter().map(|(bounded_ty, bounds)| { 185 | let bounds: Vec<_> = bounds.iter().cloned().collect(); 186 | WherePredicateVar::Type(PredicateTypeVar { 187 | bounded_ty: bounded_ty.clone(), 188 | bounds, 189 | }) 190 | }); 191 | type_predicates.collect() 192 | } 193 | 194 | pub fn sub_scope(&mut self, f: F) -> T 195 | where 196 | F: FnOnce(&mut Env) -> T, 197 | { 198 | // append one scope on namesapce 199 | self.namespace.push(HashMap::new()); 200 | 201 | // apply 202 | let ret = f(self); 203 | 204 | // pop subscope 205 | self.namespace.pop(); 206 | 207 | ret 208 | } 209 | 210 | pub fn register_trait_name(&mut self, prefix: &str) -> Option { 211 | let count = { 212 | let mut prefixes = self.trait_name_prefixes.borrow_mut(); 213 | 214 | // check if the prefix is a proper prefix of existing prefixes 215 | if let Some(subtrie) = prefixes.subtrie(prefix) { 216 | if !subtrie.is_leaf() { 217 | return None; 218 | } 219 | } 220 | prefixes.map_with_default(prefix.to_string(), |count| *count += 1, 0); 221 | *prefixes.get(prefix).unwrap() 222 | }; 223 | 224 | Some(format_ident!("{}{}", prefix, count)) 225 | } 226 | } 227 | 228 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 229 | pub struct Variable { 230 | pub is_mut: bool, 231 | // some -> bounded, none -> free 232 | pub value: Option>, 233 | } 234 | 235 | impl Variable { 236 | pub fn is_free(&self) -> bool { 237 | matches!(self.value, None) 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! TYP is a type-level programming langauge that computes types. 2 | //! It enables you to write _type operators_, the functions that translates types, in Rust syntax. 3 | //! Please read the [TYP book](https://github.com/jerry73204/typ-book/) understand the usage. 4 | 5 | #![feature(hash_set_entry)] 6 | 7 | mod common; 8 | mod env; 9 | mod parse; 10 | mod trans; 11 | mod tyint; 12 | mod utils; 13 | mod var; 14 | 15 | use crate::{common::*, parse::ItemVec}; 16 | 17 | /// The main macro that translates the TYP langauge to actual Rust implementations. 18 | #[proc_macro] 19 | pub fn typ(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { 20 | let ItemVec(items) = parse_macro_input!(tokens as ItemVec); 21 | crate::trans::translate_items(&items) 22 | .unwrap_or_else(|err| err.to_compile_error()) 23 | .into() 24 | } 25 | 26 | /// Constructs a signed integer type from an integer literal. 27 | #[proc_macro] 28 | pub fn tyint(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 29 | tyint::tyint(input) 30 | } 31 | 32 | /// Constructs an unsigned integer type from an integer literal. 33 | #[proc_macro] 34 | pub fn tyuint(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 35 | tyint::tyuint(input) 36 | } 37 | -------------------------------------------------------------------------------- /src/parse.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | common::*, 3 | env::Env, 4 | var::{ 5 | ParseTypeParamBoundVar, ParseTypeVar, ParseWherePredicateVar, PredicateTypeVar, 6 | WherePredicateVar, 7 | }, 8 | }; 9 | 10 | #[derive(Debug, Clone)] 11 | pub struct ItemVec(pub Vec); 12 | 13 | impl Parse for ItemVec { 14 | fn parse(input: ParseStream) -> syn::Result { 15 | let mut items = Vec::new(); 16 | while !input.cursor().eof() { 17 | items.push(input.parse::()?); 18 | } 19 | Ok(ItemVec(items)) 20 | } 21 | } 22 | 23 | #[derive(Debug, Clone)] 24 | pub struct SimpleTypeParam { 25 | pub ident: Ident, 26 | pub bounds: Punctuated, 27 | } 28 | 29 | impl Parse for SimpleTypeParam { 30 | fn parse(input: ParseStream) -> syn::Result { 31 | let ident: Ident = input.parse()?; 32 | 33 | let param = if input.peek(syn::token::Colon) { 34 | let _: syn::token::Colon = input.parse()?; 35 | let bounds = Punctuated::parse_separated_nonempty(input)?; 36 | Self { ident, bounds } 37 | } else { 38 | Self { 39 | ident, 40 | bounds: Punctuated::new(), 41 | } 42 | }; 43 | 44 | Ok(param) 45 | } 46 | } 47 | 48 | impl ParseWherePredicateVar for SimpleTypeParam { 49 | fn parse_where_predicate_var(&self, env: &mut Env) -> syn::Result { 50 | let SimpleTypeParam { ident, bounds } = self; 51 | 52 | let bounded_ty = ident.parse_type_var(env)?; 53 | let bounds = bounds 54 | .iter() 55 | .map(|bound| bound.parse_type_param_bound_var(env)) 56 | .try_collect()?; 57 | 58 | Ok(WherePredicateVar::Type(PredicateTypeVar { 59 | bounded_ty, 60 | bounds, 61 | })) 62 | } 63 | } 64 | 65 | #[derive(Debug, Clone)] 66 | pub struct GenericsAttr { 67 | pub params: Punctuated, 68 | } 69 | 70 | impl Parse for GenericsAttr { 71 | fn parse(input: ParseStream) -> syn::Result { 72 | let content; 73 | syn::parenthesized!(content in input); 74 | let params = Punctuated::parse_terminated(&content)?; 75 | Ok(Self { params }) 76 | } 77 | } 78 | 79 | #[derive(Debug, Clone)] 80 | pub struct CaptureAttr { 81 | pub params: Punctuated, 82 | } 83 | 84 | impl Parse for CaptureAttr { 85 | fn parse(input: ParseStream) -> syn::Result { 86 | let content; 87 | syn::parenthesized!(content in input); 88 | let params = Punctuated::parse_terminated(&content)?; 89 | Ok(Self { params }) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/trans/assign.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_assign_expr( 4 | assign: &ExprAssign, 5 | scope: &mut Env, 6 | items: &mut Vec, 7 | ) -> syn::Result 8 | where 9 | { 10 | let ExprAssign { left, right, .. } = assign; 11 | 12 | // parse lhs 13 | let ident = match &**left { 14 | Expr::Path(path) => match path.path.get_ident() { 15 | Some(ident) => ident, 16 | None => return Err(Error::new(path.span(), "not an identifier")), 17 | }, 18 | _ => return Err(Error::new(left.span(), "not an identifier")), 19 | }; 20 | 21 | // parse rhs 22 | let value = translate_expr(right, scope, items)?; 23 | 24 | // update state 25 | scope.assign_quantifier(ident, value)?; 26 | 27 | // expand return value 28 | let output = syn::parse2::(quote! { () }) 29 | .unwrap() 30 | .parse_pure_type(&mut vec![]) 31 | .unwrap(); 32 | 33 | Ok(output) 34 | } 35 | -------------------------------------------------------------------------------- /src/trans/binop.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_binary_expr( 4 | ExprBinary { 5 | left, right, op, .. 6 | }: &ExprBinary, 7 | scope: &mut Env, 8 | items: &mut Vec, 9 | ) -> syn::Result 10 | where 11 | { 12 | // parse lhs and rhs 13 | let lhs = translate_expr(left, scope, items)?; 14 | let rhs = translate_expr(right, scope, items)?; 15 | 16 | // compute output 17 | match op { 18 | BinOp::Add(_) => std_bin_op(scope, quote! { core::ops::Add }, lhs, rhs), 19 | BinOp::Sub(_) => std_bin_op(scope, quote! { core::ops::Sub }, lhs, rhs), 20 | BinOp::Div(_) => std_bin_op(scope, quote! { core::ops::Div }, lhs, rhs), 21 | BinOp::Mul(_) => std_bin_op(scope, quote! { core::ops::Mul }, lhs, rhs), 22 | BinOp::And(_) => std_bin_op(scope, quote! { core::ops::BitAnd }, lhs, rhs), 23 | BinOp::Or(_) => std_bin_op(scope, quote! { core::ops::BitOr }, lhs, rhs), 24 | BinOp::BitAnd(_) => std_bin_op(scope, quote! { core::ops::BitAnd }, lhs, rhs), 25 | BinOp::BitOr(_) => std_bin_op(scope, quote! { core::ops::BitOr }, lhs, rhs), 26 | BinOp::BitXor(_) => std_bin_op(scope, quote! { core::ops::BitXor }, lhs, rhs), 27 | BinOp::Rem(_) => std_bin_op(scope, quote! { core::ops::Rem }, lhs, rhs), 28 | BinOp::Lt(_) => typenum_bin_op(scope, quote! { typenum::type_operators::IsLess }, lhs, rhs), 29 | BinOp::Gt(_) => typenum_bin_op( 30 | scope, 31 | quote! { typenum::type_operators::IsGreater }, 32 | lhs, 33 | rhs, 34 | ), 35 | BinOp::Le(_) => typenum_bin_op( 36 | scope, 37 | quote! { typenum::type_operators::IsLessOrEqual }, 38 | lhs, 39 | rhs, 40 | ), 41 | BinOp::Ge(_) => typenum_bin_op( 42 | scope, 43 | quote! { typenum::type_operators::IsGreaterOrEqual }, 44 | lhs, 45 | rhs, 46 | ), 47 | BinOp::Eq(_) => { 48 | typenum_bin_op(scope, quote! { typenum::type_operators::IsEqual }, lhs, rhs) 49 | } 50 | BinOp::Ne(_) => typenum_bin_op( 51 | scope, 52 | quote! { typenum::type_operators::IsNotEqual }, 53 | lhs, 54 | rhs, 55 | ), 56 | _ => { 57 | return Err(Error::new( 58 | op.span(), 59 | "the binary operator is not supported", 60 | )) 61 | } 62 | } 63 | } 64 | 65 | fn std_bin_op( 66 | scope: &mut Env, 67 | trait_tokens: TokenStream, 68 | lhs: TypeVar, 69 | rhs: TypeVar, 70 | ) -> syn::Result { 71 | let trait_path = syn::parse2::(trait_tokens)?.parse_pure_path(&mut vec![])?; 72 | 73 | let (output, predicate) = { 74 | let trait_ = { 75 | let mut path = trait_path.clone(); 76 | path.segments.last_mut().as_mut().unwrap().arguments = 77 | PathArgumentsVar::AngleBracketed(vec![rhs]); 78 | path 79 | }; 80 | let path = { 81 | let mut path = trait_.clone(); 82 | path.segments.push(SegmentVar { 83 | ident: format_ident!("Output"), 84 | arguments: PathArgumentsVar::None, 85 | }); 86 | path 87 | }; 88 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 89 | bounded_ty: lhs.clone(), 90 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 91 | modifier: TraitBoundModifierVar::None, 92 | path: trait_.clone(), 93 | })], 94 | }); 95 | let output = TypeVar::Path(TypePathVar { 96 | qself: Some(QSelfVar { 97 | ty: Box::new(lhs), 98 | position: trait_.segments.len(), 99 | }), 100 | path, 101 | }); 102 | (output, predicate) 103 | }; 104 | 105 | scope.insert_predicate(predicate); 106 | 107 | Ok(output) 108 | } 109 | 110 | fn typenum_bin_op( 111 | scope: &mut Env, 112 | trait_tokens: TokenStream, 113 | lhs: TypeVar, 114 | rhs: TypeVar, 115 | ) -> syn::Result { 116 | let trait_path = syn::parse2::(trait_tokens)?.parse_pure_path(&mut vec![])?; 117 | 118 | let (output, apply_predicates, output_predicates) = { 119 | let trait_ = { 120 | let mut path = trait_path.clone(); 121 | path.segments.last_mut().as_mut().unwrap().arguments = 122 | PathArgumentsVar::AngleBracketed(vec![rhs]); 123 | path 124 | }; 125 | let path = { 126 | let mut path = trait_.clone(); 127 | path.segments.push(SegmentVar { 128 | ident: format_ident!("Output"), 129 | arguments: PathArgumentsVar::None, 130 | }); 131 | path 132 | }; 133 | let output = TypeVar::Path(TypePathVar { 134 | qself: Some(QSelfVar { 135 | ty: Box::new(lhs.clone()), 136 | position: trait_.segments.len(), 137 | }), 138 | path, 139 | }); 140 | let apply_predicate = WherePredicateVar::Type(PredicateTypeVar { 141 | bounded_ty: lhs, 142 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 143 | modifier: TraitBoundModifierVar::None, 144 | path: trait_, 145 | })], 146 | }); 147 | let output_predicate = WherePredicateVar::Type(PredicateTypeVar { 148 | bounded_ty: output.clone(), 149 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 150 | modifier: TraitBoundModifierVar::None, 151 | path: syn::parse2::(quote! { typenum::marker_traits::Bit }) 152 | .unwrap() 153 | .parse_pure_path(&mut vec![]) 154 | .unwrap(), 155 | })], 156 | }); 157 | (output, apply_predicate, output_predicate) 158 | }; 159 | 160 | scope.insert_predicate(apply_predicates); 161 | scope.insert_predicate(output_predicates); 162 | 163 | Ok(output) 164 | } 165 | -------------------------------------------------------------------------------- /src/trans/block.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_block( 4 | block: &Block, 5 | scope: &mut Env, 6 | items: &mut Vec, 7 | ) -> syn::Result 8 | where 9 | { 10 | let mut output_ty = None; 11 | 12 | // creates a subscope 13 | scope.sub_scope(|scope| { 14 | for stmt in block.stmts.iter() { 15 | match stmt { 16 | Stmt::Local(local) => { 17 | // parse let statement as (let indent: trait_bounds = expr) 18 | let (ident, ty_opt, is_mut, expr) = { 19 | // check if the initial type is present 20 | let (pat, expr) = match local { 21 | Local { 22 | pat, 23 | init: Some((_eq, expr)), 24 | .. 25 | } => (pat, expr), 26 | _ => { 27 | return Err(Error::new(local.span(), "initial type must be given")) 28 | } 29 | }; 30 | 31 | let (ident, ty_opt, is_mut) = match pat { 32 | // only indent (let x = ...) 33 | Pat::Ident(PatIdent { 34 | ident, mutability, .. 35 | }) => (ident, None, matches!(mutability, Some(_))), 36 | // indent with type (let x: T = ...) 37 | Pat::Type(PatType { pat, ty, .. }) => { 38 | let (ident, is_mut) = match &**pat { 39 | Pat::Ident(PatIdent { 40 | ident, mutability, .. 41 | }) => (ident, matches!(mutability, Some(_))), 42 | _ => return Err(Error::new(local.span(), "not an identifier")), 43 | }; 44 | (ident, Some(&**ty), is_mut) 45 | } 46 | _ => return Err(Error::new(pat.span(), "not a identifier")), 47 | }; 48 | 49 | (ident, ty_opt, is_mut, expr) 50 | }; 51 | 52 | // compute output type from expression 53 | let value = translate_expr(expr, scope, items)?; 54 | 55 | // add new bounded quantifier 56 | scope.insert_bounded_quantifier(ident.to_owned(), is_mut, value.clone()); 57 | 58 | // insert trait bounds 59 | if let Some(ty) = ty_opt { 60 | let bounded_ty = ident.parse_type_var(scope)?; 61 | let bounds = ty.parse_type_param_bounds_var(scope)?; 62 | let predicates = 63 | WherePredicateVar::Type(PredicateTypeVar { bounded_ty, bounds }); 64 | scope.insert_predicate(predicates); 65 | } 66 | 67 | output_ty = None; 68 | } 69 | Stmt::Item(item) => { 70 | return Err(Error::new(item.span(), "in-block item is not allowed")) 71 | } 72 | Stmt::Expr(expr) => { 73 | output_ty = Some(translate_expr(expr, scope, items)?); 74 | } 75 | Stmt::Semi(expr, _semi) => { 76 | translate_expr(expr, scope, items)?; 77 | output_ty = None; 78 | } 79 | } 80 | } 81 | 82 | Ok(()) 83 | })?; 84 | 85 | Ok(output_ty.unwrap_or_else(|| { 86 | syn::parse2::(quote! { () }) 87 | .unwrap() 88 | .parse_pure_type(&mut vec![]) 89 | .unwrap() 90 | })) 91 | } 92 | -------------------------------------------------------------------------------- /src/trans/enum_.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_enum(_enum_: &ItemEnum) -> syn::Result { 4 | todo!(); 5 | // let ItemEnum { 6 | // vis, 7 | // ident: trait_name, 8 | // variants, 9 | // .. 10 | // } = enum_; 11 | 12 | // let types: Vec<_> = variants 13 | // .iter() 14 | // .map(|variant| -> syn::Result<_> { 15 | // let Variant { 16 | // ident: type_name, 17 | // fields, 18 | // .. 19 | // } = variant; 20 | 21 | // let generics = match fields { 22 | // Fields::Unit => vec![], 23 | // Fields::Unnamed(unnamed) => { 24 | // let generics: Vec<_> = unnamed 25 | // .unnamed 26 | // .iter() 27 | // .enumerate() 28 | // .map(|(index, field)| -> syn::Result<_> { 29 | // let Field { ty, .. } = field; 30 | // let generic_name = format_ident!("T{}", index); 31 | // let trait_bounds = ty_to_trait_bounds(ty)?; 32 | 33 | // Ok((generic_name, trait_bounds)) 34 | // }) 35 | // .try_collect()?; 36 | 37 | // generics 38 | // } 39 | // Fields::Named(named) => { 40 | // let generics: Vec<_> = named 41 | // .named 42 | // .iter() 43 | // .map(|field| -> syn::Result<_> { 44 | // let Field { ident, ty, .. } = field; 45 | // let generic_name = ident.to_owned().unwrap(); 46 | // let trait_bounds = ty_to_trait_bounds(ty)?; 47 | 48 | // Ok((generic_name.to_owned(), trait_bounds)) 49 | // }) 50 | // .try_collect()?; 51 | 52 | // generics 53 | // } 54 | // }; 55 | 56 | // Ok((type_name, generics)) 57 | // }) 58 | // .try_collect()?; 59 | 60 | // let impls = { 61 | // let items: Vec<_> = types 62 | // .into_iter() 63 | // .map(|(type_name, generics)| { 64 | // let generic_args = { 65 | // let names: Vec<_> = generics.iter().map(|(name, _)| name).collect(); 66 | // quote! { 67 | // #(#names),* 68 | // } 69 | // }; 70 | 71 | // let where_clause = { 72 | // let bounds: Vec<_> = generics 73 | // .iter() 74 | // .filter_map(|(name, bounds)| { 75 | // if bounds.is_empty() { 76 | // None 77 | // } else { 78 | // Some(quote! { 79 | // #name: #(#bounds)+* 80 | // }) 81 | // } 82 | // }) 83 | // .collect(); 84 | 85 | // quote! { 86 | // #(#bounds),* 87 | // } 88 | // }; 89 | 90 | // quote! { 91 | // #vis struct #type_name<#generic_args> 92 | // where 93 | // #where_clause 94 | // { 95 | // _phantom: ::core::marker::PhantomData<#generic_args> 96 | // } 97 | 98 | // impl<#generic_args> #trait_name for #type_name<#generic_args> 99 | // where 100 | // #where_clause 101 | // {} 102 | // } 103 | // }) 104 | // .collect(); 105 | 106 | // quote! { 107 | // #(#items)* 108 | // } 109 | // }; 110 | 111 | // let expanded = quote! { 112 | // #vis trait #trait_name {} 113 | 114 | // #impls 115 | // }; 116 | 117 | // Ok(expanded) 118 | } 119 | -------------------------------------------------------------------------------- /src/trans/fn_.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_fn( 4 | vis: &Visibility, 5 | sig: &Signature, 6 | block: &Block, 7 | self_ty: Option<&Type>, 8 | impl_generics: Option<&Generics>, 9 | ) -> syn::Result { 10 | let Signature { 11 | ident: fn_name, 12 | generics: fn_generics, 13 | inputs, 14 | output, 15 | constness, 16 | asyncness, 17 | unsafety, 18 | variadic, 19 | .. 20 | } = sig; 21 | 22 | // sanity checks 23 | if let Some(const_) = constness { 24 | return Err(Error::new(const_.span(), "the keyword is not supported")); 25 | } 26 | 27 | if let Some(async_) = asyncness { 28 | return Err(Error::new(async_.span(), "the keyword is not supported")); 29 | } 30 | 31 | if let Some(unsafe_) = unsafety { 32 | return Err(Error::new(unsafe_.span(), "the keyword is not supported")); 33 | } 34 | 35 | if let Some(var) = variadic { 36 | return Err(Error::new(var.span(), "variadic argument is not supported")); 37 | } 38 | 39 | // reject lifetime and const generics 40 | if let Some(impl_generics) = impl_generics { 41 | for param in impl_generics.params.iter() { 42 | match param { 43 | GenericParam::Type(TypeParam { .. }) => (), 44 | GenericParam::Lifetime(lifetime) => { 45 | return Err(Error::new(lifetime.span(), "lifetime is not supported")) 46 | } 47 | GenericParam::Const(const_) => { 48 | return Err(Error::new(const_.span(), "const generic is not supported")) 49 | } 50 | } 51 | } 52 | } 53 | 54 | for param in fn_generics.params.iter() { 55 | match param { 56 | GenericParam::Type(TypeParam { .. }) => (), 57 | GenericParam::Lifetime(lifetime) => { 58 | return Err(Error::new(lifetime.span(), "lifetime is not supported")) 59 | } 60 | GenericParam::Const(const_) => { 61 | return Err(Error::new(const_.span(), "const generic is not supported")) 62 | } 63 | } 64 | } 65 | 66 | // create root scope 67 | let mut env = Env::new(fn_name.clone()); 68 | 69 | // check if impl and fn generic names coincide with each other 70 | if let Some(impl_generics) = impl_generics { 71 | let impl_type_params: HashSet<_> = impl_generics 72 | .params 73 | .iter() 74 | .map(|param| match param { 75 | GenericParam::Type(TypeParam { ident, .. }) => ident, 76 | _ => unreachable!("please report bug"), 77 | }) 78 | .collect(); 79 | 80 | for param in fn_generics.params.iter() { 81 | if let GenericParam::Type(TypeParam { 82 | ident: fn_ident, .. 83 | }) = param 84 | { 85 | if let Some(impl_ident) = impl_type_params.get(fn_ident) { 86 | let mut err = Error::new(impl_ident.span(), "the generic is defined here"); 87 | err.combine(Error::new( 88 | fn_ident.span(), 89 | "the generic name must not coincide with generics from impl blocks", 90 | )); 91 | return Err(err); 92 | } 93 | } 94 | } 95 | } 96 | 97 | // insert free quantifiers and predicates from impl generics 98 | if let Some(impl_generics) = impl_generics { 99 | // create initial quantifiers 100 | for param in impl_generics.params.iter() { 101 | if let GenericParam::Type(TypeParam { ident, .. }) = param { 102 | env.insert_free_quantifier(ident.to_owned()); 103 | } 104 | } 105 | 106 | // insert trait bounds 107 | for param in impl_generics.params.iter() { 108 | let predicate = param.parse_where_predicate_var(&mut env)?; 109 | env.insert_predicate(predicate); 110 | } 111 | 112 | if let Some(where_clause) = &impl_generics.where_clause { 113 | for predicate in where_clause.predicates.iter() { 114 | let predicate = predicate.parse_where_predicate_var(&mut env)?; 115 | env.insert_predicate(predicate); 116 | } 117 | } 118 | } 119 | 120 | // parse self_ty from impl block 121 | let self_ty_var = match (self_ty, inputs.first()) { 122 | (Some(self_ty), Some(FnArg::Receiver(receiver))) => { 123 | if receiver.reference.is_some() { 124 | return Err(Error::new( 125 | receiver.span(), 126 | r#"referenced receiver "&self" is not supported, use "self" instead"#, 127 | )); 128 | } 129 | Some(self_ty.parse_type_var(&mut env)?) 130 | } 131 | (Some(_), _) => { 132 | return Err(Error::new( 133 | inputs.span(), 134 | "functions inside impl block must have a self receiver", 135 | )) 136 | } 137 | (None, Some(FnArg::Receiver(receiver))) => { 138 | return Err(Error::new( 139 | receiver.span(), 140 | "functions with self receiver must be inside an impl block", 141 | )) 142 | } 143 | (None, _) => None, 144 | }; 145 | 146 | // insert free quantifiers and predicates from fn generics 147 | { 148 | // insert free quantifiers 149 | for param in fn_generics.params.iter() { 150 | if let GenericParam::Type(TypeParam { ident, .. }) = param { 151 | env.insert_free_quantifier(ident.to_owned()); 152 | } 153 | } 154 | 155 | // insert trait bounds 156 | for param in fn_generics.params.iter() { 157 | let predicate = param.parse_where_predicate_var(&mut env)?; 158 | env.insert_predicate(predicate); 159 | } 160 | 161 | if let Some(where_clause) = &fn_generics.where_clause { 162 | for predicate in where_clause.predicates.iter() { 163 | let predicate = predicate.parse_where_predicate_var(&mut env)?; 164 | env.insert_predicate(predicate); 165 | } 166 | } 167 | } 168 | 169 | // translate function arguments into types and trait bounds 170 | let (fn_args, fn_predicates): (Vec<_>, Vec<_>) = inputs 171 | .iter() 172 | .filter_map(|arg| match arg { 173 | FnArg::Typed(pat_type) => Some(pat_type), 174 | FnArg::Receiver(_) => None, 175 | }) 176 | .map(|pat_type| -> syn::Result<_> { 177 | let predicate = pat_type.parse_where_predicate_var(&mut env)?; 178 | let arg = pat_type.pat.parse_type_var(&mut env)?; 179 | env.insert_predicate(predicate.clone()); 180 | Ok((arg, predicate)) 181 | }) 182 | .try_collect::<_, Vec<_>, _>()? 183 | .into_iter() 184 | .unzip(); 185 | 186 | // translate output type to trait bound 187 | let output_bounds = match output { 188 | ReturnType::Default => None, 189 | ReturnType::Type(_, ty) => { 190 | let bounds = ty.parse_type_param_bounds_var(&mut env)?; 191 | Some(bounds) 192 | } 193 | }; 194 | 195 | // insert "self" variable if self_ty is present 196 | if let Some(var) = &self_ty_var { 197 | env.insert_bounded_quantifier(format_ident!("self"), false, var.clone()); 198 | } 199 | 200 | // translate block 201 | let mut items = vec![]; 202 | let output = translate_block(&block, &mut env, &mut items)?; 203 | 204 | // insert trait bound for output type 205 | if let Some(bounds) = &output_bounds { 206 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 207 | bounded_ty: output.clone(), 208 | bounds: bounds.to_owned(), 209 | }); 210 | 211 | env.insert_predicate(predicate); 212 | } 213 | 214 | // generate generic names 215 | let free_quantifiers = env.free_quantifiers(); 216 | let subsitution: IndexMap<_, _> = free_quantifiers 217 | .iter() 218 | .cloned() 219 | .enumerate() 220 | .map(|(index, var)| (var, format_ident!("{}GENERIC_{}", IDENT_PREFIX, index))) 221 | .collect(); 222 | let input_generics: Vec<_> = subsitution.values().collect(); 223 | 224 | // generate trait names 225 | let trait_name = format_ident!("{}", fn_name); 226 | 227 | // generate trait item 228 | let trait_item: ItemTrait = { 229 | let num_args = fn_args.len(); 230 | let args: Vec<_> = (0..num_args) 231 | .map(|idx| format_ident!("{}ARG_{}", IDENT_PREFIX, idx)) 232 | .collect(); 233 | let arg_predicates: Vec<_> = args 234 | .iter() 235 | .zip(fn_predicates.iter()) 236 | .map(|(arg, predicate)| match predicate { 237 | WherePredicateVar::Type(PredicateTypeVar { bounds, .. }) => { 238 | let bounds: Vec<_> = bounds 239 | .iter() 240 | .map(|bound| bound.substitute(&env, &subsitution)) 241 | .collect(); 242 | quote! { #arg: #(#bounds)+* } 243 | } 244 | }) 245 | .collect(); 246 | let output_predicate = output_bounds.as_ref().map(|bounds| { 247 | WherePredicateVar::Type(PredicateTypeVar { 248 | bounded_ty: syn::parse2::(quote! { Self::Output }) 249 | .unwrap() 250 | .parse_pure_type(&mut vec![]) 251 | .unwrap(), 252 | bounds: bounds.to_owned(), 253 | }) 254 | .substitute(&env, &subsitution) 255 | }); 256 | 257 | syn::parse2(quote! { 258 | #[allow(non_snake_case)] 259 | pub trait #trait_name < #(#args),* > 260 | where 261 | #(#arg_predicates,)* 262 | #output_predicate 263 | { 264 | type Output; 265 | } 266 | })? 267 | }; 268 | 269 | // generate impl items 270 | let impl_item: ItemImpl = { 271 | let input_types: Vec<_> = fn_args 272 | .iter() 273 | .map(|arg| arg.substitute(&env, &subsitution)) 274 | .collect(); 275 | let predicates: Vec<_> = env 276 | .predicates() 277 | .into_iter() 278 | .map(|predicate| predicate.substitute(&env, &subsitution)) 279 | .collect(); 280 | let output = output.substitute(&env, &subsitution); 281 | let self_ty_tokens = match &self_ty_var { 282 | Some(var) => { 283 | let subsituted = var.substitute(&env, &subsitution); 284 | quote! { #subsituted } 285 | } 286 | None => quote! { () }, 287 | }; 288 | 289 | syn::parse2(quote! { 290 | impl<#(#input_generics),*> #trait_name< #(#input_types),* > for #self_ty_tokens 291 | where 292 | #(#predicates),* 293 | { 294 | type Output = #output; 295 | } 296 | })? 297 | }; 298 | 299 | // push items to child module 300 | items.push(Item::Trait(trait_item)); 301 | items.push(Item::Impl(impl_item)); 302 | 303 | let expanded = { 304 | let num_args = fn_args.len(); 305 | let args: Vec<_> = (0..num_args) 306 | .map(|idx| format_ident!("{}ARG_{}", IDENT_PREFIX, idx)) 307 | .collect(); 308 | let mod_name = format_ident!("{}mod_{}", IDENT_PREFIX, fn_name); 309 | let type_name = format_ident!("{}Op", fn_name); 310 | let type_item = if self_ty_var.is_some() { 311 | let self_arg = format_ident!("{}SELF", IDENT_PREFIX); 312 | quote! { 313 | #vis type #type_name<#self_arg, #(#args),*> = < #self_arg as #trait_name <#(#args),*> > :: Output; 314 | } 315 | } else { 316 | quote! { 317 | #vis type #type_name<#(#args),*> = < () as #trait_name <#(#args),*> > :: Output; 318 | } 319 | }; 320 | 321 | quote! { 322 | #vis use #mod_name :: #trait_name; 323 | #type_item 324 | 325 | #[allow(non_snake_case)] 326 | mod #mod_name { 327 | use super::*; 328 | 329 | #(#items)* 330 | } 331 | } 332 | }; 333 | 334 | Ok(expanded) 335 | } 336 | -------------------------------------------------------------------------------- /src/trans/if_.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_if_expr( 4 | if_: &ExprIf, 5 | env: &mut Env, 6 | items: &mut Vec, 7 | ) -> syn::Result 8 | where 9 | { 10 | let ExprIf { 11 | cond, 12 | then_branch, 13 | else_branch, 14 | .. 15 | } = if_; 16 | 17 | // generate predicate tokens 18 | let condition = { 19 | let cond_ty = translate_expr(&*cond, env, items)?; 20 | let eq_trait: PathVar = 21 | syn::parse2::(quote! { typenum::type_operators::IsEqual }) 22 | .unwrap() 23 | .parse_pure_path(&mut vec![]) 24 | .unwrap(); 25 | let path = { 26 | let mut path = eq_trait.clone(); 27 | path.segments.push(SegmentVar { 28 | ident: format_ident!("Output"), 29 | arguments: PathArgumentsVar::None, 30 | }); 31 | path 32 | }; 33 | let output = TypeVar::Path(TypePathVar { 34 | qself: Some(QSelfVar { 35 | ty: Box::new(cond_ty.clone()), 36 | position: eq_trait.segments.len(), 37 | }), 38 | path, 39 | }); 40 | let apply_predicate = WherePredicateVar::Type(PredicateTypeVar { 41 | bounded_ty: cond_ty, 42 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 43 | modifier: TraitBoundModifierVar::None, 44 | path: eq_trait, 45 | })], 46 | }); 47 | let output_predicate = WherePredicateVar::Type(PredicateTypeVar { 48 | bounded_ty: output.clone(), 49 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 50 | modifier: TraitBoundModifierVar::None, 51 | path: syn::parse2::(quote! { typenum::marker_traits::Bit }) 52 | .unwrap() 53 | .parse_pure_path(&mut vec![]) 54 | .unwrap(), 55 | })], 56 | }); 57 | 58 | env.insert_predicate(apply_predicate); 59 | env.insert_predicate(output_predicate); 60 | 61 | output 62 | }; 63 | 64 | // save quantifiers 65 | let mutable_quantifiers = env.mutable_quantifiers(); 66 | let free_quantifiers = env.free_quantifiers(); 67 | 68 | // generate trait names 69 | let if_trait_name = env 70 | .register_trait_name(&format!("{}If_", IDENT_PREFIX)) 71 | .expect("the trait name cannot proper prefix of existing trait names"); 72 | 73 | let assign_trait_names: HashMap<_, _> = mutable_quantifiers 74 | .keys() 75 | .map(|ident| { 76 | let trait_name = env 77 | .register_trait_name(&format!("{}IfAssign_", IDENT_PREFIX)) 78 | .expect("please report bug: accidentally using a proper prefix"); 79 | (ident, trait_name) 80 | }) 81 | .collect(); 82 | 83 | // generate traits 84 | let substitution: IndexMap<_, _> = free_quantifiers 85 | .iter() 86 | .cloned() 87 | .enumerate() 88 | .map(|(index, var)| (var, format_ident!("{}GENERIC_{}", IDENT_PREFIX, index))) 89 | .collect(); 90 | let generics: Vec<_> = substitution.values().collect(); 91 | let cond_generic = format_ident!("{}CONDITION_GENERIC", IDENT_PREFIX); 92 | 93 | let if_trait_item: ItemTrait = { 94 | syn::parse2(quote! { 95 | #[allow(non_snake_case)] 96 | pub trait #if_trait_name < #(#generics,)* #cond_generic > { 97 | type Output; 98 | } 99 | })? 100 | }; 101 | 102 | let assign_trait_items: Vec = assign_trait_names 103 | .values() 104 | .map(|trait_name| { 105 | syn::parse2(quote! { 106 | #[allow(non_snake_case)] 107 | pub trait #trait_name < #(#generics,)* #cond_generic> { 108 | type Output; 109 | } 110 | }) 111 | }) 112 | .try_collect()?; 113 | 114 | // generate impl items 115 | let impls = { 116 | let impls: Vec = match else_branch { 117 | Some((_else, else_expr)) => { 118 | let if_impls: Vec<_> = { 119 | let mut branched_env = env.branch(); 120 | let then_output = translate_block(then_branch, &mut branched_env, items)? 121 | .substitute(&branched_env, &substitution); 122 | let predicates: Vec<_> = branched_env 123 | .predicates() 124 | .into_iter() 125 | .map(|predicate| predicate.substitute(&branched_env, &substitution)) 126 | .collect(); 127 | 128 | let body_impl: ItemImpl = { 129 | let trait_ = quote! { #if_trait_name<#(#generics,)* typenum::B1> }; 130 | let impl_ = quote! { 131 | impl< #(#generics),* > #trait_ for () 132 | where 133 | #(#predicates),* 134 | { 135 | type Output = #then_output; 136 | } 137 | }; 138 | syn::parse2(impl_)? 139 | }; 140 | 141 | let assign_impls: Vec = mutable_quantifiers 142 | .keys() 143 | .map(|ident| { 144 | let trait_name = &assign_trait_names[ident]; 145 | let output = branched_env 146 | .get_variable(ident) 147 | .expect("please report bug: the variable is missing") 148 | .value 149 | .as_ref() 150 | .unwrap() 151 | .substitute(&branched_env, &substitution); 152 | let trait_ = quote! { #trait_name<#(#generics,)* typenum::B1> }; 153 | let impl_ = quote! { 154 | impl< #(#generics),* > #trait_ for () 155 | where 156 | #(#predicates),* 157 | { 158 | type Output = #output; 159 | } 160 | }; 161 | syn::parse2(impl_) 162 | }) 163 | .try_collect()?; 164 | 165 | iter::once(body_impl).chain(assign_impls).collect() 166 | }; 167 | 168 | let else_impls: Vec<_> = { 169 | let mut branched_env = env.branch(); 170 | let else_output = translate_expr(&**else_expr, &mut branched_env, items)? 171 | .substitute(&branched_env, &substitution); 172 | let predicates: Vec<_> = branched_env 173 | .predicates() 174 | .into_iter() 175 | .map(|predicate| predicate.substitute(&branched_env, &substitution)) 176 | .collect(); 177 | 178 | let body_impl: ItemImpl = { 179 | let trait_ = quote! { #if_trait_name<#(#generics,)* typenum::B0> }; 180 | let body_impl = quote! { 181 | impl< #(#generics),* > #trait_ for () 182 | where 183 | #(#predicates),* 184 | { 185 | type Output = #else_output; 186 | } 187 | }; 188 | syn::parse2(body_impl)? 189 | }; 190 | 191 | let assign_impls: Vec = mutable_quantifiers 192 | .keys() 193 | .map(|ident| { 194 | let trait_name = &assign_trait_names[ident]; 195 | let value = branched_env 196 | .get_variable(ident) 197 | .expect("please report bug: the variable is missing") 198 | .value 199 | .as_ref() 200 | .unwrap() 201 | .substitute(&env, &substitution); 202 | let trait_ = quote! { #trait_name<#(#generics,)* typenum::B0> }; 203 | let impl_ = quote! { 204 | impl< #(#generics),* > #trait_ for () 205 | where 206 | #(#predicates),* 207 | { 208 | type Output = #value; 209 | } 210 | }; 211 | syn::parse2(impl_) 212 | }) 213 | .try_collect()?; 214 | 215 | iter::once(body_impl).chain(assign_impls).collect() 216 | }; 217 | 218 | if_impls.into_iter().chain(else_impls).collect() 219 | } 220 | None => { 221 | let if_impls: Vec<_> = { 222 | let mut branched_env = env.branch(); 223 | translate_block(then_branch, &mut branched_env, items)?; 224 | let predicates: Vec<_> = branched_env 225 | .predicates() 226 | .into_iter() 227 | .map(|predicate| predicate.substitute(&branched_env, &substitution)) 228 | .collect(); 229 | 230 | let body_impl: ItemImpl = { 231 | let trait_ = quote! { #if_trait_name<#(#generics,)* typenum::B1> }; 232 | let impl_ = quote! { 233 | impl< #(#generics),* > #trait_ for () 234 | where 235 | #(#predicates),* 236 | { 237 | type Output = (); 238 | } 239 | }; 240 | syn::parse2(impl_)? 241 | }; 242 | 243 | // insert trait bound 244 | let assign_impls: Vec = mutable_quantifiers 245 | .keys() 246 | .map(|ident| { 247 | let trait_name = &assign_trait_names[ident]; 248 | let value = branched_env 249 | .get_variable(ident) 250 | .expect("please report bug: the variable is missing") 251 | .value 252 | .as_ref() 253 | .unwrap() 254 | .substitute(&branched_env, &substitution); 255 | let trait_ = quote! { #trait_name<#(#generics,)* typenum::B1> }; 256 | let impl_ = quote! { 257 | impl< #(#generics),* > #trait_ for () 258 | where 259 | #(#predicates),* 260 | { 261 | type Output = #value; 262 | } 263 | }; 264 | syn::parse2(impl_) 265 | }) 266 | .try_collect()?; 267 | 268 | iter::once(body_impl).chain(assign_impls).collect() 269 | }; 270 | 271 | let else_impls: Vec<_> = { 272 | let predicates: Vec<_> = env 273 | .predicates() 274 | .into_iter() 275 | .map(|predicate| predicate.substitute(env, &substitution)) 276 | .collect(); 277 | 278 | let body_impl: ItemImpl = { 279 | let trait_ = quote! { #if_trait_name<#(#generics,)* typenum::B0> }; 280 | let impl_ = quote! { 281 | impl< #(#generics),* > #trait_ for () 282 | where 283 | #(#predicates),* 284 | { 285 | type Output = (); 286 | } 287 | }; 288 | syn::parse2(impl_)? 289 | }; 290 | 291 | let assign_impls: Vec = mutable_quantifiers 292 | .keys() 293 | .map(|ident| { 294 | let trait_name = &assign_trait_names[ident]; 295 | let value = &env 296 | .get_variable(ident) 297 | .expect("please report bug: the variable is missing") 298 | .value 299 | .as_ref() 300 | .unwrap() 301 | .substitute(&env, &substitution); 302 | let trait_ = quote! { #trait_name<#(#generics,)* typenum::B0> }; 303 | let impl_ = quote! { 304 | impl< #(#generics),* > #trait_ for () 305 | where 306 | #(#predicates),* 307 | { 308 | type Output = #value; 309 | } 310 | }; 311 | syn::parse2(impl_) 312 | }) 313 | .try_collect()?; 314 | 315 | iter::once(body_impl).chain(assign_impls).collect() 316 | }; 317 | 318 | if_impls.into_iter().chain(else_impls).collect() 319 | } 320 | }; 321 | 322 | impls 323 | }; 324 | 325 | // assign affected variables 326 | for ident in mutable_quantifiers.keys() { 327 | let trait_name = &assign_trait_names[ident]; 328 | let args: Vec<_> = free_quantifiers 329 | .iter() 330 | .map(|var| TypeVar::Var(var.clone())) 331 | .chain(iter::once(condition.clone())) 332 | .collect(); 333 | let trait_ = PathVar { 334 | segments: vec![SegmentVar { 335 | ident: trait_name.to_owned(), 336 | arguments: PathArgumentsVar::AngleBracketed(args), 337 | }], 338 | }; 339 | let path = { 340 | let mut path = trait_.clone(); 341 | path.segments.push(SegmentVar { 342 | ident: format_ident!("Output"), 343 | arguments: PathArgumentsVar::None, 344 | }); 345 | path 346 | }; 347 | let bounded_ty: TypeVar = syn::parse2::(quote! { () }) 348 | .unwrap() 349 | .parse_pure_type(&mut vec![]) 350 | .unwrap(); 351 | let value = TypeVar::Path(TypePathVar { 352 | qself: Some(QSelfVar { 353 | ty: Box::new(bounded_ty.clone()), 354 | position: trait_.segments.len(), 355 | }), 356 | path, 357 | }); 358 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 359 | bounded_ty, 360 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 361 | modifier: TraitBoundModifierVar::None, 362 | path: trait_, 363 | })], 364 | }); 365 | 366 | env.assign_quantifier(ident, value)?; 367 | env.insert_predicate(predicate); 368 | } 369 | 370 | // construct output 371 | let output = { 372 | let args: Vec<_> = free_quantifiers 373 | .iter() 374 | .map(|var| TypeVar::Var(var.clone())) 375 | .chain(iter::once(condition)) 376 | .collect(); 377 | let trait_ = PathVar { 378 | segments: vec![SegmentVar { 379 | ident: if_trait_name.to_owned(), 380 | arguments: PathArgumentsVar::AngleBracketed(args), 381 | }], 382 | }; 383 | let path = { 384 | let mut path = trait_.clone(); 385 | path.segments.push(SegmentVar { 386 | ident: format_ident!("Output"), 387 | arguments: PathArgumentsVar::None, 388 | }); 389 | path 390 | }; 391 | let bounded_ty: TypeVar = syn::parse2::(quote! { () }) 392 | .unwrap() 393 | .parse_pure_type(&mut vec![]) 394 | .unwrap(); 395 | let output = TypeVar::Path(TypePathVar { 396 | qself: Some(QSelfVar { 397 | ty: Box::new(bounded_ty.clone()), 398 | position: trait_.segments.len(), 399 | }), 400 | path, 401 | }); 402 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 403 | bounded_ty, 404 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 405 | modifier: TraitBoundModifierVar::None, 406 | path: trait_, 407 | })], 408 | }); 409 | 410 | env.insert_predicate(predicate); 411 | output 412 | }; 413 | 414 | // add items to env 415 | items.push(Item::Trait(if_trait_item)); 416 | items.extend(assign_trait_items.into_iter().map(Item::Trait)); 417 | items.extend(impls.into_iter().map(Item::Impl)); 418 | 419 | Ok(output) 420 | } 421 | -------------------------------------------------------------------------------- /src/trans/impl_.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_impl(impl_: &ItemImpl) -> syn::Result { 4 | let ItemImpl { 5 | defaultness, 6 | unsafety, 7 | generics, 8 | trait_, 9 | self_ty, 10 | items, 11 | .. 12 | } = impl_; 13 | 14 | // sanity check 15 | if let Some(defaultness) = defaultness { 16 | return Err(Error::new( 17 | defaultness.span(), 18 | "default keyword is not supported", 19 | )); 20 | } 21 | if let Some(unsafety) = unsafety { 22 | return Err(Error::new( 23 | unsafety.span(), 24 | "unsafe keyword is not supported", 25 | )); 26 | } 27 | if trait_.is_some() { 28 | return Err(Error::new( 29 | impl_.span(), 30 | r#""for Trait" clause is not supported"#, 31 | )); 32 | } 33 | 34 | let items_tokens: Vec<_> = items 35 | .iter() 36 | .map(|item| -> syn::Result<_> { 37 | let tokens = match item { 38 | ImplItem::Method(method) => { 39 | let ImplItemMethod { 40 | sig, block, vis, .. 41 | } = method; 42 | translate_fn(vis, sig, block, Some(&**self_ty), Some(generics))? 43 | } 44 | _ => { 45 | return Err(Error::new(item.span(), "unsupported item")); 46 | } 47 | }; 48 | 49 | Ok(tokens) 50 | }) 51 | .try_collect()?; 52 | 53 | let expanded = quote! { #(#items_tokens)* }; 54 | Ok(expanded) 55 | } 56 | -------------------------------------------------------------------------------- /src/trans/lit.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_lit_expr( 4 | expr: &ExprLit, 5 | _env: &mut Env, 6 | _items: &mut Vec, 7 | ) -> syn::Result { 8 | let ExprLit { lit, .. } = expr; 9 | 10 | // parse literal 11 | let lit_tokens = match lit { 12 | Lit::Bool(LitBool { value, .. }) => { 13 | if *value { 14 | quote! { typenum::B1 } 15 | } else { 16 | quote! { typenum::B0 } 17 | } 18 | } 19 | Lit::Int(int_) => match int_.suffix() { 20 | "" | "i" => { 21 | let value: u128 = int_.base10_parse()?; 22 | if value == 0 { 23 | quote! { typenum::Z0 } 24 | } else { 25 | let ty = int_to_typenum(value); 26 | quote! { typenum::int::PInt<#ty> } 27 | } 28 | } 29 | "u" => { 30 | let value: u128 = int_.base10_parse()?; 31 | let ty = int_to_typenum(value); 32 | ty 33 | } 34 | _ => return Err(Error::new(int_.span(), "unsupported literal suffix")), 35 | }, 36 | _ => return Err(Error::new(lit.span(), "unsupported literal")), 37 | }; 38 | let lit_ty: TypeVar = syn::parse2::(lit_tokens) 39 | .unwrap() 40 | .parse_pure_type(&mut vec![]) 41 | .unwrap(); 42 | 43 | Ok(lit_ty) 44 | } 45 | 46 | fn int_to_typenum(value: u128) -> TokenStream { 47 | if value == 0 { 48 | quote! { 49 | typenum::uint::UTerm 50 | } 51 | } else if value & 1 == 1 { 52 | let sub_tokens = int_to_typenum(value >> 1); 53 | quote! { 54 | typenum::uint::UInt<#sub_tokens, typenum::B1> 55 | } 56 | } else { 57 | let sub_tokens = int_to_typenum(value >> 1); 58 | quote! { 59 | typenum::uint::UInt<#sub_tokens, typenum::B0> 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/trans/match_.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | struct ArmAttributes { 4 | pub generics_attr: Option, 5 | pub capture_attr: Option, 6 | pub default_attr: Option<()>, 7 | } 8 | 9 | pub fn translate_match_expr( 10 | match_: &ExprMatch, 11 | env: &mut Env, 12 | items: &mut Vec, 13 | ) -> syn::Result 14 | where 15 | { 16 | let ExprMatch { expr, arms, .. } = match_; 17 | 18 | // parse matched expression 19 | let pattern = translate_expr(&**expr, env, items)?; 20 | 21 | // save quantifiers (after matched expression) 22 | let mutable_quantifiers = env.mutable_quantifiers(); 23 | 24 | // generate trait names 25 | let match_trait_name = env 26 | .register_trait_name(&format!("{}MatchArm_", IDENT_PREFIX)) 27 | .expect("the trait name cannot proper prefix of existing trait names"); 28 | 29 | let assign_trait_names: HashMap<_, _> = mutable_quantifiers 30 | .keys() 31 | .map(|ident| { 32 | let trait_name = env 33 | .register_trait_name(&format!("{}MatchAssign_", IDENT_PREFIX)) 34 | .expect("please report bug: accidentally using a proper prefix"); 35 | (ident, trait_name) 36 | }) 37 | .collect(); 38 | 39 | // generate generics 40 | let parent_free_quantifiers = env.free_quantifiers(); 41 | let parent_substitution: IndexMap<_, _> = parent_free_quantifiers 42 | .iter() 43 | .cloned() 44 | .enumerate() 45 | .map(|(index, var)| (var, format_ident!("{}GENERIC_{}", IDENT_PREFIX, index))) 46 | .collect(); 47 | let parent_generics: Vec<_> = parent_substitution.values().collect(); 48 | 49 | // generate traits 50 | let (match_trait_item, assign_trait_items) = { 51 | let cond_generic = format_ident!("{}_CONDITION_GENERIC", IDENT_PREFIX); 52 | 53 | let match_trait_item: ItemTrait = syn::parse2(quote! { 54 | #[allow(non_snake_case)] 55 | pub trait #match_trait_name < #(#parent_generics,)* #cond_generic> { 56 | type Output; 57 | } 58 | })?; 59 | 60 | let assign_trait_items: Vec = assign_trait_names 61 | .values() 62 | .map(|trait_name| { 63 | syn::parse2(quote! { 64 | #[allow(non_snake_case)] 65 | pub trait #trait_name < #(#parent_generics,)* #cond_generic> { 66 | type Output; 67 | } 68 | }) 69 | }) 70 | .try_collect()?; 71 | 72 | (match_trait_item, assign_trait_items) 73 | }; 74 | 75 | // generate impl items 76 | let impl_items = { 77 | let impl_items: Vec<_> = arms 78 | .iter() 79 | .map( 80 | |Arm { 81 | attrs, pat, body, .. 82 | }| 83 | -> syn::Result<_> { 84 | let mut branched_env = env.branch(); 85 | 86 | // parse attributes 87 | let ArmAttributes { 88 | generics_attr, 89 | capture_attr, 90 | default_attr, 91 | } = unpack_pat_attr(attrs)?; 92 | 93 | // insert new free quantifiers and predicates 94 | let extra_free_quantifiers = match &generics_attr { 95 | Some(GenericsAttr { params }) => { 96 | let free_quantifiers: IndexSet<_> = params 97 | .iter() 98 | .map(|param| -> syn::Result<_> { 99 | let SimpleTypeParam { ident, .. } = param; 100 | let var = branched_env.insert_free_quantifier(ident.to_owned()); 101 | let predicate = 102 | param.parse_where_predicate_var(&mut branched_env)?; 103 | branched_env.insert_predicate(predicate); 104 | Ok(var) 105 | }) 106 | .try_collect()?; 107 | free_quantifiers 108 | } 109 | None => IndexSet::new(), 110 | }; 111 | 112 | // insert new predicates for captured variables 113 | match &capture_attr { 114 | Some(CaptureAttr { params }) => { 115 | for param in params.iter() { 116 | let predicate = 117 | param.parse_where_predicate_var(&mut branched_env)?; 118 | branched_env.insert_predicate(predicate); 119 | } 120 | } 121 | None => (), 122 | } 123 | 124 | // generate substitutions for free variables 125 | let substitution: IndexMap<_, _> = branched_env 126 | .free_quantifiers() 127 | .iter() 128 | .cloned() 129 | .enumerate() 130 | .map(|(index, var)| { 131 | (var, format_ident!("{}GENERIC_{}", IDENT_PREFIX, index)) 132 | }) 133 | .collect(); 134 | 135 | // generate generic identifiers 136 | let input_generics: Vec<_> = substitution 137 | .iter() 138 | .filter_map(|(var, generic)| { 139 | if extra_free_quantifiers.contains(var) { 140 | None 141 | } else { 142 | Some(generic) 143 | } 144 | }) 145 | .collect(); 146 | let all_generics: Vec<_> = substitution.values().collect(); 147 | 148 | // parse body 149 | let target = { 150 | // list in-place free and captured variables 151 | let mut variables = HashMap::new(); 152 | 153 | if let Some(CaptureAttr { params }) = capture_attr { 154 | let vars: Vec<_> = params 155 | .iter() 156 | .map(|SimpleTypeParam { ident, .. }| { 157 | branched_env 158 | .get_variable(ident) 159 | .map(|var| (ident.to_owned(), var)) 160 | .ok_or_else(|| { 161 | Error::new(ident.span(), "the variable is not defined") 162 | }) 163 | }) 164 | .try_collect()?; 165 | variables.extend(vars); 166 | }; 167 | 168 | if let Some(GenericsAttr { params }) = generics_attr { 169 | let iter = params.iter().map(|SimpleTypeParam { ident, .. }| { 170 | branched_env 171 | .get_variable(ident) 172 | .map(|var| (ident.to_owned(), var)) 173 | .unwrap() 174 | }); 175 | variables.extend(iter); 176 | }; 177 | 178 | // parse target 179 | parse_pattern::parse_type_pattern_from_pat(pat, &variables)? 180 | .substitute(&branched_env, &substitution) 181 | }; 182 | let body_value = translate_expr(body, &mut branched_env, items)? 183 | .substitute(&branched_env, &substitution); 184 | let predicates: Vec<_> = branched_env 185 | .predicates() 186 | .into_iter() 187 | .map(|predicate| predicate.substitute(&branched_env, &substitution)) 188 | .collect(); 189 | 190 | // impl item for output type 191 | let match_impl: ItemImpl = { 192 | let trait_ = quote!( #match_trait_name<#(#input_generics,)* #target> ); 193 | let default_ = if let Some(()) = default_attr { 194 | quote! { default } 195 | } else { 196 | quote! {} 197 | }; 198 | let impl_ = quote! { 199 | impl< #(#all_generics),* > #trait_ for () 200 | where 201 | #(#predicates),* 202 | { 203 | #default_ type Output = #body_value; 204 | } 205 | }; 206 | syn::parse2(impl_)? 207 | }; 208 | 209 | // impls for variable assignments 210 | let assign_impls: Vec = mutable_quantifiers 211 | .keys() 212 | .map(|ident| { 213 | let trait_name = &assign_trait_names[ident]; 214 | let value = branched_env 215 | .get_variable(ident) 216 | .expect("please report bug: the variable is missing") 217 | .value 218 | .as_ref() 219 | .unwrap() 220 | .substitute(&branched_env, &substitution); 221 | let trait_ = quote! { #trait_name< #(#input_generics,)* #target > }; 222 | let impl_ = quote! { 223 | impl< #(#all_generics),* > #trait_ for () 224 | where 225 | #(#predicates),* 226 | { 227 | type Output = #value; 228 | } 229 | }; 230 | syn::parse2(impl_) 231 | }) 232 | .try_collect()?; 233 | 234 | let impls: Vec<_> = iter::once(match_impl).chain(assign_impls).collect(); 235 | Ok(impls) 236 | }, 237 | ) 238 | .collect::, _>>()? 239 | .into_iter() 240 | .flatten() 241 | .collect(); 242 | 243 | impl_items 244 | }; 245 | 246 | // add items to env 247 | items.push(Item::Trait(match_trait_item)); 248 | items.extend(assign_trait_items.into_iter().map(Item::Trait)); 249 | items.extend(impl_items.into_iter().map(Item::Impl)); 250 | 251 | // assign affected variables 252 | for ident in mutable_quantifiers.keys() { 253 | let trait_name = &assign_trait_names[ident]; 254 | let args: Vec<_> = parent_free_quantifiers 255 | .iter() 256 | .map(|var| TypeVar::Var(var.clone())) 257 | .chain(iter::once(pattern.clone())) 258 | .collect(); 259 | let trait_ = PathVar { 260 | segments: vec![SegmentVar { 261 | ident: trait_name.to_owned(), 262 | arguments: PathArgumentsVar::AngleBracketed(args), 263 | }], 264 | }; 265 | let path = { 266 | let mut path = trait_.clone(); 267 | path.segments.push(SegmentVar { 268 | ident: format_ident!("Output"), 269 | arguments: PathArgumentsVar::None, 270 | }); 271 | path 272 | }; 273 | let bounded_ty: TypeVar = syn::parse2::(quote! { () }) 274 | .unwrap() 275 | .parse_pure_type(&mut vec![]) 276 | .unwrap(); 277 | let value = TypeVar::Path(TypePathVar { 278 | qself: Some(QSelfVar { 279 | ty: Box::new(bounded_ty.clone()), 280 | position: trait_.segments.len(), 281 | }), 282 | path, 283 | }); 284 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 285 | bounded_ty, 286 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 287 | modifier: TraitBoundModifierVar::None, 288 | path: trait_, 289 | })], 290 | }); 291 | 292 | env.assign_quantifier(ident, value)?; 293 | env.insert_predicate(predicate); 294 | } 295 | 296 | // construct returned value 297 | let output = { 298 | let args: Vec<_> = parent_free_quantifiers 299 | .iter() 300 | .map(|var| TypeVar::Var(var.clone())) 301 | .chain(iter::once(pattern)) 302 | .collect(); 303 | let trait_ = PathVar { 304 | segments: vec![SegmentVar { 305 | ident: match_trait_name.to_owned(), 306 | arguments: PathArgumentsVar::AngleBracketed(args), 307 | }], 308 | }; 309 | let path = { 310 | let mut path = trait_.clone(); 311 | path.segments.push(SegmentVar { 312 | ident: format_ident!("Output"), 313 | arguments: PathArgumentsVar::None, 314 | }); 315 | path 316 | }; 317 | let bounded_ty: TypeVar = syn::parse2::(quote! { () }) 318 | .unwrap() 319 | .parse_pure_type(&mut vec![]) 320 | .unwrap(); 321 | let output = TypeVar::Path(TypePathVar { 322 | qself: Some(QSelfVar { 323 | ty: Box::new(bounded_ty.clone()), 324 | position: trait_.segments.len(), 325 | }), 326 | path, 327 | }); 328 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 329 | bounded_ty, 330 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 331 | modifier: TraitBoundModifierVar::None, 332 | path: trait_, 333 | })], 334 | }); 335 | 336 | env.insert_predicate(predicate); 337 | output 338 | }; 339 | 340 | Ok(output) 341 | } 342 | 343 | fn unpack_pat_attr(attrs: &[Attribute]) -> syn::Result { 344 | let mut generics_attr = None; 345 | let mut capture_attr = None; 346 | let mut default_attr = None; 347 | 348 | // check attributes one by one 349 | for attr in attrs.iter() { 350 | let Attribute { style, path, .. } = attr; 351 | 352 | // sanity check 353 | match (style, path.get_ident()) { 354 | (AttrStyle::Outer, Some(ident)) => match ident.to_string().as_str() { 355 | "generics" => match generics_attr { 356 | Some(_) => { 357 | return Err(Error::new( 358 | path.span(), 359 | "the generics attribute is defined more than once", 360 | )); 361 | } 362 | None => generics_attr = Some(attr), 363 | }, 364 | "capture" => match capture_attr { 365 | Some(_) => { 366 | return Err(Error::new( 367 | path.span(), 368 | "the capture attribute is defined more than once", 369 | )); 370 | } 371 | None => capture_attr = Some(attr), 372 | }, 373 | "default" => match default_attr { 374 | Some(_) => { 375 | return Err(Error::new( 376 | path.span(), 377 | "the default attribute is defined more than once", 378 | )); 379 | } 380 | None => default_attr = Some(()), 381 | }, 382 | _ => return Err(Error::new(path.span(), "unsupported attribute")), 383 | }, 384 | (AttrStyle::Outer, None) => { 385 | return Err(Error::new(path.span(), "unsupported attribute")); 386 | } 387 | (AttrStyle::Inner(_), _) => { 388 | return Err(Error::new(attr.span(), "inner attribute is not supported")) 389 | } 390 | } 391 | } 392 | 393 | // parse 394 | let generics_attr: Option = generics_attr 395 | .map(|attr| syn::parse2(attr.tokens.to_owned())) 396 | .transpose()?; 397 | let capture_attr: Option = capture_attr 398 | .map(|attr| syn::parse2(attr.tokens.to_owned())) 399 | .transpose()?; 400 | 401 | // sanity check 402 | match (&generics_attr, &capture_attr) { 403 | (Some(generics_attr), Some(capture_attr)) => { 404 | let generic_idents: HashSet<_> = generics_attr 405 | .params 406 | .iter() 407 | .map(|param| ¶m.ident) 408 | .collect(); 409 | for SimpleTypeParam { 410 | ident: capture_ident, 411 | .. 412 | } in capture_attr.params.iter() 413 | { 414 | if let Some(generic_ident) = generic_idents.get(capture_ident) { 415 | let mut err = Error::new( 416 | capture_ident.span(), 417 | "cannot capture a variable already in generics list", 418 | ); 419 | err.combine(Error::new( 420 | generic_ident.span(), 421 | "the name is declared as a generic here", 422 | )); 423 | return Err(err); 424 | } 425 | } 426 | } 427 | _ => (), 428 | } 429 | 430 | Ok(ArmAttributes { 431 | generics_attr, 432 | capture_attr, 433 | default_attr, 434 | }) 435 | } 436 | 437 | mod parse_pattern { 438 | use super::*; 439 | 440 | pub fn parse_type_pattern_from_pat( 441 | pat: &Pat, 442 | captured: &HashMap>, 443 | ) -> syn::Result { 444 | match pat { 445 | Pat::Ident(pat_ident) => { 446 | // sanity check 447 | let PatIdent { 448 | ident, 449 | by_ref, 450 | mutability, 451 | subpat, 452 | .. 453 | } = pat_ident; 454 | 455 | if let Some(by_ref) = by_ref { 456 | return Err(Error::new(by_ref.span(), "ref keyword is not supported")); 457 | } 458 | 459 | if let Some(mutability) = mutability { 460 | return Err(Error::new( 461 | mutability.span(), 462 | "mut keyword is not supported", 463 | )); 464 | } 465 | 466 | if let Some(_) = subpat { 467 | return Err(Error::new(pat_ident.span(), "subpattern is not supported")); 468 | } 469 | 470 | parse_type_pattern_from_ident(ident, captured) 471 | } 472 | Pat::Path(PatPath { qself, path, .. }) => { 473 | let qself = match qself { 474 | Some(QSelf { ty, position, .. }) => { 475 | let ty = parse_type_pattern(ty, captured)?; 476 | Some(QSelfVar { 477 | ty: Box::new(ty), 478 | position: *position, 479 | }) 480 | } 481 | None => None, 482 | }; 483 | let path = parse_path_pattern(path, captured)?; 484 | Ok(TypeVar::Path(TypePathVar { qself, path })) 485 | } 486 | Pat::Tuple(PatTuple { elems, .. }) => { 487 | let elems: Vec<_> = elems 488 | .iter() 489 | .map(|elem| parse_type_pattern_from_pat(elem, captured)) 490 | .try_collect()?; 491 | Ok(TypeVar::Tuple(TypeTupleVar { elems })) 492 | } 493 | _ => Err(Error::new(pat.span(), "not a type")), 494 | } 495 | } 496 | 497 | pub fn parse_type_pattern( 498 | type_: &Type, 499 | captured: &HashMap>, 500 | ) -> syn::Result { 501 | let ty = match type_ { 502 | Type::Path(TypePath { qself, path }) => match (qself, path.get_ident()) { 503 | (Some(QSelf { ty, position, .. }), _) => { 504 | let ty = parse_type_pattern(ty, captured)?; 505 | let path = parse_path_pattern(path, captured)?; 506 | TypeVar::Path(TypePathVar { 507 | qself: Some(QSelfVar { 508 | ty: Box::new(ty), 509 | position: *position, 510 | }), 511 | path, 512 | }) 513 | } 514 | (None, Some(ident)) => match captured.get(ident) { 515 | Some(var) => TypeVar::Var(var.to_owned()), 516 | None => { 517 | let path = parse_path_pattern(path, captured)?; 518 | TypeVar::Path(TypePathVar { qself: None, path }) 519 | } 520 | }, 521 | (None, None) => { 522 | let path = parse_path_pattern(path, captured)?; 523 | TypeVar::Path(TypePathVar { qself: None, path }) 524 | } 525 | }, 526 | Type::Tuple(TypeTuple { elems, .. }) => { 527 | let elems: Vec<_> = elems 528 | .iter() 529 | .map(|elem| parse_type_pattern(elem, captured)) 530 | .try_collect()?; 531 | TypeVar::Tuple(TypeTupleVar { elems }) 532 | } 533 | Type::Paren(TypeParen { elem, .. }) => parse_type_pattern(elem, captured)?, 534 | _ => return Err(Error::new(type_.span(), "unsupported type variant")), 535 | }; 536 | Ok(ty) 537 | } 538 | 539 | pub fn parse_type_pattern_from_ident( 540 | ident: &Ident, 541 | captured: &HashMap>, 542 | ) -> syn::Result { 543 | match captured.get(ident) { 544 | Some(var) => Ok(TypeVar::Var(var.to_owned())), 545 | None => Ok(TypeVar::Path(TypePathVar { 546 | qself: None, 547 | path: PathVar { 548 | segments: vec![SegmentVar { 549 | ident: ident.to_owned(), 550 | arguments: PathArgumentsVar::None, 551 | }], 552 | }, 553 | })), 554 | } 555 | } 556 | 557 | pub fn parse_path_pattern( 558 | path: &Path, 559 | captured: &HashMap>, 560 | ) -> syn::Result { 561 | let Path { segments, .. } = path; 562 | let segments: Vec<_> = segments 563 | .iter() 564 | .map(|segment| parse_segment_pattern(segment, captured)) 565 | .try_collect()?; 566 | Ok(PathVar { segments }) 567 | } 568 | 569 | pub fn parse_segment_pattern( 570 | segment: &PathSegment, 571 | captured: &HashMap>, 572 | ) -> syn::Result { 573 | let PathSegment { ident, arguments } = segment; 574 | let arguments = match arguments { 575 | PathArguments::None => PathArgumentsVar::None, 576 | PathArguments::AngleBracketed(args) => { 577 | let args = args 578 | .args 579 | .iter() 580 | .map(|arg| match arg { 581 | GenericArgument::Type(ty) => parse_type_pattern(ty, captured), 582 | _ => Err(Error::new(arg.span(), "unsupported generic variant")), 583 | }) 584 | .try_collect()?; 585 | PathArgumentsVar::AngleBracketed(args) 586 | } 587 | PathArguments::Parenthesized(args) => { 588 | let inputs = args 589 | .inputs 590 | .iter() 591 | .map(|ty| parse_type_pattern(ty, captured)) 592 | .try_collect()?; 593 | PathArgumentsVar::Parenthesized(inputs) 594 | } 595 | }; 596 | 597 | Ok(SegmentVar { 598 | ident: ident.to_owned(), 599 | arguments, 600 | }) 601 | } 602 | } 603 | -------------------------------------------------------------------------------- /src/trans/misc.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_expr(expr: &Expr, scope: &mut Env, items: &mut Vec) -> syn::Result 4 | where 5 | { 6 | let ret = match expr { 7 | Expr::Match(match_) => translate_match_expr(match_, scope, items), 8 | Expr::Path(path) => translate_path_expr(path, scope, items), 9 | Expr::Tuple(tuple) => translate_tuple_expr(tuple, scope, items), 10 | Expr::Binary(binop) => translate_binary_expr(binop, scope, items), 11 | Expr::If(if_) => translate_if_expr(if_, scope, items), 12 | Expr::Block(block) => translate_block_expr(block, scope, items), 13 | Expr::Call(call) => translate_call_expr(call, scope, items), 14 | Expr::Paren(paren) => translate_expr(&paren.expr, scope, items), 15 | Expr::Assign(assign) => translate_assign_expr(assign, scope, items), 16 | Expr::Lit(lit) => translate_lit_expr(lit, scope, items), 17 | Expr::Unary(unary) => translate_unary_expr(unary, scope, items), 18 | Expr::Index(index) => translate_index_expr(index, scope, items), 19 | Expr::MethodCall(call) => translate_method_call_expr(call, scope, items), 20 | _ => Err(Error::new(expr.span(), "unsupported expression")), 21 | }; 22 | ret 23 | } 24 | 25 | pub fn translate_method_call_expr( 26 | call: &ExprMethodCall, 27 | env: &mut Env, 28 | items: &mut Vec, 29 | ) -> syn::Result { 30 | let ExprMethodCall { 31 | receiver, 32 | method, 33 | turbofish, 34 | args, 35 | .. 36 | } = call; 37 | 38 | // translate to types 39 | if let Some(turbofish) = turbofish { 40 | return Err(Error::new(turbofish.span(), "turbofish is not supported")); 41 | } 42 | 43 | let receiver_ty = translate_expr(&**receiver, env, items)?; 44 | let arg_tys: Vec<_> = args 45 | .iter() 46 | .map(|arg| translate_expr(arg, env, items)) 47 | .try_collect()?; 48 | let trait_ = PathVar { 49 | segments: vec![SegmentVar { 50 | ident: method.clone(), 51 | arguments: PathArgumentsVar::AngleBracketed(arg_tys), 52 | }], 53 | }; 54 | let path = { 55 | let mut path = trait_.clone(); 56 | path.segments.push(SegmentVar { 57 | ident: format_ident!("Output"), 58 | arguments: PathArgumentsVar::None, 59 | }); 60 | path 61 | }; 62 | 63 | let output = TypeVar::Path(TypePathVar { 64 | qself: Some(QSelfVar { 65 | ty: Box::new(receiver_ty.clone()), 66 | position: trait_.segments.len(), 67 | }), 68 | path, 69 | }); 70 | 71 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 72 | bounded_ty: receiver_ty, 73 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 74 | modifier: TraitBoundModifierVar::None, 75 | path: trait_, 76 | })], 77 | }); 78 | 79 | env.insert_predicate(predicate); 80 | 81 | Ok(output) 82 | } 83 | 84 | pub fn translate_index_expr( 85 | expr: &ExprIndex, 86 | env: &mut Env, 87 | items: &mut Vec, 88 | ) -> syn::Result 89 | where 90 | { 91 | let ExprIndex { expr, index, .. } = expr; 92 | let operand = translate_expr(expr, env, items)?; 93 | let index = translate_expr(index, env, items)?; 94 | 95 | let trait_ = { 96 | let mut path: PathVar = syn::parse2::(quote! { core::ops::Index }) 97 | .unwrap() 98 | .parse_pure_path(&mut vec![]) 99 | .unwrap(); 100 | path.segments.last_mut().unwrap().arguments = PathArgumentsVar::AngleBracketed(vec![index]); 101 | path 102 | }; 103 | let path = { 104 | let mut path = trait_.clone(); 105 | path.segments.push(SegmentVar { 106 | ident: format_ident!("Output"), 107 | arguments: PathArgumentsVar::None, 108 | }); 109 | path 110 | }; 111 | let output = TypeVar::Path(TypePathVar { 112 | qself: Some(QSelfVar { 113 | ty: Box::new(operand.clone()), 114 | position: trait_.segments.len(), 115 | }), 116 | path, 117 | }); 118 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 119 | bounded_ty: operand, 120 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 121 | modifier: TraitBoundModifierVar::None, 122 | path: trait_, 123 | })], 124 | }); 125 | 126 | env.insert_predicate(predicate); 127 | Ok(output) 128 | } 129 | 130 | pub fn translate_path_expr( 131 | expr: &ExprPath, 132 | scope: &mut Env, 133 | _items: &mut Vec, 134 | ) -> syn::Result 135 | where 136 | { 137 | expr.parse_type_var(scope) 138 | } 139 | 140 | pub fn translate_tuple_expr( 141 | tuple: &ExprTuple, 142 | scope: &mut Env, 143 | items: &mut Vec, 144 | ) -> syn::Result 145 | where 146 | { 147 | // translate each element 148 | let elems: Vec<_> = tuple 149 | .elems 150 | .iter() 151 | .map(|expr| translate_expr(expr, scope, items)) 152 | .try_collect()?; 153 | 154 | // merge tokens from each element 155 | Ok(TypeVar::Tuple(TypeTupleVar { elems })) 156 | } 157 | 158 | pub fn translate_block_expr( 159 | block: &ExprBlock, 160 | scope: &mut Env, 161 | items: &mut Vec, 162 | ) -> syn::Result { 163 | translate_block(&block.block, scope, items) 164 | } 165 | 166 | pub fn translate_call_expr( 167 | call: &ExprCall, 168 | scope: &mut Env, 169 | items: &mut Vec, 170 | ) -> syn::Result 171 | where 172 | { 173 | let ExprCall { func, args, .. } = call; 174 | 175 | // parse arguments 176 | let args: Vec<_> = args 177 | .iter() 178 | .map(|arg| translate_expr(arg, scope, items)) 179 | .try_collect()?; 180 | 181 | // parse the function path to a trait path 182 | let trait_path = { 183 | let mut trait_path = match &**func { 184 | Expr::Path(ExprPath { 185 | qself: None, path, .. 186 | }) => path.parse_path_var(scope)?, 187 | _ => return Err(Error::new(func.span(), "not a trait")), 188 | }; 189 | 190 | // set the type arguments on trait 191 | trait_path.segments.last_mut().as_mut().unwrap().arguments = 192 | if let PathArgumentsVar::None = trait_path.segments.last().unwrap().arguments { 193 | PathArgumentsVar::AngleBracketed(args) 194 | } else { 195 | return Err(Error::new( 196 | func.span(), 197 | "type parameters are not allowed in trait call", 198 | )); 199 | }; 200 | 201 | trait_path 202 | }; 203 | 204 | // insert predicates 205 | let (output, predicate) = { 206 | // construct the output type 207 | let bounded_ty: TypeVar = syn::parse2::(quote! { () }) 208 | .unwrap() 209 | .parse_pure_type(&mut vec![]) 210 | .unwrap(); 211 | let output = { 212 | let position = trait_path.segments.len(); 213 | let path = { 214 | let mut path = trait_path.clone(); 215 | path.segments.push(SegmentVar { 216 | ident: format_ident!("Output"), 217 | arguments: PathArgumentsVar::None, 218 | }); 219 | path 220 | }; 221 | TypeVar::Path(TypePathVar { 222 | qself: Some(QSelfVar { 223 | ty: Box::new(bounded_ty.clone()), 224 | position, 225 | }), 226 | path, 227 | }) 228 | }; 229 | 230 | // construct the predicate 231 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 232 | bounded_ty, 233 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 234 | modifier: TraitBoundModifierVar::None, 235 | path: trait_path, 236 | })], 237 | }); 238 | 239 | (output, predicate) 240 | }; 241 | 242 | scope.insert_predicate(predicate); 243 | 244 | Ok(output) 245 | } 246 | -------------------------------------------------------------------------------- /src/trans/mod.rs: -------------------------------------------------------------------------------- 1 | mod assign; 2 | mod binop; 3 | mod block; 4 | mod enum_; 5 | mod fn_; 6 | mod if_; 7 | mod impl_; 8 | mod lit; 9 | mod match_; 10 | mod misc; 11 | mod struct_; 12 | mod unary; 13 | 14 | pub use crate::{ 15 | common::*, 16 | env::{Env, Variable}, 17 | parse::{CaptureAttr, GenericsAttr, SimpleTypeParam}, 18 | utils::Shared, 19 | var::{ 20 | ParsePathVar, ParsePurePath, ParsePureType, ParsePureWherePredicate, 21 | ParseTypeParamBoundsVar, ParseTypeVar, ParseWherePredicateVar, PathArgumentsVar, PathVar, 22 | PredicateTypeVar, QSelfVar, SegmentVar, Subsitution, TraitBoundModifierVar, TraitBoundVar, 23 | TypeParamBoundVar, TypePathVar, TypeTupleVar, TypeVar, WherePredicateVar, 24 | }, 25 | }; 26 | pub use assign::*; 27 | pub use binop::*; 28 | pub use block::*; 29 | pub use enum_::*; 30 | pub use fn_::*; 31 | pub use if_::*; 32 | pub use impl_::*; 33 | pub use lit::*; 34 | pub use match_::*; 35 | pub use misc::*; 36 | pub use struct_::*; 37 | pub use unary::*; 38 | 39 | pub fn translate_items(items: &[Item]) -> syn::Result { 40 | let tokens_vec: Vec<_> = items 41 | .into_iter() 42 | .map(|item| { 43 | let tokens = match item { 44 | Item::Enum(enum_) => translate_enum(&enum_)?, 45 | Item::Fn(fn_) => { 46 | let ItemFn { 47 | sig, block, vis, .. 48 | } = fn_; 49 | translate_fn(vis, sig, block, None, None)? 50 | } 51 | Item::Struct(struct_) => translate_struct(&struct_)?, 52 | Item::Impl(impl_) => translate_impl(&impl_)?, 53 | Item::Use(use_) => translate_use(&use_), 54 | _ => { 55 | return Err(Error::new(item.span(), "unsupported item kind")); 56 | } 57 | }; 58 | Ok(tokens) 59 | }) 60 | .try_collect()?; 61 | 62 | let expanded = quote! { 63 | #(#tokens_vec)* 64 | }; 65 | 66 | Ok(expanded) 67 | } 68 | 69 | fn translate_use(use_: &ItemUse) -> TokenStream { 70 | // return as it is 71 | quote! { #use_ } 72 | } 73 | -------------------------------------------------------------------------------- /src/trans/struct_.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_struct(_struct_: &ItemStruct) -> syn::Result { 4 | todo!(); 5 | } 6 | -------------------------------------------------------------------------------- /src/trans/unary.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn translate_unary_expr( 4 | ExprUnary { op, expr, .. }: &ExprUnary, 5 | scope: &mut Env, 6 | items: &mut Vec, 7 | ) -> syn::Result { 8 | let operand = translate_expr(expr, scope, items)?; 9 | 10 | let output = match op { 11 | UnOp::Neg(_) => { 12 | let (output, predicate) = { 13 | let trait_: PathVar = syn::parse2::(quote! { core::ops::Neg }) 14 | .unwrap() 15 | .parse_pure_path(&mut vec![]) 16 | .unwrap(); 17 | let path = { 18 | let mut path = trait_.clone(); 19 | path.segments.push(SegmentVar { 20 | ident: format_ident!("Output"), 21 | arguments: PathArgumentsVar::None, 22 | }); 23 | path 24 | }; 25 | let output = TypeVar::Path(TypePathVar { 26 | qself: Some(QSelfVar { 27 | ty: Box::new(operand.clone()), 28 | position: trait_.segments.len(), 29 | }), 30 | path, 31 | }); 32 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 33 | bounded_ty: operand, 34 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 35 | modifier: TraitBoundModifierVar::None, 36 | path: trait_, 37 | })], 38 | }); 39 | 40 | (output, predicate) 41 | }; 42 | 43 | scope.insert_predicate(predicate); 44 | output 45 | } 46 | UnOp::Not(_) => { 47 | let (output, predicate) = { 48 | let trait_: PathVar = syn::parse2::(quote! { core::ops::Not }) 49 | .unwrap() 50 | .parse_pure_path(&mut vec![]) 51 | .unwrap(); 52 | let path = { 53 | let mut path = trait_.clone(); 54 | path.segments.push(SegmentVar { 55 | ident: format_ident!("Output"), 56 | arguments: PathArgumentsVar::None, 57 | }); 58 | path 59 | }; 60 | let output = TypeVar::Path(TypePathVar { 61 | qself: Some(QSelfVar { 62 | ty: Box::new(operand.clone()), 63 | position: trait_.segments.len(), 64 | }), 65 | path, 66 | }); 67 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 68 | bounded_ty: operand, 69 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 70 | modifier: TraitBoundModifierVar::None, 71 | path: trait_, 72 | })], 73 | }); 74 | 75 | (output, predicate) 76 | }; 77 | 78 | scope.insert_predicate(predicate); 79 | output 80 | } 81 | UnOp::Deref(_) => { 82 | let (output, predicate) = { 83 | let trait_: PathVar = syn::parse2::(quote! { core::ops::Deref }) 84 | .unwrap() 85 | .parse_pure_path(&mut vec![]) 86 | .unwrap(); 87 | let path = { 88 | let mut path = trait_.clone(); 89 | path.segments.push(SegmentVar { 90 | ident: format_ident!("Target"), 91 | arguments: PathArgumentsVar::None, 92 | }); 93 | path 94 | }; 95 | let output = TypeVar::Path(TypePathVar { 96 | qself: Some(QSelfVar { 97 | ty: Box::new(operand.clone()), 98 | position: trait_.segments.len(), 99 | }), 100 | path, 101 | }); 102 | let predicate = WherePredicateVar::Type(PredicateTypeVar { 103 | bounded_ty: operand, 104 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 105 | modifier: TraitBoundModifierVar::None, 106 | path: trait_, 107 | })], 108 | }); 109 | 110 | (output, predicate) 111 | }; 112 | 113 | scope.insert_predicate(predicate); 114 | output 115 | } 116 | }; 117 | 118 | Ok(output) 119 | } 120 | -------------------------------------------------------------------------------- /src/tyint.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | 3 | struct SignedInteger { 4 | has_negative_op: bool, 5 | value: u128, 6 | } 7 | 8 | impl Parse for SignedInteger { 9 | fn parse(input: ParseStream) -> syn::Result { 10 | let has_negative_op = if input.peek(Token![-]) { 11 | input.parse::()?; 12 | true 13 | } else { 14 | false 15 | }; 16 | 17 | let literal = input.parse::()?; 18 | let value = literal.base10_parse::()?; 19 | 20 | let output = SignedInteger { 21 | has_negative_op, 22 | value, 23 | }; 24 | 25 | Ok(output) 26 | } 27 | } 28 | 29 | struct UnsignedInteger { 30 | value: u128, 31 | } 32 | 33 | impl Parse for UnsignedInteger { 34 | fn parse(input: ParseStream) -> syn::Result { 35 | let literal = input.parse::()?; 36 | let value = literal.base10_parse::()?; 37 | 38 | let output = UnsignedInteger { value }; 39 | 40 | Ok(output) 41 | } 42 | } 43 | 44 | pub fn tyint(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 45 | let SignedInteger { 46 | has_negative_op, 47 | value, 48 | } = parse_macro_input!(input as SignedInteger); 49 | 50 | let tokens = if value == 0 { 51 | quote! { 52 | typenum::consts::Z0 53 | } 54 | } else if has_negative_op { 55 | let uint_tokens = recursive_value_to_typeuint(value); 56 | quote! { 57 | typenum::int::NInt<#uint_tokens> 58 | } 59 | } else { 60 | let uint_tokens = recursive_value_to_typeuint(value); 61 | quote! { 62 | typenum::int::PInt<#uint_tokens> 63 | } 64 | }; 65 | 66 | proc_macro::TokenStream::from(tokens) 67 | } 68 | 69 | pub fn tyuint(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 70 | let UnsignedInteger { value } = parse_macro_input!(input as UnsignedInteger); 71 | 72 | let tokens = recursive_value_to_typeuint(value); 73 | proc_macro::TokenStream::from(tokens) 74 | } 75 | 76 | fn recursive_value_to_typeuint(value: u128) -> TokenStream { 77 | if value == 0 { 78 | quote! { 79 | typenum::uint::UTerm 80 | } 81 | } else if value & 1 == 1 { 82 | let sub_tokens = recursive_value_to_typeuint(value >> 1); 83 | quote! { 84 | typenum::uint::UInt<#sub_tokens, typenum::bit::B1> 85 | } 86 | } else { 87 | let sub_tokens = recursive_value_to_typeuint(value >> 1); 88 | quote! { 89 | typenum::uint::UInt<#sub_tokens, typenum::bit::B0> 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | common::*, 3 | var::{TypeVar, WherePredicateVar}, 4 | }; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct Shared(ByAddress>); 8 | 9 | impl Shared { 10 | pub fn new(value: T) -> Shared { 11 | Shared(ByAddress(Rc::new(value))) 12 | } 13 | } 14 | 15 | impl PartialEq> for Shared { 16 | fn eq(&self, other: &Shared) -> bool { 17 | self.0.eq(&other.0) 18 | } 19 | } 20 | 21 | impl Eq for Shared {} 22 | 23 | impl PartialOrd> for Shared { 24 | fn partial_cmp(&self, other: &Shared) -> Option { 25 | self.0.partial_cmp(&other.0) 26 | } 27 | } 28 | 29 | impl Ord for Shared { 30 | fn cmp(&self, other: &Shared) -> Ordering { 31 | self.0.cmp(&other.0) 32 | } 33 | } 34 | 35 | impl Hash for Shared { 36 | fn hash(&self, state: &mut H) { 37 | self.0.hash(state) 38 | } 39 | } 40 | 41 | impl Borrow for Shared { 42 | fn borrow(&self) -> &T { 43 | self.0.deref().deref() 44 | } 45 | } 46 | 47 | impl Deref for Shared { 48 | type Target = T; 49 | 50 | fn deref(&self) -> &Self::Target { 51 | self.0.deref().deref() 52 | } 53 | } 54 | 55 | #[derive(Debug, Clone)] 56 | pub struct SharedCell(ByAddress>>); 57 | 58 | impl SharedCell { 59 | pub fn new(value: T) -> SharedCell { 60 | SharedCell(ByAddress(Rc::new(RefCell::new(value)))) 61 | } 62 | 63 | pub fn borrow(&self) -> Ref { 64 | self.0.deref().deref().borrow() 65 | } 66 | 67 | pub fn borrow_mut(&self) -> RefMut { 68 | self.0.deref().deref().borrow_mut() 69 | } 70 | 71 | pub fn deep_clone(&self) -> SharedCell 72 | where 73 | T: Clone, 74 | { 75 | SharedCell(ByAddress(Rc::new(RefCell::new( 76 | (**self.0).borrow().clone(), 77 | )))) 78 | } 79 | } 80 | 81 | impl PartialEq> for SharedCell { 82 | fn eq(&self, other: &SharedCell) -> bool { 83 | self.0.eq(&other.0) 84 | } 85 | } 86 | 87 | impl Eq for SharedCell {} 88 | 89 | impl PartialOrd> for SharedCell { 90 | fn partial_cmp(&self, other: &SharedCell) -> Option { 91 | self.0.partial_cmp(&other.0) 92 | } 93 | } 94 | 95 | impl Ord for SharedCell { 96 | fn cmp(&self, other: &SharedCell) -> Ordering { 97 | self.0.cmp(&other.0) 98 | } 99 | } 100 | 101 | impl Hash for SharedCell { 102 | fn hash(&self, state: &mut H) { 103 | self.0.hash(state) 104 | } 105 | } 106 | 107 | pub trait IntoRc { 108 | type Inner; 109 | 110 | fn into_rc(self) -> Rc; 111 | } 112 | 113 | impl IntoRc for TypeVar { 114 | type Inner = TypeVar; 115 | 116 | fn into_rc(self) -> Rc { 117 | Rc::new(self) 118 | } 119 | } 120 | 121 | impl IntoRc for Rc { 122 | type Inner = TypeVar; 123 | 124 | fn into_rc(self) -> Rc { 125 | self 126 | } 127 | } 128 | 129 | impl IntoRc for WherePredicateVar { 130 | type Inner = WherePredicateVar; 131 | 132 | fn into_rc(self) -> Rc { 133 | Rc::new(self) 134 | } 135 | } 136 | 137 | impl IntoRc for Rc { 138 | type Inner = WherePredicateVar; 139 | 140 | fn into_rc(self) -> Rc { 141 | self 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/var.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | common::*, 3 | env::{Env, Variable}, 4 | utils::Shared, 5 | }; 6 | 7 | // parse without substitutions 8 | 9 | pub trait ParsePureType { 10 | fn parse_pure_type>( 11 | &self, 12 | predicates: &mut E, 13 | ) -> syn::Result; 14 | } 15 | 16 | impl ParsePureType for Ident { 17 | fn parse_pure_type>( 18 | &self, 19 | predicates: &mut E, 20 | ) -> syn::Result { 21 | Ok(TypeVar::Path(TypePathVar { 22 | qself: None, 23 | path: self.parse_pure_path(predicates)?, 24 | })) 25 | } 26 | } 27 | 28 | impl ParsePureType for Type { 29 | fn parse_pure_type>( 30 | &self, 31 | predicates: &mut E, 32 | ) -> syn::Result { 33 | let var = match self { 34 | Type::Path(TypePath { qself, path }) => match *qself { 35 | Some(QSelf { 36 | ref ty, position, .. 37 | }) => { 38 | let ty = ty.parse_pure_type(predicates)?; 39 | let path = path.parse_pure_path(predicates)?; 40 | let trait_ = PathVar { 41 | segments: path.segments[0..position].iter().cloned().collect(), 42 | }; 43 | 44 | predicates.extend(iter::once(WherePredicateVar::Type(PredicateTypeVar { 45 | bounded_ty: ty.clone(), 46 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 47 | modifier: TraitBoundModifierVar::None, 48 | path: trait_, 49 | })], 50 | }))); 51 | 52 | TypeVar::Path(TypePathVar { 53 | qself: Some(QSelfVar { 54 | ty: Box::new(ty), 55 | position, 56 | }), 57 | path, 58 | }) 59 | } 60 | None => TypeVar::Path(TypePathVar { 61 | qself: None, 62 | path: path.parse_pure_path(predicates)?, 63 | }), 64 | }, 65 | Type::Tuple(TypeTuple { elems, .. }) => { 66 | let elems: Vec<_> = elems 67 | .iter() 68 | .map(|elem| elem.parse_pure_type(predicates)) 69 | .try_collect()?; 70 | TypeVar::Tuple(TypeTupleVar { elems }) 71 | } 72 | Type::Paren(TypeParen { elem, .. }) => elem.parse_pure_type(predicates)?, 73 | _ => return Err(Error::new(self.span(), "unsupported type variant")), 74 | }; 75 | Ok(var) 76 | } 77 | } 78 | 79 | pub trait ParsePurePath { 80 | fn parse_pure_path>( 81 | &self, 82 | predicates: &mut E, 83 | ) -> syn::Result; 84 | } 85 | 86 | impl ParsePurePath for Ident { 87 | fn parse_pure_path>( 88 | &self, 89 | predicates: &mut E, 90 | ) -> syn::Result { 91 | let segments = vec![self.parse_pure_segment(predicates)?]; 92 | Ok(PathVar { segments }) 93 | } 94 | } 95 | 96 | impl ParsePurePath for Path { 97 | fn parse_pure_path>( 98 | &self, 99 | predicates: &mut E, 100 | ) -> syn::Result { 101 | let Path { segments, .. } = self; 102 | let segments: Vec<_> = segments 103 | .iter() 104 | .map(|segment| segment.parse_pure_segment(predicates)) 105 | .try_collect()?; 106 | Ok(PathVar { segments }) 107 | } 108 | } 109 | 110 | pub trait ParsePureSegment { 111 | fn parse_pure_segment>( 112 | &self, 113 | predicates: &mut E, 114 | ) -> syn::Result; 115 | } 116 | 117 | impl ParsePureSegment for Ident { 118 | fn parse_pure_segment>( 119 | &self, 120 | _predicates: &mut E, 121 | ) -> syn::Result { 122 | Ok(SegmentVar { 123 | ident: self.to_owned(), 124 | arguments: PathArgumentsVar::None, 125 | }) 126 | } 127 | } 128 | 129 | impl ParsePureSegment for PathSegment { 130 | fn parse_pure_segment>( 131 | &self, 132 | predicates: &mut E, 133 | ) -> syn::Result { 134 | let PathSegment { ident, arguments } = self; 135 | let arguments = match arguments { 136 | PathArguments::None => PathArgumentsVar::None, 137 | PathArguments::AngleBracketed(args) => { 138 | let args: Vec<_> = args 139 | .args 140 | .iter() 141 | .map(|arg| match arg { 142 | GenericArgument::Type(ty) => ty.parse_pure_type(predicates), 143 | _ => Err(Error::new(arg.span(), "unsupported generic variant")), 144 | }) 145 | .try_collect()?; 146 | PathArgumentsVar::AngleBracketed(args) 147 | } 148 | PathArguments::Parenthesized(args) => { 149 | let inputs: Vec<_> = args 150 | .inputs 151 | .iter() 152 | .map(|ty| ty.parse_pure_type(predicates)) 153 | .try_collect()?; 154 | PathArgumentsVar::Parenthesized(inputs) 155 | } 156 | }; 157 | 158 | Ok(SegmentVar { 159 | ident: ident.to_owned(), 160 | arguments, 161 | }) 162 | } 163 | } 164 | 165 | pub trait ParsePureWherePredicate { 166 | fn parse_pure_where_predicate>( 167 | &self, 168 | predicates: &mut E, 169 | ) -> syn::Result; 170 | } 171 | 172 | impl ParsePureWherePredicate for GenericParam { 173 | fn parse_pure_where_predicate>( 174 | &self, 175 | predicates: &mut E, 176 | ) -> syn::Result { 177 | match self { 178 | GenericParam::Type(TypeParam { ident, bounds, .. }) => { 179 | Ok(WherePredicateVar::Type(PredicateTypeVar { 180 | bounded_ty: ident.parse_pure_type(predicates)?, 181 | bounds: bounds 182 | .iter() 183 | .map(|bound| bound.parse_pure_type_param_bound(predicates)) 184 | .try_collect()?, 185 | })) 186 | } 187 | GenericParam::Lifetime(_) => { 188 | return Err(Error::new(self.span(), "lifetime is not supported")); 189 | } 190 | GenericParam::Const(_) => { 191 | return Err(Error::new(self.span(), "const generics is not supported")); 192 | } 193 | } 194 | } 195 | } 196 | 197 | impl ParsePureWherePredicate for WherePredicate { 198 | fn parse_pure_where_predicate>( 199 | &self, 200 | predicates: &mut E, 201 | ) -> syn::Result { 202 | match self { 203 | WherePredicate::Type(PredicateType { 204 | bounded_ty, bounds, .. 205 | }) => Ok(WherePredicateVar::Type(PredicateTypeVar { 206 | bounded_ty: bounded_ty.parse_pure_type(predicates)?, 207 | bounds: bounds 208 | .iter() 209 | .map(|bound| bound.parse_pure_type_param_bound(predicates)) 210 | .try_collect()?, 211 | })), 212 | WherePredicate::Lifetime(_) => { 213 | return Err(Error::new(self.span(), "lifetime bound is not supported")); 214 | } 215 | WherePredicate::Eq(_) => { 216 | return Err(Error::new(self.span(), "binding is not supported")); 217 | } 218 | } 219 | } 220 | } 221 | 222 | pub trait ParsePureTypeParamBound { 223 | fn parse_pure_type_param_bound>( 224 | &self, 225 | predicates: &mut E, 226 | ) -> syn::Result; 227 | } 228 | 229 | impl ParsePureTypeParamBound for TypeParamBound { 230 | fn parse_pure_type_param_bound>( 231 | &self, 232 | predicates: &mut E, 233 | ) -> syn::Result { 234 | match self { 235 | TypeParamBound::Trait(bound) => Ok(TypeParamBoundVar::Trait( 236 | bound.parse_pure_trait_bound(predicates)?, 237 | )), 238 | TypeParamBound::Lifetime(_) => { 239 | Err(Error::new(self.span(), "lifetime bound is not supported")) 240 | } 241 | } 242 | } 243 | } 244 | 245 | pub trait ParsePureTraitBound { 246 | fn parse_pure_trait_bound>( 247 | &self, 248 | predicates: &mut E, 249 | ) -> syn::Result; 250 | } 251 | 252 | impl ParsePureTraitBound for TraitBound { 253 | fn parse_pure_trait_bound>( 254 | &self, 255 | predicates: &mut E, 256 | ) -> syn::Result { 257 | let TraitBound { modifier, path, .. } = self; 258 | Ok(TraitBoundVar { 259 | modifier: modifier.into(), 260 | path: path.parse_pure_path(predicates)?, 261 | }) 262 | } 263 | } 264 | 265 | // parse with substitutions 266 | 267 | pub trait ParseTypeVar { 268 | fn parse_type_var(&self, env: &mut Env) -> syn::Result; 269 | } 270 | 271 | impl ParseTypeVar for Type { 272 | fn parse_type_var(&self, env: &mut Env) -> syn::Result { 273 | let ty = match self { 274 | Type::Path(TypePath { qself, path }) => match (qself, path.get_ident()) { 275 | ( 276 | Some(QSelf { 277 | ref ty, position, .. 278 | }), 279 | _, 280 | ) => { 281 | let ty = ty.parse_type_var(env)?; 282 | let path = path.parse_path_var(env)?; 283 | let trait_ = PathVar { 284 | segments: path.segments[0..(*position)].iter().cloned().collect(), 285 | }; 286 | 287 | env.insert_predicate(WherePredicateVar::Type(PredicateTypeVar { 288 | bounded_ty: ty.clone(), 289 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 290 | modifier: TraitBoundModifierVar::None, 291 | path: trait_, 292 | })], 293 | })); 294 | 295 | TypeVar::Path(TypePathVar { 296 | qself: Some(QSelfVar { 297 | ty: Box::new(ty), 298 | position: *position, 299 | }), 300 | path, 301 | }) 302 | } 303 | (None, Some(ident)) => match env.get_variable(ident) { 304 | Some(var) => TypeVar::Var(var), 305 | None => { 306 | let path = path.parse_path_var(env)?; 307 | TypeVar::Path(TypePathVar { qself: None, path }) 308 | } 309 | }, 310 | (None, None) => { 311 | let path = path.parse_path_var(env)?; 312 | TypeVar::Path(TypePathVar { qself: None, path }) 313 | } 314 | }, 315 | Type::Tuple(TypeTuple { elems, .. }) => { 316 | let elems: Vec<_> = elems 317 | .iter() 318 | .map(|elem| elem.parse_type_var(env)) 319 | .try_collect()?; 320 | TypeVar::Tuple(TypeTupleVar { elems }) 321 | } 322 | Type::Paren(TypeParen { elem, .. }) => elem.parse_type_var(env)?, 323 | _ => return Err(Error::new(self.span(), "unsupported type variant")), 324 | }; 325 | Ok(ty) 326 | } 327 | } 328 | 329 | impl ParseTypeVar for Pat { 330 | fn parse_type_var(&self, env: &mut Env) -> syn::Result { 331 | match self { 332 | Pat::Ident(pat_ident) => { 333 | // sanity check 334 | let PatIdent { 335 | ident, 336 | by_ref, 337 | mutability, 338 | subpat, 339 | .. 340 | } = pat_ident; 341 | 342 | if let Some(by_ref) = by_ref { 343 | return Err(Error::new(by_ref.span(), "ref keyword is not supported")); 344 | } 345 | 346 | if let Some(mutability) = mutability { 347 | return Err(Error::new( 348 | mutability.span(), 349 | "mut keyword is not supported", 350 | )); 351 | } 352 | 353 | if let Some(_) = subpat { 354 | return Err(Error::new(pat_ident.span(), "subpattern is not supported")); 355 | } 356 | 357 | ident.parse_type_var(env) 358 | } 359 | Pat::Path(PatPath { 360 | qself: Some(QSelf { ty, position, .. }), 361 | path, 362 | .. 363 | }) => { 364 | let ty = ty.parse_type_var(env)?; 365 | let path = path.parse_path_var(env)?; 366 | let trait_ = PathVar { 367 | segments: path.segments[0..(*position)].iter().cloned().collect(), 368 | }; 369 | 370 | env.insert_predicate(WherePredicateVar::Type(PredicateTypeVar { 371 | bounded_ty: ty.clone(), 372 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 373 | modifier: TraitBoundModifierVar::None, 374 | path: trait_, 375 | })], 376 | })); 377 | 378 | Ok(TypeVar::Path(TypePathVar { 379 | qself: Some(QSelfVar { 380 | ty: Box::new(ty), 381 | position: *position, 382 | }), 383 | path, 384 | })) 385 | } 386 | Pat::Path(PatPath { 387 | qself: None, path, .. 388 | }) => { 389 | let path = path.parse_path_var(env)?; 390 | Ok(TypeVar::Path(TypePathVar { qself: None, path })) 391 | } 392 | Pat::Tuple(PatTuple { elems, .. }) => { 393 | let elems: Vec<_> = elems 394 | .iter() 395 | .map(|elem| elem.parse_type_var(env)) 396 | .try_collect()?; 397 | Ok(TypeVar::Tuple(TypeTupleVar { elems })) 398 | } 399 | _ => Err(Error::new(self.span(), "not a type")), 400 | } 401 | } 402 | } 403 | 404 | impl ParseTypeVar for Ident { 405 | fn parse_type_var(&self, env: &mut Env) -> syn::Result { 406 | match env.get_variable(self) { 407 | Some(var) => Ok(TypeVar::Var(var)), 408 | None => Ok(TypeVar::Path(TypePathVar { 409 | qself: None, 410 | path: PathVar { 411 | segments: vec![SegmentVar { 412 | ident: self.to_owned(), 413 | arguments: PathArgumentsVar::None, 414 | }], 415 | }, 416 | })), 417 | } 418 | } 419 | } 420 | 421 | impl ParseTypeVar for ExprPath { 422 | fn parse_type_var(&self, env: &mut Env) -> syn::Result { 423 | let ExprPath { qself, path, .. } = self; 424 | let var = match (qself, path.get_ident()) { 425 | (Some(QSelf { ty, position, .. }), _) => { 426 | let ty = ty.parse_type_var(env)?; 427 | let path = path.parse_path_var(env)?; 428 | let trait_ = PathVar { 429 | segments: path.segments[0..(*position)].iter().cloned().collect(), 430 | }; 431 | 432 | env.insert_predicate(WherePredicateVar::Type(PredicateTypeVar { 433 | bounded_ty: ty.clone(), 434 | bounds: vec![TypeParamBoundVar::Trait(TraitBoundVar { 435 | modifier: TraitBoundModifierVar::None, 436 | path: trait_, 437 | })], 438 | })); 439 | 440 | TypeVar::Path(TypePathVar { 441 | qself: Some(QSelfVar { 442 | ty: Box::new(ty), 443 | position: *position, 444 | }), 445 | path, 446 | }) 447 | } 448 | (None, Some(ident)) => match env.get_variable(ident) { 449 | Some(var) => TypeVar::Var(var), 450 | None => { 451 | let path = path.parse_path_var(env)?; 452 | TypeVar::Path(TypePathVar { qself: None, path }) 453 | } 454 | }, 455 | (None, None) => { 456 | let path = path.parse_path_var(env)?; 457 | TypeVar::Path(TypePathVar { qself: None, path }) 458 | } 459 | }; 460 | Ok(var) 461 | } 462 | } 463 | 464 | pub trait ParsePathVar { 465 | fn parse_path_var(&self, env: &mut Env) -> syn::Result; 466 | } 467 | 468 | impl ParsePathVar for Path { 469 | fn parse_path_var(&self, env: &mut Env) -> syn::Result { 470 | let Path { segments, .. } = self; 471 | let segments: Vec<_> = segments 472 | .iter() 473 | .map(|segment| segment.parse_segment_var(env)) 474 | .try_collect()?; 475 | Ok(PathVar { segments }) 476 | } 477 | } 478 | 479 | pub trait ParseSegmentVar { 480 | fn parse_segment_var(&self, env: &mut Env) -> syn::Result; 481 | } 482 | 483 | impl ParseSegmentVar for PathSegment { 484 | fn parse_segment_var(&self, env: &mut Env) -> syn::Result { 485 | let PathSegment { ident, arguments } = self; 486 | let arguments = match arguments { 487 | PathArguments::None => PathArgumentsVar::None, 488 | PathArguments::AngleBracketed(args) => { 489 | let args = args 490 | .args 491 | .iter() 492 | .map(|arg| match arg { 493 | GenericArgument::Type(ty) => ty.parse_type_var(env), 494 | _ => Err(Error::new(arg.span(), "unsupported generic variant")), 495 | }) 496 | .try_collect()?; 497 | PathArgumentsVar::AngleBracketed(args) 498 | } 499 | PathArguments::Parenthesized(args) => { 500 | let inputs = args 501 | .inputs 502 | .iter() 503 | .map(|ty| ty.parse_type_var(env)) 504 | .try_collect()?; 505 | PathArgumentsVar::Parenthesized(inputs) 506 | } 507 | }; 508 | 509 | Ok(SegmentVar { 510 | ident: ident.to_owned(), 511 | arguments, 512 | }) 513 | } 514 | } 515 | 516 | pub trait ParseTraitBoundVar { 517 | fn parse_trait_bound_var(&self, env: &mut Env) -> syn::Result; 518 | } 519 | 520 | impl ParseTraitBoundVar for TraitBound { 521 | fn parse_trait_bound_var(&self, env: &mut Env) -> syn::Result { 522 | let TraitBound { modifier, path, .. } = self; 523 | let path = path.parse_path_var(env)?; 524 | Ok(TraitBoundVar { 525 | modifier: modifier.into(), 526 | path, 527 | }) 528 | } 529 | } 530 | 531 | pub trait ParsePredicateTypeVar { 532 | fn parse_predicate_type_var(&self, env: &mut Env) -> syn::Result; 533 | } 534 | 535 | impl ParsePredicateTypeVar for PredicateType { 536 | fn parse_predicate_type_var(&self, env: &mut Env) -> syn::Result { 537 | let PredicateType { 538 | lifetimes, 539 | bounded_ty, 540 | bounds, 541 | .. 542 | } = self; 543 | 544 | if let Some(life) = lifetimes { 545 | return Err(Error::new(life.span(), "bounded lifetime is not supported")); 546 | } 547 | 548 | let bounded_ty = bounded_ty.parse_type_var(env)?; 549 | let bounds: Vec<_> = bounds 550 | .iter() 551 | .map(|bound| match bound { 552 | TypeParamBound::Trait(trait_) => { 553 | let bounds = trait_.parse_trait_bound_var(env)?; 554 | Ok(TypeParamBoundVar::Trait(bounds)) 555 | } 556 | TypeParamBound::Lifetime(lifetime) => { 557 | Err(Error::new(lifetime.span(), "lifetime is not supported")) 558 | } 559 | }) 560 | .try_collect()?; 561 | 562 | Ok(PredicateTypeVar { bounded_ty, bounds }) 563 | } 564 | } 565 | 566 | pub trait ParseWherePredicateVar { 567 | fn parse_where_predicate_var(&self, env: &mut Env) -> syn::Result; 568 | } 569 | 570 | impl ParseWherePredicateVar for WherePredicate { 571 | fn parse_where_predicate_var(&self, env: &mut Env) -> syn::Result { 572 | match self { 573 | WherePredicate::Type(ty) => { 574 | let predicate = ty.parse_predicate_type_var(env)?; 575 | Ok(WherePredicateVar::Type(predicate)) 576 | } 577 | WherePredicate::Lifetime(lifetime) => { 578 | Err(Error::new(lifetime.span(), "lifetime is not supported")) 579 | } 580 | WherePredicate::Eq(eq) => { 581 | Err(Error::new(eq.span(), "equality predidate is not supported")) 582 | } 583 | } 584 | } 585 | } 586 | 587 | impl ParseWherePredicateVar for GenericParam { 588 | fn parse_where_predicate_var(&self, env: &mut Env) -> syn::Result { 589 | match self { 590 | GenericParam::Type(TypeParam { ident, bounds, .. }) => { 591 | let bounded_ty = ident.parse_type_var(env)?; 592 | let bounds = bounds 593 | .iter() 594 | .map(|bound| bound.parse_type_param_bound_var(env)) 595 | .try_collect()?; 596 | 597 | Ok(WherePredicateVar::Type(PredicateTypeVar { 598 | bounded_ty, 599 | bounds, 600 | })) 601 | } 602 | GenericParam::Lifetime(_) => { 603 | return Err(Error::new(self.span(), "lifetime is not supported")); 604 | } 605 | GenericParam::Const(_) => { 606 | return Err(Error::new(self.span(), "const generics is not supported")); 607 | } 608 | } 609 | } 610 | } 611 | 612 | impl ParseWherePredicateVar for PatType { 613 | fn parse_where_predicate_var(&self, env: &mut Env) -> syn::Result { 614 | let PatType { pat, ty, .. } = self; 615 | let bounded_ty = pat.parse_type_var(env)?; 616 | let bounds = ty.parse_type_param_bounds_var(env)?; 617 | Ok(WherePredicateVar::Type(PredicateTypeVar { 618 | bounded_ty, 619 | bounds, 620 | })) 621 | } 622 | } 623 | 624 | pub trait ParseTypeParamBoundVar { 625 | fn parse_type_param_bound_var(&self, env: &mut Env) -> syn::Result; 626 | } 627 | 628 | impl ParseTypeParamBoundVar for TypeParamBound { 629 | fn parse_type_param_bound_var(&self, env: &mut Env) -> syn::Result { 630 | match self { 631 | TypeParamBound::Trait(bound) => { 632 | let bounds = bound.parse_trait_bound_var(env)?; 633 | Ok(TypeParamBoundVar::Trait(bounds)) 634 | } 635 | 636 | TypeParamBound::Lifetime(_) => { 637 | Err(Error::new(self.span(), "lifetime is not supported")) 638 | } 639 | } 640 | } 641 | } 642 | 643 | impl ParseTypeParamBoundVar for TraitBound { 644 | fn parse_type_param_bound_var(&self, env: &mut Env) -> syn::Result { 645 | let bounds = self.parse_trait_bound_var(env)?; 646 | Ok(TypeParamBoundVar::Trait(bounds)) 647 | } 648 | } 649 | 650 | pub trait ParseTypeParamBoundsVar { 651 | fn parse_type_param_bounds_var(&self, env: &mut Env) -> syn::Result>; 652 | } 653 | 654 | impl ParseTypeParamBoundsVar for Type { 655 | fn parse_type_param_bounds_var(&self, env: &mut Env) -> syn::Result> { 656 | match self { 657 | Type::Infer(_) => Ok(vec![]), 658 | Type::Path(TypePath { 659 | qself: None, path, .. 660 | }) => { 661 | let path = path.parse_path_var(env)?; 662 | Ok(vec![TypeParamBoundVar::Trait(TraitBoundVar { 663 | modifier: TraitBoundModifierVar::None, 664 | path, 665 | })]) 666 | } 667 | Type::TraitObject(TypeTraitObject { 668 | bounds, dyn_token, .. 669 | }) => { 670 | if let Some(token) = dyn_token { 671 | return Err(Error::new(token.span(), "remove the dyn token")); 672 | } 673 | let bounds = bounds 674 | .iter() 675 | .map(|bound| bound.parse_type_param_bound_var(env)) 676 | .try_collect()?; 677 | Ok(bounds) 678 | } 679 | _ => Err(Error::new(self.span(), "not trait bounds")), 680 | } 681 | } 682 | } 683 | 684 | // substitution 685 | 686 | pub trait Subsitution { 687 | type Output; 688 | 689 | fn substitute( 690 | &self, 691 | env: &Env, 692 | substitution: &IndexMap, Ident>, 693 | ) -> Self::Output; 694 | } 695 | 696 | impl Subsitution for TypeVar { 697 | type Output = Type; 698 | 699 | fn substitute( 700 | &self, 701 | env: &Env, 702 | substitution: &IndexMap, Ident>, 703 | ) -> Self::Output { 704 | match self { 705 | TypeVar::Var(var) => var.substitute(env, substitution), 706 | TypeVar::Path(path) => Type::Path(path.substitute(env, substitution)), 707 | TypeVar::Tuple(tuple) => Type::Tuple(tuple.substitute(env, substitution)), 708 | } 709 | } 710 | } 711 | 712 | impl Subsitution for Shared { 713 | type Output = Type; 714 | 715 | fn substitute( 716 | &self, 717 | env: &Env, 718 | substitution: &IndexMap, Ident>, 719 | ) -> Self::Output { 720 | match &self.value { 721 | Some(value) => value.substitute(env, substitution), 722 | None => { 723 | let ident = substitution 724 | .get(self) 725 | .expect("the subsitution list is incomplete"); 726 | syn::parse2(quote! { #ident }).unwrap() 727 | } 728 | } 729 | } 730 | } 731 | 732 | impl Subsitution for TypePathVar { 733 | type Output = TypePath; 734 | 735 | fn substitute( 736 | &self, 737 | env: &Env, 738 | substitution: &IndexMap, Ident>, 739 | ) -> Self::Output { 740 | let TypePathVar { qself, path } = self; 741 | let path = path.substitute(env, substitution); 742 | 743 | match *qself { 744 | Some(QSelfVar { ref ty, position }) => { 745 | let ty = ty.substitute(env, substitution); 746 | let trait_: Vec<_> = path.segments.iter().take(position).collect(); 747 | let associated_type: Vec<_> = path.segments.iter().skip(position).collect(); 748 | syn::parse2(quote! { < #ty as #(#trait_)::* > #(::#associated_type)* }).unwrap() 749 | } 750 | None => syn::parse2(quote! { #path }).unwrap(), 751 | } 752 | } 753 | } 754 | 755 | impl Subsitution for TypeTupleVar { 756 | type Output = TypeTuple; 757 | 758 | fn substitute( 759 | &self, 760 | env: &Env, 761 | substitution: &IndexMap, Ident>, 762 | ) -> Self::Output { 763 | let elems: Vec<_> = self 764 | .elems 765 | .iter() 766 | .map(|elem| elem.substitute(env, substitution)) 767 | .collect(); 768 | syn::parse2(quote! { (#(#elems),*) }).unwrap() 769 | } 770 | } 771 | 772 | impl Subsitution for PathVar { 773 | type Output = Path; 774 | 775 | fn substitute( 776 | &self, 777 | env: &Env, 778 | substitution: &IndexMap, Ident>, 779 | ) -> Self::Output { 780 | let segments: Vec<_> = self 781 | .segments 782 | .iter() 783 | .map(|SegmentVar { ident, arguments }| { 784 | let arguments = arguments.substitute(env, substitution); 785 | PathSegment { 786 | ident: ident.to_owned(), 787 | arguments, 788 | } 789 | }) 790 | .collect(); 791 | 792 | syn::parse2(quote! { #(#segments)::* }).unwrap() 793 | } 794 | } 795 | 796 | impl Subsitution for PathArgumentsVar { 797 | type Output = PathArguments; 798 | 799 | fn substitute( 800 | &self, 801 | env: &Env, 802 | substitution: &IndexMap, Ident>, 803 | ) -> Self::Output { 804 | match self { 805 | PathArgumentsVar::None => PathArguments::None, 806 | PathArgumentsVar::AngleBracketed(args) => { 807 | let args: Vec<_> = args 808 | .iter() 809 | .map(|arg| arg.substitute(env, substitution)) 810 | .collect(); 811 | let args = syn::parse2(quote! { < #(#args),* > }).unwrap(); 812 | PathArguments::AngleBracketed(args) 813 | } 814 | PathArgumentsVar::Parenthesized(args) => { 815 | let args: Vec<_> = args 816 | .iter() 817 | .map(|arg| arg.substitute(env, substitution)) 818 | .collect(); 819 | let args = syn::parse2(quote! { ( #(#args),* ) }).unwrap(); 820 | PathArguments::Parenthesized(args) 821 | } 822 | } 823 | } 824 | } 825 | 826 | impl Subsitution for WherePredicateVar { 827 | type Output = WherePredicate; 828 | 829 | fn substitute( 830 | &self, 831 | env: &Env, 832 | substitution: &IndexMap, Ident>, 833 | ) -> Self::Output { 834 | match self { 835 | WherePredicateVar::Type(PredicateTypeVar { bounded_ty, bounds }) => { 836 | let bounded_ty = bounded_ty.substitute(env, substitution); 837 | let bounds: Vec<_> = bounds 838 | .into_iter() 839 | .map(|bound| bound.substitute(env, substitution)) 840 | .collect(); 841 | let predicate: WherePredicate = 842 | syn::parse2(quote! { #bounded_ty: #(#bounds)+* }).unwrap(); 843 | predicate 844 | } 845 | } 846 | } 847 | } 848 | 849 | impl Subsitution for TypeParamBoundVar { 850 | type Output = TypeParamBound; 851 | 852 | fn substitute( 853 | &self, 854 | env: &Env, 855 | substitution: &IndexMap, Ident>, 856 | ) -> Self::Output { 857 | match self { 858 | TypeParamBoundVar::Trait(TraitBoundVar { modifier, path }) => { 859 | let path = path.substitute(env, substitution); 860 | let bound: TraitBound = match modifier { 861 | TraitBoundModifierVar::None => syn::parse2(quote! { #path }).unwrap(), 862 | TraitBoundModifierVar::Maybe => syn::parse2(quote! { ?#path }).unwrap(), 863 | }; 864 | TypeParamBound::Trait(bound) 865 | } 866 | } 867 | } 868 | } 869 | 870 | // types 871 | 872 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 873 | pub enum TypeVar { 874 | Var(Shared), 875 | Path(TypePathVar), 876 | Tuple(TypeTupleVar), 877 | } 878 | 879 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 880 | pub struct SegmentVar { 881 | pub ident: Ident, 882 | pub arguments: PathArgumentsVar, 883 | } 884 | 885 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 886 | pub enum PathArgumentsVar { 887 | None, 888 | AngleBracketed(Vec), 889 | Parenthesized(Vec), 890 | } 891 | 892 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 893 | pub struct GenericArgumentVar { 894 | pub ty: TypeVar, 895 | } 896 | 897 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 898 | pub struct PathVar { 899 | pub segments: Vec, 900 | } 901 | 902 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 903 | pub struct QSelfVar { 904 | pub ty: Box, 905 | pub position: usize, 906 | } 907 | 908 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 909 | pub struct TypePathVar { 910 | pub qself: Option, 911 | pub path: PathVar, 912 | } 913 | 914 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 915 | pub struct TypeTupleVar { 916 | pub elems: Vec, 917 | } 918 | 919 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 920 | pub struct TraitBoundVar { 921 | pub modifier: TraitBoundModifierVar, 922 | pub path: PathVar, 923 | } 924 | 925 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 926 | pub enum TraitBoundModifierVar { 927 | None, 928 | Maybe, 929 | } 930 | 931 | impl From for TraitBoundModifierVar { 932 | fn from(from: TraitBoundModifier) -> Self { 933 | (&from).into() 934 | } 935 | } 936 | 937 | impl From<&TraitBoundModifier> for TraitBoundModifierVar { 938 | fn from(from: &TraitBoundModifier) -> Self { 939 | match from { 940 | TraitBoundModifier::None => Self::None, 941 | TraitBoundModifier::Maybe(_) => Self::Maybe, 942 | } 943 | } 944 | } 945 | 946 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 947 | pub enum WherePredicateVar { 948 | Type(PredicateTypeVar), 949 | } 950 | 951 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 952 | pub struct PredicateTypeVar { 953 | pub bounded_ty: TypeVar, 954 | pub bounds: Vec, 955 | } 956 | 957 | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] 958 | pub enum TypeParamBoundVar { 959 | Trait(TraitBoundVar), 960 | } 961 | -------------------------------------------------------------------------------- /tests/macro/binop.rs: -------------------------------------------------------------------------------- 1 | use super::common::*; 2 | 3 | typ! { 4 | fn True() -> Bit { 5 | true 6 | } 7 | 8 | fn False() -> Bit { 9 | false 10 | } 11 | 12 | fn And(Lhs: Bit, Rhs: Bit) -> Bit { 13 | Lhs && Rhs 14 | } 15 | 16 | fn Or(Lhs: Bit, Rhs: Bit) -> Bit { 17 | Lhs || Rhs 18 | } 19 | 20 | fn Not(Value: Bit) -> Bit { 21 | !Value 22 | } 23 | 24 | fn XorV1(Lhs: Bit, Rhs: Bit) -> Bit { 25 | (Lhs && !Rhs) || (!Lhs && Rhs) 26 | } 27 | 28 | fn XorV2(Lhs: Bit, Rhs: Bit) -> Bit { 29 | Or(And(Lhs, Not(Rhs)), And(Not(Lhs), Rhs)) 30 | } 31 | } 32 | 33 | #[test] 34 | fn test() { 35 | use typenum::{B0, B1}; 36 | let _: AssertSameOp = (); 37 | let _: AssertSameOp = (); 38 | 39 | let _: AssertSameOp, B1> = (); 40 | let _: AssertSameOp, B0> = (); 41 | 42 | let _: AssertSameOp, B0> = (); 43 | let _: AssertSameOp, B1> = (); 44 | let _: AssertSameOp, B1> = (); 45 | let _: AssertSameOp, B1> = (); 46 | 47 | let _: AssertSameOp, B0> = (); 48 | let _: AssertSameOp, B0> = (); 49 | let _: AssertSameOp, B0> = (); 50 | let _: AssertSameOp, B1> = (); 51 | 52 | let _: AssertSameOp, B0> = (); 53 | let _: AssertSameOp, B1> = (); 54 | let _: AssertSameOp, B1> = (); 55 | let _: AssertSameOp, B0> = (); 56 | 57 | let _: AssertSameOp, B0> = (); 58 | let _: AssertSameOp, B1> = (); 59 | let _: AssertSameOp, B1> = (); 60 | let _: AssertSameOp, B0> = (); 61 | } 62 | -------------------------------------------------------------------------------- /tests/macro/common.rs: -------------------------------------------------------------------------------- 1 | pub use typ::{typ, tyuint}; 2 | pub use typenum::{Bit, Integer, Max, Unsigned}; 3 | 4 | pub trait AssertSame { 5 | type Output; 6 | } 7 | 8 | impl AssertSame for () { 9 | type Output = (); 10 | } 11 | 12 | pub type AssertSameOp = <() as AssertSame>::Output; 13 | -------------------------------------------------------------------------------- /tests/macro/fail_match_attribute.rs: -------------------------------------------------------------------------------- 1 | use typ::typ; 2 | 3 | pub trait AssertSame { 4 | type Output; 5 | } 6 | 7 | impl AssertSame for () { 8 | type Output = (); 9 | } 10 | 11 | pub type AssertSameOp = <() as AssertSame>::Output; 12 | 13 | struct Alice(X); 14 | struct Bob(X); 15 | 16 | typ! { 17 | fn Compare(lhs: _, rhs: _) { 18 | let lval = match lhs { 19 | #[generics(val)] 20 | Alice:: => val, 21 | #[generics(val)] 22 | Bob:: => val, 23 | }; 24 | 25 | match rhs { 26 | #[capture(lval)] 27 | Alice:: => (), 28 | #[capture(lval)] 29 | Bob:: => (), 30 | } 31 | } 32 | } 33 | 34 | fn main() { 35 | use typenum::consts::*; 36 | 37 | let _: AssertSameOp, Alice>, ()> = (); 38 | let _: AssertSameOp, Bob>, ()> = (); 39 | let _: AssertSameOp, Alice>, ()> = (); 40 | let _: AssertSameOp, Bob>, ()> = (); 41 | let _: AssertSameOp, Alice>, ()> = (); 42 | let _: AssertSameOp, Bob>, ()> = (); 43 | let _: AssertSameOp, Alice>, ()> = (); 44 | let _: AssertSameOp, Bob>, ()> = (); 45 | } 46 | -------------------------------------------------------------------------------- /tests/macro/fail_match_attribute.stderr: -------------------------------------------------------------------------------- 1 | error[E0271]: type mismatch resolving `<() as __TYP_MatchArm_0, Alice, Alice>>::Output == typenum::B1` 2 | --> $DIR/fail_match_attribute.rs:37:25 3 | | 4 | 37 | let _: AssertSameOp, Alice>, ()> = (); 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `typenum::B0`, found struct `typenum::B1` 6 | 7 | error[E0271]: type mismatch resolving `<() as __TYP_MatchArm_0, Bob, Alice>>::Output == typenum::B1` 8 | --> $DIR/fail_match_attribute.rs:38:25 9 | | 10 | 38 | let _: AssertSameOp, Bob>, ()> = (); 11 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `typenum::B0`, found struct `typenum::B1` 12 | 13 | error[E0271]: type mismatch resolving `<() as __TYP_MatchArm_0, Alice, Bob>>::Output == typenum::B1` 14 | --> $DIR/fail_match_attribute.rs:39:25 15 | | 16 | 39 | let _: AssertSameOp, Alice>, ()> = (); 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `typenum::B0`, found struct `typenum::B1` 18 | 19 | error[E0271]: type mismatch resolving `<() as __TYP_MatchArm_0, Bob, Bob>>::Output == typenum::B1` 20 | --> $DIR/fail_match_attribute.rs:40:25 21 | | 22 | 40 | let _: AssertSameOp, Bob>, ()> = (); 23 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `typenum::B0`, found struct `typenum::B1` 24 | 25 | error[E0271]: type mismatch resolving `<() as __TYP_MatchArm_0, Alice, Alice>>::Output == typenum::B0` 26 | --> $DIR/fail_match_attribute.rs:41:25 27 | | 28 | 41 | let _: AssertSameOp, Alice>, ()> = (); 29 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `typenum::B1`, found struct `typenum::B0` 30 | 31 | error[E0271]: type mismatch resolving `<() as __TYP_MatchArm_0, Bob, Alice>>::Output == typenum::B0` 32 | --> $DIR/fail_match_attribute.rs:42:25 33 | | 34 | 42 | let _: AssertSameOp, Bob>, ()> = (); 35 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `typenum::B1`, found struct `typenum::B0` 36 | 37 | error[E0271]: type mismatch resolving `<() as __TYP_MatchArm_0, Alice, Bob>>::Output == typenum::B0` 38 | --> $DIR/fail_match_attribute.rs:43:25 39 | | 40 | 43 | let _: AssertSameOp, Alice>, ()> = (); 41 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `typenum::B1`, found struct `typenum::B0` 42 | 43 | error[E0271]: type mismatch resolving `<() as __TYP_MatchArm_0, Bob, Bob>>::Output == typenum::B0` 44 | --> $DIR/fail_match_attribute.rs:44:25 45 | | 46 | 44 | let _: AssertSameOp, Bob>, ()> = (); 47 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `typenum::B1`, found struct `typenum::B0` 48 | -------------------------------------------------------------------------------- /tests/macro/if_.rs: -------------------------------------------------------------------------------- 1 | use super::common::*; 2 | use typenum::consts::*; 3 | 4 | typ! { 5 | fn IfTest1(Cond: _) { 6 | if Cond { 7 | 1 8 | } 9 | } 10 | 11 | fn IfTest2(Cond: _) { 12 | if Cond { 13 | 1 14 | } else { 15 | -1 16 | } 17 | } 18 | 19 | fn IfTest3(Cond: Bit) { 20 | let mut value = 0; 21 | 22 | if Cond { 23 | value = 1; 24 | } 25 | value 26 | } 27 | 28 | fn IfTest4(Cond: Bit) { 29 | let mut value = 0; 30 | 31 | if Cond { 32 | value = 1; 33 | } else { 34 | value = -1; 35 | } 36 | 37 | value 38 | } 39 | 40 | fn IfTest5(Input: Integer) { 41 | let mut value: Integer = 0; 42 | 43 | if Input < 5 { 44 | value = 1; 45 | } else { 46 | value = -1; 47 | } 48 | 49 | let output = if value >= 0 { 50 | 7 51 | } else { 52 | -7 53 | }; 54 | 55 | output 56 | } 57 | 58 | fn IfTest6(L: Integer, R: Integer) { 59 | if L % 2 == 1 { 60 | if R % 2 == 1 { 61 | 3 62 | } else { 63 | 2 64 | } 65 | } else if R % 2 == 1 { 66 | 1 67 | } else { 68 | 0 69 | } 70 | } 71 | } 72 | 73 | #[test] 74 | fn test() { 75 | let _: AssertSameOp, ()> = (); 76 | let _: AssertSameOp, ()> = (); 77 | 78 | let _: AssertSameOp, N1> = (); 79 | let _: AssertSameOp, P1> = (); 80 | 81 | let _: AssertSameOp, Z0> = (); 82 | let _: AssertSameOp, P1> = (); 83 | 84 | let _: AssertSameOp, N1> = (); 85 | let _: AssertSameOp, P1> = (); 86 | 87 | let _: AssertSameOp, P7> = (); 88 | let _: AssertSameOp, N7> = (); 89 | 90 | let _: AssertSameOp, Z0> = (); 91 | let _: AssertSameOp, P1> = (); 92 | let _: AssertSameOp, P2> = (); 93 | let _: AssertSameOp, P3> = (); 94 | } 95 | -------------------------------------------------------------------------------- /tests/macro/main.rs: -------------------------------------------------------------------------------- 1 | mod binop; 2 | mod common; 3 | mod if_; 4 | mod match_; 5 | mod misc; 6 | mod recursion; 7 | -------------------------------------------------------------------------------- /tests/macro/match_.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | use typenum::consts::*; 3 | 4 | mod animal_test { 5 | use super::*; 6 | 7 | pub trait Animal {} 8 | 9 | pub struct Dog; 10 | impl Animal for Dog {} 11 | 12 | pub struct Cat; 13 | impl Animal for Cat {} 14 | 15 | pub struct Mouse; 16 | impl Animal for Mouse {} 17 | 18 | typ! { 19 | fn MatchTest1(A: Animal) -> Unsigned 20 | { 21 | match A { 22 | Dog => 1u, 23 | Cat => 2u, 24 | Mouse => 3u, 25 | } 26 | } 27 | } 28 | 29 | #[test] 30 | fn test() { 31 | let _: AssertSameOp, U1> = (); 32 | let _: AssertSameOp, U2> = (); 33 | let _: AssertSameOp, U3> = (); 34 | } 35 | } 36 | 37 | mod recursive_append_list_test { 38 | use super::*; 39 | 40 | // traits and types 41 | 42 | pub trait List {} 43 | 44 | pub struct Cons 45 | where 46 | Tail: List, 47 | { 48 | _head: Head, 49 | _tail: Tail, 50 | } 51 | 52 | impl List for Cons where Tail: List {} 53 | 54 | pub struct Nil; 55 | 56 | impl List for Nil {} 57 | 58 | // append type operator 59 | 60 | typ! { 61 | fn Append(input: List, value: _) -> List { 62 | match input { 63 | #[generics(head, tail: List)] 64 | Cons:: => { 65 | let new_tail = Append(tail, value); 66 | Cons:: 67 | } 68 | Nil => { 69 | Cons:: 70 | } 71 | } 72 | } 73 | } 74 | 75 | #[test] 76 | fn test() { 77 | type List0 = Nil; 78 | type List1 = Cons; 79 | type List2 = Cons>; 80 | type List3 = Cons>>; 81 | type List4 = Cons>>>; 82 | 83 | let _: AssertSameOp, List1> = (); 84 | let _: AssertSameOp, List2> = (); 85 | let _: AssertSameOp, List3> = (); 86 | let _: AssertSameOp, List4> = (); 87 | } 88 | 89 | } 90 | 91 | mod attributes_test { 92 | use super::*; 93 | 94 | struct Alice(X); 95 | struct Bob(X); 96 | 97 | typ! { 98 | fn Compare(lhs: _, rhs: _) { 99 | let lval = match lhs { 100 | #[generics(val)] 101 | Alice:: => val, 102 | #[generics(val)] 103 | Bob:: => val, 104 | }; 105 | 106 | match rhs { 107 | #[capture(lval)] 108 | Alice:: => (), 109 | #[capture(lval)] 110 | Bob:: => (), 111 | } 112 | } 113 | } 114 | 115 | #[test] 116 | fn test() { 117 | let _: AssertSameOp, Alice>, ()> = (); 118 | let _: AssertSameOp, Bob>, ()> = (); 119 | let _: AssertSameOp, Alice>, ()> = (); 120 | let _: AssertSameOp, Bob>, ()> = (); 121 | let _: AssertSameOp, Alice>, ()> = (); 122 | let _: AssertSameOp, Bob>, ()> = (); 123 | let _: AssertSameOp, Alice>, ()> = (); 124 | let _: AssertSameOp, Bob>, ()> = (); 125 | } 126 | } 127 | 128 | #[test] 129 | fn compile_fail_test() { 130 | let t = trybuild::TestCases::new(); 131 | t.compile_fail("tests/macro/fail_match_attribute.rs"); 132 | } 133 | -------------------------------------------------------------------------------- /tests/macro/misc.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | use typenum::consts::*; 3 | 4 | typ! { 5 | fn Empty() {} 6 | 7 | fn MethodCall(lhs: Unsigned, rhs: Unsigned) -> Unsigned { 8 | lhs.Max(rhs) 9 | } 10 | } 11 | 12 | typ! { 13 | impl V { 14 | fn GetOneIfIsSquareOf(self, rhs: Unsigned) -> Unsigned { 15 | if self == rhs * rhs { 1u } else { 0u } 16 | } 17 | } 18 | } 19 | 20 | #[test] 21 | fn test() { 22 | let _: AssertSameOp = (); 23 | let _: AssertSameOp, U7> = (); 24 | let _: AssertSameOp, U1> = (); 25 | let _: AssertSameOp, U0> = (); 26 | } 27 | -------------------------------------------------------------------------------- /tests/macro/recursion.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | use typenum::Unsigned; 3 | 4 | mod binary_gcd { 5 | use super::*; 6 | 7 | typ! { 8 | fn BinaryGcd(lhs: Unsigned, rhs: Unsigned) -> Unsigned { 9 | if lhs == rhs { 10 | lhs 11 | } else if lhs == 0u { 12 | rhs 13 | } else if rhs == 0u { 14 | lhs 15 | } else { 16 | if lhs % 2u == 1u { 17 | if rhs % 2u == 1u { 18 | if lhs > rhs { 19 | let sub: Unsigned = lhs - rhs; 20 | BinaryGcd(sub, rhs) 21 | } else { 22 | let sub: Unsigned = rhs - lhs; 23 | BinaryGcd(sub, lhs) 24 | } 25 | } else { 26 | let div: Unsigned = rhs / 2u; 27 | BinaryGcd(lhs, div) 28 | 29 | } 30 | } else { 31 | if rhs % 2u == 1u { 32 | let div: Unsigned = lhs / 2u; 33 | BinaryGcd(div, rhs) 34 | } else { 35 | let ldiv: Unsigned = lhs / 2u; 36 | let rdiv: Unsigned = rhs / 2u; 37 | BinaryGcd(ldiv, rdiv) * 2u 38 | } 39 | } 40 | } 41 | } 42 | } 43 | 44 | #[test] 45 | fn binary_gcd() { 46 | use typenum::consts::*; 47 | let _: AssertSameOp, U3> = (); 48 | let _: AssertSameOp, U1> = (); 49 | let _: AssertSameOp, U2> = (); 50 | let _: AssertSameOp, U3> = (); 51 | let _: AssertSameOp, U4> = (); 52 | let _: AssertSameOp, U1> = (); 53 | let _: AssertSameOp, U1> = (); 54 | let _: AssertSameOp, tyuint!(18913)> = (); 55 | } 56 | } 57 | --------------------------------------------------------------------------------