use super::*; /// The different kinds of types recognized by the compiler #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub enum Ty { /// A variable-length array (`[T]`) Slice(Box), /// A fixed length array (`[T; n]`) Array(Box, ConstExpr), /// A raw pointer (`*const T` or `*mut T`) Ptr(Box), /// A reference (`&'a T` or `&'a mut T`) Rptr(Option, Box), /// A bare function (e.g. `fn(usize) -> bool`) BareFn(Box), /// The never type (`!`) Never, /// A tuple (`(A, B, C, D, ...)`) Tup(Vec), /// A path (`module::module::...::Type`), optionally /// "qualified", e.g. ` as SomeTrait>::SomeType`. /// /// Type parameters are stored in the Path itself Path(Option, Path), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TraitObject(Vec), /// An `impl Bound1 + Bound2 + Bound3` type /// where `Bound` is a trait or a lifetime. ImplTrait(Vec), /// No-op; kept solely so that we can pretty-print faithfully Paren(Box), /// TyKind::Infer means the type should be inferred instead of it having been /// specified. This can appear anywhere in a type. Infer, /// A macro in the type position. Mac(Mac), } #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct MutTy { pub ty: Ty, pub mutability: Mutability, } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Mutability { Mutable, Immutable, } /// A "Path" is essentially Rust's notion of a name. /// /// It's represented as a sequence of identifiers, /// along with a bunch of supporting information. /// /// E.g. `std::cmp::PartialEq` #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct Path { /// A `::foo` path, is relative to the crate root rather than current /// module (like paths in an import). pub global: bool, /// The segments in the path: the things separated by `::`. pub segments: Vec, } impl From for Path where T: Into { fn from(segment: T) -> Self { Path { global: false, segments: vec![segment.into()], } } } /// A segment of a path: an identifier, an optional lifetime, and a set of types. /// /// E.g. `std`, `String` or `Box` #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct PathSegment { /// The identifier portion of this path segment. pub ident: Ident, /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. Note that /// this is more than just simple syntactic sugar; the use of /// parens affects the region binding rules, so we preserve the /// distinction. pub parameters: PathParameters, } impl From for PathSegment where T: Into { fn from(ident: T) -> Self { PathSegment { ident: ident.into(), parameters: PathParameters::none(), } } } /// Parameters of a path segment. /// /// E.g. `` as in `Foo` or `(A, B)` as in `Foo(A, B)` #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub enum PathParameters { /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>` AngleBracketed(AngleBracketedParameterData), /// The `(A, B)` and `C` in `Foo(A, B) -> C` Parenthesized(ParenthesizedParameterData), } impl PathParameters { pub fn none() -> Self { PathParameters::AngleBracketed(AngleBracketedParameterData::default()) } pub fn is_empty(&self) -> bool { match *self { PathParameters::AngleBracketed(ref bracketed) => { bracketed.lifetimes.is_empty() && bracketed.types.is_empty() && bracketed.bindings.is_empty() } PathParameters::Parenthesized(_) => false, } } } /// A path like `Foo<'a, T>` #[derive(Debug, Clone, Eq, PartialEq, Default, Hash)] pub struct AngleBracketedParameterData { /// The lifetime parameters for this path segment. pub lifetimes: Vec, /// The type parameters for this path segment, if present. pub types: Vec, /// Bindings (equality constraints) on associated types, if present. /// /// E.g., `Foo`. pub bindings: Vec, } /// Bind a type to an associated type: `A=Foo`. #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct TypeBinding { pub ident: Ident, pub ty: Ty, } /// A path like `Foo(A,B) -> C` #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct ParenthesizedParameterData { /// `(A, B)` pub inputs: Vec, /// `C` pub output: Option, } #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct PolyTraitRef { /// The `'a` in `<'a> Foo<&'a T>` pub bound_lifetimes: Vec, /// The `Foo<&'a T>` in `<'a> Foo<&'a T>` pub trait_ref: Path, } /// The explicit Self type in a "qualified path". The actual /// path, including the trait and the associated item, is stored /// separately. `position` represents the index of the associated /// item qualified with this Self type. /// /// ```rust,ignore /// as a::b::Trait>::AssociatedItem /// ^~~~~ ~~~~~~~~~~~~~~^ /// ty position = 3 /// /// >::AssociatedItem /// ^~~~~ ^ /// ty position = 0 /// ``` #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct QSelf { pub ty: Box, pub position: usize, } #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct BareFnTy { pub unsafety: Unsafety, pub abi: Option, pub lifetimes: Vec, pub inputs: Vec, pub output: FunctionRetTy, pub variadic: bool, } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Unsafety { Unsafe, Normal, } #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub enum Abi { Named(String), Rust, } /// An argument in a function type. /// /// E.g. `bar: usize` as in `fn foo(bar: usize)` #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct BareFnArg { pub name: Option, pub ty: Ty, } #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub enum FunctionRetTy { /// Return type is not specified. /// /// Functions default to `()` and /// closures default to inference. Span points to where return /// type would be inserted. Default, /// Everything else Ty(Ty), } #[cfg(feature = "parsing")] pub mod parsing { use super::*; use {TyParamBound, TraitBoundModifier}; #[cfg(feature = "full")] use ConstExpr; #[cfg(feature = "full")] use constant::parsing::const_expr; #[cfg(feature = "full")] use expr::parsing::expr; use generics::parsing::{lifetime, lifetime_def, ty_param_bound, bound_lifetimes}; use ident::parsing::ident; use lit::parsing::quoted_string; use mac::parsing::mac; use std::str; named!(pub ty -> Ty, alt!( ty_paren // must be before ty_tup | ty_mac // must be before ty_path | ty_path // must be before ty_poly_trait_ref | ty_vec | ty_array | ty_ptr | ty_rptr | ty_bare_fn | ty_never | ty_tup | ty_poly_trait_ref | ty_impl_trait )); named!(ty_mac -> Ty, map!(mac, Ty::Mac)); named!(ty_vec -> Ty, do_parse!( punct!("[") >> elem: ty >> punct!("]") >> (Ty::Slice(Box::new(elem))) )); named!(ty_array -> Ty, do_parse!( punct!("[") >> elem: ty >> punct!(";") >> len: array_len >> punct!("]") >> (Ty::Array(Box::new(elem), len)) )); #[cfg(not(feature = "full"))] use constant::parsing::const_expr as array_len; #[cfg(feature = "full")] named!(array_len -> ConstExpr, alt!( terminated!(const_expr, after_array_len) | terminated!(expr, after_array_len) => { ConstExpr::Other } )); #[cfg(feature = "full")] named!(after_array_len -> &str, peek!(punct!("]"))); named!(ty_ptr -> Ty, do_parse!( punct!("*") >> mutability: alt!( keyword!("const") => { |_| Mutability::Immutable } | keyword!("mut") => { |_| Mutability::Mutable } ) >> target: ty >> (Ty::Ptr(Box::new(MutTy { ty: target, mutability: mutability, }))) )); named!(ty_rptr -> Ty, do_parse!( punct!("&") >> life: option!(lifetime) >> mutability: mutability >> target: ty >> (Ty::Rptr(life, Box::new(MutTy { ty: target, mutability: mutability, }))) )); named!(ty_bare_fn -> Ty, do_parse!( lifetimes: opt_vec!(do_parse!( keyword!("for") >> punct!("<") >> lifetimes: terminated_list!(punct!(","), lifetime_def) >> punct!(">") >> (lifetimes) )) >> unsafety: unsafety >> abi: option!(abi) >> keyword!("fn") >> punct!("(") >> inputs: separated_list!(punct!(","), fn_arg) >> trailing_comma: option!(punct!(",")) >> variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >> punct!(")") >> output: option!(preceded!( punct!("->"), ty )) >> (Ty::BareFn(Box::new(BareFnTy { unsafety: unsafety, abi: abi, lifetimes: lifetimes, inputs: inputs, output: match output { Some(ty) => FunctionRetTy::Ty(ty), None => FunctionRetTy::Default, }, variadic: variadic.is_some(), }))) )); named!(ty_never -> Ty, map!(punct!("!"), |_| Ty::Never)); named!(ty_tup -> Ty, do_parse!( punct!("(") >> elems: terminated_list!(punct!(","), ty) >> punct!(")") >> (Ty::Tup(elems)) )); named!(ty_path -> Ty, do_parse!( qpath: qpath >> parenthesized: cond!( qpath.1.segments.last().unwrap().parameters == PathParameters::none(), option!(parenthesized_parameter_data) ) >> bounds: many0!(preceded!(punct!("+"), ty_param_bound)) >> ({ let (qself, mut path) = qpath; if let Some(Some(parenthesized)) = parenthesized { path.segments.last_mut().unwrap().parameters = parenthesized; } if bounds.is_empty() { Ty::Path(qself, path) } else { let path = TyParamBound::Trait( PolyTraitRef { bound_lifetimes: Vec::new(), trait_ref: path, }, TraitBoundModifier::None, ); let bounds = Some(path).into_iter().chain(bounds).collect(); Ty::TraitObject(bounds) } }) )); named!(parenthesized_parameter_data -> PathParameters, do_parse!( punct!("(") >> inputs: terminated_list!(punct!(","), ty) >> punct!(")") >> output: option!(preceded!( punct!("->"), ty )) >> (PathParameters::Parenthesized( ParenthesizedParameterData { inputs: inputs, output: output, }, )) )); named!(pub qpath -> (Option, Path), alt!( map!(path, |p| (None, p)) | do_parse!( punct!("<") >> this: map!(ty, Box::new) >> path: option!(preceded!( keyword!("as"), path )) >> punct!(">") >> punct!("::") >> rest: separated_nonempty_list!(punct!("::"), path_segment) >> ({ match path { Some(mut path) => { let pos = path.segments.len(); path.segments.extend(rest); (Some(QSelf { ty: this, position: pos }), path) } None => { (Some(QSelf { ty: this, position: 0 }), Path { global: false, segments: rest, }) } } }) ) | map!(keyword!("self"), |_| (None, "self".into())) )); named!(ty_poly_trait_ref -> Ty, map!( separated_nonempty_list!(punct!("+"), ty_param_bound), Ty::TraitObject )); named!(ty_impl_trait -> Ty, do_parse!( keyword!("impl") >> elem: separated_nonempty_list!(punct!("+"), ty_param_bound) >> (Ty::ImplTrait(elem)) )); named!(ty_paren -> Ty, do_parse!( punct!("(") >> elem: ty >> punct!(")") >> (Ty::Paren(Box::new(elem))) )); named!(pub mutability -> Mutability, alt!( keyword!("mut") => { |_| Mutability::Mutable } | epsilon!() => { |_| Mutability::Immutable } )); named!(pub path -> Path, do_parse!( global: option!(punct!("::")) >> segments: separated_nonempty_list!(punct!("::"), path_segment) >> (Path { global: global.is_some(), segments: segments, }) )); named!(path_segment -> PathSegment, alt!( do_parse!( id: option!(ident) >> punct!("<") >> lifetimes: separated_list!(punct!(","), lifetime) >> types: opt_vec!(preceded!( cond!(!lifetimes.is_empty(), punct!(",")), separated_nonempty_list!( punct!(","), terminated!(ty, not!(punct!("="))) ) )) >> bindings: opt_vec!(preceded!( cond!(!lifetimes.is_empty() || !types.is_empty(), punct!(",")), separated_nonempty_list!(punct!(","), type_binding) )) >> cond!(!lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty(), option!(punct!(","))) >> punct!(">") >> (PathSegment { ident: id.unwrap_or_else(|| "".into()), parameters: PathParameters::AngleBracketed( AngleBracketedParameterData { lifetimes: lifetimes, types: types, bindings: bindings, } ), }) ) | map!(ident, Into::into) | map!(alt!( keyword!("super") | keyword!("self") | keyword!("Self") ), Into::into) )); named!(type_binding -> TypeBinding, do_parse!( id: ident >> punct!("=") >> ty: ty >> (TypeBinding { ident: id, ty: ty, }) )); named!(pub poly_trait_ref -> PolyTraitRef, do_parse!( bound_lifetimes: bound_lifetimes >> trait_ref: path >> parenthesized: option!(cond_reduce!( trait_ref.segments.last().unwrap().parameters == PathParameters::none(), parenthesized_parameter_data )) >> ({ let mut trait_ref = trait_ref; if let Some(parenthesized) = parenthesized { trait_ref.segments.last_mut().unwrap().parameters = parenthesized; } PolyTraitRef { bound_lifetimes: bound_lifetimes, trait_ref: trait_ref, } }) )); named!(pub fn_arg -> BareFnArg, do_parse!( name: option!(do_parse!( name: ident >> punct!(":") >> not!(tag!(":")) >> // not :: (name) )) >> ty: ty >> (BareFnArg { name: name, ty: ty, }) )); named!(pub unsafety -> Unsafety, alt!( keyword!("unsafe") => { |_| Unsafety::Unsafe } | epsilon!() => { |_| Unsafety::Normal } )); named!(pub abi -> Abi, do_parse!( keyword!("extern") >> name: option!(quoted_string) >> (match name { Some(name) => Abi::Named(name), None => Abi::Rust, }) )); } #[cfg(feature = "printing")] mod printing { use super::*; use quote::{Tokens, ToTokens}; impl ToTokens for Ty { fn to_tokens(&self, tokens: &mut Tokens) { match *self { Ty::Slice(ref inner) => { tokens.append("["); inner.to_tokens(tokens); tokens.append("]"); } Ty::Array(ref inner, ref len) => { tokens.append("["); inner.to_tokens(tokens); tokens.append(";"); len.to_tokens(tokens); tokens.append("]"); } Ty::Ptr(ref target) => { tokens.append("*"); match target.mutability { Mutability::Mutable => tokens.append("mut"), Mutability::Immutable => tokens.append("const"), } target.ty.to_tokens(tokens); } Ty::Rptr(ref lifetime, ref target) => { tokens.append("&"); lifetime.to_tokens(tokens); target.mutability.to_tokens(tokens); target.ty.to_tokens(tokens); } Ty::BareFn(ref func) => { func.to_tokens(tokens); } Ty::Never => { tokens.append("!"); } Ty::Tup(ref elems) => { tokens.append("("); tokens.append_separated(elems, ","); if elems.len() == 1 { tokens.append(","); } tokens.append(")"); } Ty::Path(None, ref path) => { path.to_tokens(tokens); } Ty::Path(Some(ref qself), ref path) => { tokens.append("<"); qself.ty.to_tokens(tokens); if qself.position > 0 { tokens.append("as"); for (i, segment) in path.segments .iter() .take(qself.position) .enumerate() { if i > 0 || path.global { tokens.append("::"); } segment.to_tokens(tokens); } } tokens.append(">"); for segment in path.segments.iter().skip(qself.position) { tokens.append("::"); segment.to_tokens(tokens); } } Ty::TraitObject(ref bounds) => { tokens.append_separated(bounds, "+"); } Ty::ImplTrait(ref bounds) => { tokens.append("impl"); tokens.append_separated(bounds, "+"); } Ty::Paren(ref inner) => { tokens.append("("); inner.to_tokens(tokens); tokens.append(")"); } Ty::Infer => { tokens.append("_"); } Ty::Mac(ref mac) => mac.to_tokens(tokens), } } } impl ToTokens for Mutability { fn to_tokens(&self, tokens: &mut Tokens) { if let Mutability::Mutable = *self { tokens.append("mut"); } } } impl ToTokens for Path { fn to_tokens(&self, tokens: &mut Tokens) { for (i, segment) in self.segments.iter().enumerate() { if i > 0 || self.global { tokens.append("::"); } segment.to_tokens(tokens); } } } impl ToTokens for PathSegment { fn to_tokens(&self, tokens: &mut Tokens) { self.ident.to_tokens(tokens); if self.ident.as_ref().is_empty() && self.parameters.is_empty() { tokens.append("<"); tokens.append(">"); } else { self.parameters.to_tokens(tokens); } } } impl ToTokens for PathParameters { fn to_tokens(&self, tokens: &mut Tokens) { match *self { PathParameters::AngleBracketed(ref parameters) => { parameters.to_tokens(tokens); } PathParameters::Parenthesized(ref parameters) => { parameters.to_tokens(tokens); } } } } impl ToTokens for AngleBracketedParameterData { fn to_tokens(&self, tokens: &mut Tokens) { let has_lifetimes = !self.lifetimes.is_empty(); let has_types = !self.types.is_empty(); let has_bindings = !self.bindings.is_empty(); if !has_lifetimes && !has_types && !has_bindings { return; } tokens.append("<"); let mut first = true; for lifetime in &self.lifetimes { if !first { tokens.append(","); } lifetime.to_tokens(tokens); first = false; } for ty in &self.types { if !first { tokens.append(","); } ty.to_tokens(tokens); first = false; } for binding in &self.bindings { if !first { tokens.append(","); } binding.to_tokens(tokens); first = false; } tokens.append(">"); } } impl ToTokens for TypeBinding { fn to_tokens(&self, tokens: &mut Tokens) { self.ident.to_tokens(tokens); tokens.append("="); self.ty.to_tokens(tokens); } } impl ToTokens for ParenthesizedParameterData { fn to_tokens(&self, tokens: &mut Tokens) { tokens.append("("); tokens.append_separated(&self.inputs, ","); tokens.append(")"); if let Some(ref output) = self.output { tokens.append("->"); output.to_tokens(tokens); } } } impl ToTokens for PolyTraitRef { fn to_tokens(&self, tokens: &mut Tokens) { if !self.bound_lifetimes.is_empty() { tokens.append("for"); tokens.append("<"); tokens.append_separated(&self.bound_lifetimes, ","); tokens.append(">"); } self.trait_ref.to_tokens(tokens); } } impl ToTokens for BareFnTy { fn to_tokens(&self, tokens: &mut Tokens) { if !self.lifetimes.is_empty() { tokens.append("for"); tokens.append("<"); tokens.append_separated(&self.lifetimes, ","); tokens.append(">"); } self.unsafety.to_tokens(tokens); self.abi.to_tokens(tokens); tokens.append("fn"); tokens.append("("); tokens.append_separated(&self.inputs, ","); if self.variadic { if !self.inputs.is_empty() { tokens.append(","); } tokens.append("..."); } tokens.append(")"); if let FunctionRetTy::Ty(ref ty) = self.output { tokens.append("->"); ty.to_tokens(tokens); } } } impl ToTokens for BareFnArg { fn to_tokens(&self, tokens: &mut Tokens) { if let Some(ref name) = self.name { name.to_tokens(tokens); tokens.append(":"); } self.ty.to_tokens(tokens); } } impl ToTokens for Unsafety { fn to_tokens(&self, tokens: &mut Tokens) { match *self { Unsafety::Unsafe => tokens.append("unsafe"), Unsafety::Normal => { // nothing } } } } impl ToTokens for Abi { fn to_tokens(&self, tokens: &mut Tokens) { tokens.append("extern"); match *self { Abi::Named(ref named) => named.to_tokens(tokens), Abi::Rust => {} } } } }