]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/mod.rs
Rollup merge of #40898 - MaloJaffre:remove-unused-feature, r=alexcrichton
[rust.git] / src / libsyntax_ext / deriving / mod.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! The compiler code necessary to implement the `#[derive]` extensions.
12
13 use std::rc::Rc;
14 use syntax::ast;
15 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver};
16 use syntax::ext::build::AstBuilder;
17 use syntax::ext::hygiene::{Mark, SyntaxContext};
18 use syntax::ptr::P;
19 use syntax::symbol::Symbol;
20 use syntax_pos::Span;
21
22 macro_rules! pathvec {
23     ($($x:ident)::+) => (
24         vec![ $( stringify!($x) ),+ ]
25     )
26 }
27
28 macro_rules! path {
29     ($($x:tt)*) => (
30         ::ext::deriving::generic::ty::Path::new( pathvec![ $($x)* ] )
31     )
32 }
33
34 macro_rules! path_local {
35     ($x:ident) => (
36         ::deriving::generic::ty::Path::new_local(stringify!($x))
37     )
38 }
39
40 macro_rules! pathvec_std {
41     ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
42         let mut v = pathvec![$($rest)::+];
43         if let Some(s) = $cx.crate_root {
44             v.insert(0, s);
45         }
46         v
47     })
48 }
49
50 macro_rules! path_std {
51     ($($x:tt)*) => (
52         ::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) )
53     )
54 }
55
56 pub mod bounds;
57 pub mod clone;
58 pub mod encodable;
59 pub mod decodable;
60 pub mod hash;
61 pub mod debug;
62 pub mod default;
63 pub mod custom;
64
65 #[path="cmp/partial_eq.rs"]
66 pub mod partial_eq;
67 #[path="cmp/eq.rs"]
68 pub mod eq;
69 #[path="cmp/partial_ord.rs"]
70 pub mod partial_ord;
71 #[path="cmp/ord.rs"]
72 pub mod ord;
73
74
75 pub mod generic;
76
77 macro_rules! derive_traits {
78     ($( $name:expr => $func:path, )+) => {
79         pub fn is_builtin_trait(name: ast::Name) -> bool {
80             match &*name.as_str() {
81                 $( $name )|+ => true,
82                 _ => false,
83             }
84         }
85
86         pub fn register_builtin_derives(resolver: &mut Resolver) {
87             $(
88                 resolver.add_builtin(
89                     ast::Ident::with_empty_ctxt(Symbol::intern($name)),
90                     Rc::new(SyntaxExtension::BuiltinDerive($func))
91                 );
92             )*
93         }
94     }
95 }
96
97 derive_traits! {
98     "Clone" => clone::expand_deriving_clone,
99
100     "Hash" => hash::expand_deriving_hash,
101
102     "RustcEncodable" => encodable::expand_deriving_rustc_encodable,
103
104     "RustcDecodable" => decodable::expand_deriving_rustc_decodable,
105
106     "PartialEq" => partial_eq::expand_deriving_partial_eq,
107     "Eq" => eq::expand_deriving_eq,
108     "PartialOrd" => partial_ord::expand_deriving_partial_ord,
109     "Ord" => ord::expand_deriving_ord,
110
111     "Debug" => debug::expand_deriving_debug,
112
113     "Default" => default::expand_deriving_default,
114
115     "Send" => bounds::expand_deriving_unsafe_bound,
116     "Sync" => bounds::expand_deriving_unsafe_bound,
117     "Copy" => bounds::expand_deriving_copy,
118
119     // deprecated
120     "Encodable" => encodable::expand_deriving_encodable,
121     "Decodable" => decodable::expand_deriving_decodable,
122 }
123
124 #[inline] // because `name` is a compile-time constant
125 fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
126     if let Some(replacement) = match name {
127         "Encodable" => Some("RustcEncodable"),
128         "Decodable" => Some("RustcDecodable"),
129         _ => None,
130     } {
131         ecx.span_warn(sp,
132                       &format!("derive({}) is deprecated in favor of derive({})",
133                                name,
134                                replacement));
135     }
136 }
137
138 /// Construct a name for the inner type parameter that can't collide with any type parameters of
139 /// the item. This is achieved by starting with a base and then concatenating the names of all
140 /// other type parameters.
141 // FIXME(aburka): use real hygiene when that becomes possible
142 fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
143     let mut typaram = String::from(base);
144     if let Annotatable::Item(ref item) = *item {
145         match item.node {
146             ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) |
147             ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => {
148                 for ty in ty_params.iter() {
149                     typaram.push_str(&ty.ident.name.as_str());
150                 }
151             }
152
153             _ => {}
154         }
155     }
156
157     typaram
158 }
159
160 /// Constructs an expression that calls an intrinsic
161 fn call_intrinsic(cx: &ExtCtxt,
162                   mut span: Span,
163                   intrinsic: &str,
164                   args: Vec<P<ast::Expr>>)
165                   -> P<ast::Expr> {
166     if cx.current_expansion.mark.expn_info().unwrap().callee.allow_internal_unstable {
167         span.ctxt = cx.backtrace();
168     } else { // Avoid instability errors with user defined curstom derives, cc #36316
169         let mut info = cx.current_expansion.mark.expn_info().unwrap();
170         info.callee.allow_internal_unstable = true;
171         let mark = Mark::fresh();
172         mark.set_expn_info(info);
173         span.ctxt = SyntaxContext::empty().apply_mark(mark);
174     }
175     let path = cx.std_path(&["intrinsics", intrinsic]);
176     let call = cx.expr_call_global(span, path, args);
177
178     cx.expr_block(P(ast::Block {
179         stmts: vec![cx.stmt_expr(call)],
180         id: ast::DUMMY_NODE_ID,
181         rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
182         span: span,
183     }))
184 }