]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/mod.rs
tests: prefer edition: directives to compile-flags:--edition.
[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 rustc_data_structures::sync::Lrc;
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! span_err_if_not_stage0 {
23     ($cx:expr, $sp:expr, $code:ident, $text:tt) => {
24         #[cfg(not(stage0))] {
25             span_err!($cx, $sp, $code, $text)
26         }
27         #[cfg(stage0)] {
28             $cx.span_err($sp, $text)
29         }
30     }
31 }
32
33 macro path_local($x:ident) {
34     generic::ty::Path::new_local(stringify!($x))
35 }
36
37 macro pathvec_std($cx:expr, $($rest:ident)::+) {{
38     vec![ $( stringify!($rest) ),+ ]
39 }}
40
41 macro path_std($($x:tt)*) {
42     generic::ty::Path::new( pathvec_std!( $($x)* ) )
43 }
44
45 pub mod bounds;
46 pub mod clone;
47 pub mod encodable;
48 pub mod decodable;
49 pub mod hash;
50 pub mod debug;
51 pub mod default;
52 pub mod custom;
53
54 #[path="cmp/partial_eq.rs"]
55 pub mod partial_eq;
56 #[path="cmp/eq.rs"]
57 pub mod eq;
58 #[path="cmp/partial_ord.rs"]
59 pub mod partial_ord;
60 #[path="cmp/ord.rs"]
61 pub mod ord;
62
63
64 pub mod generic;
65
66 macro_rules! derive_traits {
67     ($( $name:expr => $func:path, )+) => {
68         pub fn is_builtin_trait(name: ast::Name) -> bool {
69             match &*name.as_str() {
70                 $( $name )|+ => true,
71                 _ => false,
72             }
73         }
74
75         pub fn register_builtin_derives(resolver: &mut dyn Resolver) {
76             $(
77                 resolver.add_builtin(
78                     ast::Ident::with_empty_ctxt(Symbol::intern($name)),
79                     Lrc::new(SyntaxExtension::BuiltinDerive($func))
80                 );
81             )*
82         }
83     }
84 }
85
86 derive_traits! {
87     "Clone" => clone::expand_deriving_clone,
88
89     "Hash" => hash::expand_deriving_hash,
90
91     "RustcEncodable" => encodable::expand_deriving_rustc_encodable,
92
93     "RustcDecodable" => decodable::expand_deriving_rustc_decodable,
94
95     "PartialEq" => partial_eq::expand_deriving_partial_eq,
96     "Eq" => eq::expand_deriving_eq,
97     "PartialOrd" => partial_ord::expand_deriving_partial_ord,
98     "Ord" => ord::expand_deriving_ord,
99
100     "Debug" => debug::expand_deriving_debug,
101
102     "Default" => default::expand_deriving_default,
103
104     "Send" => bounds::expand_deriving_unsafe_bound,
105     "Sync" => bounds::expand_deriving_unsafe_bound,
106     "Copy" => bounds::expand_deriving_copy,
107
108     // deprecated
109     "Encodable" => encodable::expand_deriving_encodable,
110     "Decodable" => decodable::expand_deriving_decodable,
111 }
112
113 #[inline] // because `name` is a compile-time constant
114 fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
115     if let Some(replacement) = match name {
116         "Encodable" => Some("RustcEncodable"),
117         "Decodable" => Some("RustcDecodable"),
118         _ => None,
119     } {
120         ecx.span_warn(sp,
121                       &format!("derive({}) is deprecated in favor of derive({})",
122                                name,
123                                replacement));
124     }
125 }
126
127 /// Construct a name for the inner type parameter that can't collide with any type parameters of
128 /// the item. This is achieved by starting with a base and then concatenating the names of all
129 /// other type parameters.
130 // FIXME(aburka): use real hygiene when that becomes possible
131 fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
132     let mut typaram = String::from(base);
133     if let Annotatable::Item(ref item) = *item {
134         match item.node {
135             ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) |
136             ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => {
137                 for param in params {
138                     match param.kind {
139                         ast::GenericParamKind::Type { .. } => {
140                             typaram.push_str(&param.ident.as_str());
141                         }
142                         _ => {}
143                     }
144                 }
145             }
146
147             _ => {}
148         }
149     }
150
151     typaram
152 }
153
154 /// Constructs an expression that calls an intrinsic
155 fn call_intrinsic(cx: &ExtCtxt,
156                   mut span: Span,
157                   intrinsic: &str,
158                   args: Vec<P<ast::Expr>>)
159                   -> P<ast::Expr> {
160     if cx.current_expansion.mark.expn_info().unwrap().allow_internal_unstable {
161         span = span.with_ctxt(cx.backtrace());
162     } else { // Avoid instability errors with user defined curstom derives, cc #36316
163         let mut info = cx.current_expansion.mark.expn_info().unwrap();
164         info.allow_internal_unstable = true;
165         let mark = Mark::fresh(Mark::root());
166         mark.set_expn_info(info);
167         span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
168     }
169     let path = cx.std_path(&["intrinsics", intrinsic]);
170     let call = cx.expr_call_global(span, path, args);
171
172     cx.expr_block(P(ast::Block {
173         stmts: vec![cx.stmt_expr(call)],
174         id: ast::DUMMY_NODE_ID,
175         rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
176         span,
177         recovered: false,
178     }))
179 }