diff options
Diffstat (limited to 'compiler/rustc_builtin_macros/src/deriving/generic/ty.rs')
-rw-r--r-- | compiler/rustc_builtin_macros/src/deriving/generic/ty.rs | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs new file mode 100644 index 000000000..4d46f7cd4 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -0,0 +1,203 @@ +//! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use +//! when specifying impls to be derived. + +pub use Ty::*; + +use rustc_ast::ptr::P; +use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind}; +use rustc_expand::base::ExtCtxt; +use rustc_span::source_map::{respan, DUMMY_SP}; +use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_span::Span; + +/// A path, e.g., `::std::option::Option::<i32>` (global). Has support +/// for type parameters. +#[derive(Clone)] +pub struct Path { + path: Vec<Symbol>, + params: Vec<Box<Ty>>, + kind: PathKind, +} + +#[derive(Clone)] +pub enum PathKind { + Local, + Global, + Std, +} + +impl Path { + pub fn new(path: Vec<Symbol>) -> Path { + Path::new_(path, Vec::new(), PathKind::Std) + } + pub fn new_local(path: Symbol) -> Path { + Path::new_(vec![path], Vec::new(), PathKind::Local) + } + pub fn new_(path: Vec<Symbol>, params: Vec<Box<Ty>>, kind: PathKind) -> Path { + Path { path, params, kind } + } + + pub fn to_ty( + &self, + cx: &ExtCtxt<'_>, + span: Span, + self_ty: Ident, + self_generics: &Generics, + ) -> P<ast::Ty> { + cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) + } + pub fn to_path( + &self, + cx: &ExtCtxt<'_>, + span: Span, + self_ty: Ident, + self_generics: &Generics, + ) -> ast::Path { + let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect(); + let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)); + let params = tys.map(GenericArg::Type).collect(); + + match self.kind { + PathKind::Global => cx.path_all(span, true, idents, params), + PathKind::Local => cx.path_all(span, false, idents, params), + PathKind::Std => { + let def_site = cx.with_def_site_ctxt(DUMMY_SP); + idents.insert(0, Ident::new(kw::DollarCrate, def_site)); + cx.path_all(span, false, idents, params) + } + } + } +} + +/// A type. Supports pointers, Self, and literals. +#[derive(Clone)] +pub enum Ty { + Self_, + /// A reference. + Ref(Box<Ty>, ast::Mutability), + /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type + /// parameter, and things like `i32` + Path(Path), + /// For () return types. + Unit, +} + +pub fn self_ref() -> Ty { + Ref(Box::new(Self_), ast::Mutability::Not) +} + +impl Ty { + pub fn to_ty( + &self, + cx: &ExtCtxt<'_>, + span: Span, + self_ty: Ident, + self_generics: &Generics, + ) -> P<ast::Ty> { + match self { + Ref(ty, mutbl) => { + let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); + cx.ty_rptr(span, raw_ty, None, *mutbl) + } + Path(p) => p.to_ty(cx, span, self_ty, self_generics), + Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)), + Unit => { + let ty = ast::TyKind::Tup(vec![]); + cx.ty(span, ty) + } + } + } + + pub fn to_path( + &self, + cx: &ExtCtxt<'_>, + span: Span, + self_ty: Ident, + generics: &Generics, + ) -> ast::Path { + match *self { + Self_ => { + let params: Vec<_> = generics + .params + .iter() + .map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident }) + } + GenericParamKind::Type { .. } => { + GenericArg::Type(cx.ty_ident(span, param.ident)) + } + GenericParamKind::Const { .. } => { + GenericArg::Const(cx.const_ident(span, param.ident)) + } + }) + .collect(); + + cx.path_all(span, false, vec![self_ty], params) + } + Path(ref p) => p.to_path(cx, span, self_ty, generics), + Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"), + Unit => cx.span_bug(span, "unit in a path in generic `derive`"), + } + } +} + +fn mk_ty_param( + cx: &ExtCtxt<'_>, + span: Span, + name: Symbol, + attrs: &[ast::Attribute], + bounds: &[Path], + self_ident: Ident, + self_generics: &Generics, +) -> ast::GenericParam { + let bounds = bounds + .iter() + .map(|b| { + let path = b.to_path(cx, span, self_ident, self_generics); + cx.trait_bound(path) + }) + .collect(); + cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None) +} + +/// Bounds on type parameters. +#[derive(Clone)] +pub struct Bounds { + pub bounds: Vec<(Symbol, Vec<Path>)>, +} + +impl Bounds { + pub fn empty() -> Bounds { + Bounds { bounds: Vec::new() } + } + pub fn to_generics( + &self, + cx: &ExtCtxt<'_>, + span: Span, + self_ty: Ident, + self_generics: &Generics, + ) -> Generics { + let params = self + .bounds + .iter() + .map(|t| { + let (name, ref bounds) = *t; + mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics) + }) + .collect(); + + Generics { + params, + where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span }, + span, + } + } +} + +pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) { + // This constructs a fresh `self` path. + let self_path = cx.expr_self(span); + let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not)); + (self_path, self_ty) +} |