diff options
| author | bors <bors@rust-lang.org> | 2015-12-16 10:09:36 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-12-16 10:09:36 +0000 |
| commit | ce7bc51933e2facb4eca029ac17b398f372f5b41 (patch) | |
| tree | 84695672384f43235514ea531a92c793122c3837 /src/libsyntax | |
| parent | ac2c5ff0241bdd090af11a74566bd00f03ae8ae0 (diff) | |
| parent | 0883f10550299af021bbdec95b98693b395153b6 (diff) | |
| download | rust-ce7bc51933e2facb4eca029ac17b398f372f5b41.tar.gz rust-ce7bc51933e2facb4eca029ac17b398f372f5b41.zip | |
Auto merge of #30300 - sanxiyn:syntax-ext, r=nikomatsakis
This reduces iteration time (`make rustc-stage1`) for moved syntax extensions from 11 minutes to 3 minutes on my machine. Because of the signature change, this is a [breaking-change] for people directly calling `expand_crate`. I think it is rare: from GitHub search, only case I found is [glassful](https://github.com/kmcallister/glassful).
Diffstat (limited to 'src/libsyntax')
26 files changed, 20 insertions, 5257 deletions
diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs deleted file mode 100644 index b4f29f83726..00000000000 --- a/src/libsyntax/ext/asm.rs +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/* - * Inline assembly support. - */ -use self::State::*; - -use ast; -use codemap; -use codemap::Span; -use ext::base; -use ext::base::*; -use feature_gate; -use parse::token::{intern, InternedString}; -use parse::token; -use ptr::P; -use syntax::ast::AsmDialect; - -enum State { - Asm, - Outputs, - Inputs, - Clobbers, - Options, - StateNone -} - -impl State { - fn next(&self) -> State { - match *self { - Asm => Outputs, - Outputs => Inputs, - Inputs => Clobbers, - Clobbers => Options, - Options => StateNone, - StateNone => StateNone - } - } -} - -const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"]; - -pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box<base::MacResult+'cx> { - if !cx.ecfg.enable_asm() { - feature_gate::emit_feature_err( - &cx.parse_sess.span_diagnostic, "asm", sp, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_ASM); - return DummyResult::expr(sp); - } - - let mut p = cx.new_parser_from_tts(tts); - let mut asm = InternedString::new(""); - let mut asm_str_style = None; - let mut outputs = Vec::new(); - let mut inputs = Vec::new(); - let mut clobs = Vec::new(); - let mut volatile = false; - let mut alignstack = false; - let mut dialect = AsmDialect::Att; - - let mut state = Asm; - - 'statement: loop { - match state { - Asm => { - if asm_str_style.is_some() { - // If we already have a string with instructions, - // ending up in Asm state again is an error. - cx.span_err(sp, "malformed inline assembly"); - return DummyResult::expr(sp); - } - let (s, style) = match expr_to_string(cx, panictry!(p.parse_expr()), - "inline assembly must be a string literal") { - Some((s, st)) => (s, st), - // let compilation continue - None => return DummyResult::expr(sp), - }; - asm = s; - asm_str_style = Some(style); - } - Outputs => { - while p.token != token::Eof && - p.token != token::Colon && - p.token != token::ModSep { - - if !outputs.is_empty() { - panictry!(p.eat(&token::Comma)); - } - - let (constraint, _str_style) = panictry!(p.parse_str()); - - let span = p.last_span; - - panictry!(p.expect(&token::OpenDelim(token::Paren))); - let out = panictry!(p.parse_expr()); - panictry!(p.expect(&token::CloseDelim(token::Paren))); - - // Expands a read+write operand into two operands. - // - // Use '+' modifier when you want the same expression - // to be both an input and an output at the same time. - // It's the opposite of '=&' which means that the memory - // cannot be shared with any other operand (usually when - // a register is clobbered early.) - let output = match constraint.slice_shift_char() { - Some(('=', _)) => None, - Some(('+', operand)) => { - Some(token::intern_and_get_ident(&format!( - "={}", operand))) - } - _ => { - cx.span_err(span, "output operand constraint lacks '=' or '+'"); - None - } - }; - - let is_rw = output.is_some(); - let is_indirect = constraint.contains("*"); - outputs.push(ast::InlineAsmOutput { - constraint: output.unwrap_or(constraint), - expr: out, - is_rw: is_rw, - is_indirect: is_indirect, - }); - } - } - Inputs => { - while p.token != token::Eof && - p.token != token::Colon && - p.token != token::ModSep { - - if !inputs.is_empty() { - panictry!(p.eat(&token::Comma)); - } - - let (constraint, _str_style) = panictry!(p.parse_str()); - - if constraint.starts_with("=") { - cx.span_err(p.last_span, "input operand constraint contains '='"); - } else if constraint.starts_with("+") { - cx.span_err(p.last_span, "input operand constraint contains '+'"); - } - - panictry!(p.expect(&token::OpenDelim(token::Paren))); - let input = panictry!(p.parse_expr()); - panictry!(p.expect(&token::CloseDelim(token::Paren))); - - inputs.push((constraint, input)); - } - } - Clobbers => { - while p.token != token::Eof && - p.token != token::Colon && - p.token != token::ModSep { - - if !clobs.is_empty() { - panictry!(p.eat(&token::Comma)); - } - - let (s, _str_style) = panictry!(p.parse_str()); - - if OPTIONS.iter().any(|&opt| s == opt) { - cx.span_warn(p.last_span, "expected a clobber, found an option"); - } - clobs.push(s); - } - } - Options => { - let (option, _str_style) = panictry!(p.parse_str()); - - if option == "volatile" { - // Indicates that the inline assembly has side effects - // and must not be optimized out along with its outputs. - volatile = true; - } else if option == "alignstack" { - alignstack = true; - } else if option == "intel" { - dialect = AsmDialect::Intel; - } else { - cx.span_warn(p.last_span, "unrecognized option"); - } - - if p.token == token::Comma { - panictry!(p.eat(&token::Comma)); - } - } - StateNone => () - } - - loop { - // MOD_SEP is a double colon '::' without space in between. - // When encountered, the state must be advanced twice. - match (&p.token, state.next(), state.next().next()) { - (&token::Colon, StateNone, _) | - (&token::ModSep, _, StateNone) => { - panictry!(p.bump()); - break 'statement; - } - (&token::Colon, st, _) | - (&token::ModSep, _, st) => { - panictry!(p.bump()); - state = st; - } - (&token::Eof, _, _) => break 'statement, - _ => break - } - } - } - - let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: sp, - callee: codemap::NameAndSpan { - format: codemap::MacroBang(intern("asm")), - span: None, - allow_internal_unstable: false, - }, - }); - - MacEager::expr(P(ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprInlineAsm(ast::InlineAsm { - asm: token::intern_and_get_ident(&asm), - asm_str_style: asm_str_style.unwrap(), - outputs: outputs, - inputs: inputs, - clobbers: clobs, - volatile: volatile, - alignstack: alignstack, - dialect: dialect, - expn_id: expn_id, - }), - span: sp, - attrs: None, - })) -} diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 22315454f89..9d62e407cb9 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -464,26 +464,6 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) let mut syntax_expanders = SyntaxEnv::new(); syntax_expanders.insert(intern("macro_rules"), MacroRulesTT); - syntax_expanders.insert(intern("format_args"), - // format_args uses `unstable` things internally. - NormalTT(Box::new(ext::format::expand_format_args), None, true)); - syntax_expanders.insert(intern("env"), - builtin_normal_expander( - ext::env::expand_env)); - syntax_expanders.insert(intern("option_env"), - builtin_normal_expander( - ext::env::expand_option_env)); - syntax_expanders.insert(intern("concat_idents"), - builtin_normal_expander( - ext::concat_idents::expand_syntax_ext)); - syntax_expanders.insert(intern("concat"), - builtin_normal_expander( - ext::concat::expand_syntax_ext)); - syntax_expanders.insert(intern("log_syntax"), - builtin_normal_expander( - ext::log_syntax::expand_syntax_ext)); - - ext::deriving::register_all(&mut syntax_expanders); if ecfg.enable_quotes() { // Quasi-quoting expanders @@ -552,15 +532,6 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) syntax_expanders.insert(intern("module_path"), builtin_normal_expander( ext::source_util::expand_mod)); - syntax_expanders.insert(intern("asm"), - builtin_normal_expander( - ext::asm::expand_asm)); - syntax_expanders.insert(intern("cfg"), - builtin_normal_expander( - ext::cfg::expand_cfg)); - syntax_expanders.insert(intern("trace_macros"), - builtin_normal_expander( - ext::trace_macros::expand_trace_macros)); syntax_expanders } diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs deleted file mode 100644 index e100355e4f8..00000000000 --- a/src/libsyntax/ext/cfg.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// The compiler code necessary to support the cfg! extension, which expands to -/// a literal `true` or `false` based on whether the given cfg matches the -/// current compilation environment. - -use ast; -use codemap::Span; -use ext::base::*; -use ext::base; -use ext::build::AstBuilder; -use attr; -use attr::*; -use parse::token; -use config::CfgDiagReal; - -pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, - sp: Span, - tts: &[ast::TokenTree]) - -> Box<base::MacResult+'static> { - let mut p = cx.new_parser_from_tts(tts); - let cfg = panictry!(p.parse_meta_item()); - - if !panictry!(p.eat(&token::Eof)){ - cx.span_err(sp, "expected 1 cfg-pattern"); - return DummyResult::expr(sp); - } - - let matches_cfg = { - let mut diag = CfgDiagReal { - diag: &cx.parse_sess.span_diagnostic, - feature_gated_cfgs: cx.feature_gated_cfgs, - }; - attr::cfg_matches(&cx.cfg, &cfg, &mut diag) - }; - MacEager::expr(cx.expr_bool(sp, matches_cfg)) -} diff --git a/src/libsyntax/ext/concat.rs b/src/libsyntax/ext/concat.rs deleted file mode 100644 index 71430b7aad5..00000000000 --- a/src/libsyntax/ext/concat.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast; -use codemap; -use ext::base; -use ext::build::AstBuilder; -use parse::token; - -use std::string::String; - -pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, - sp: codemap::Span, - tts: &[ast::TokenTree]) - -> Box<base::MacResult+'static> { - let es = match base::get_exprs_from_tts(cx, sp, tts) { - Some(e) => e, - None => return base::DummyResult::expr(sp) - }; - let mut accumulator = String::new(); - for e in es { - match e.node { - ast::ExprLit(ref lit) => { - match lit.node { - ast::LitStr(ref s, _) | - ast::LitFloat(ref s, _) | - ast::LitFloatUnsuffixed(ref s) => { - accumulator.push_str(&s); - } - ast::LitChar(c) => { - accumulator.push(c); - } - ast::LitInt(i, ast::UnsignedIntLit(_)) | - ast::LitInt(i, ast::SignedIntLit(_, ast::Plus)) | - ast::LitInt(i, ast::UnsuffixedIntLit(ast::Plus)) => { - accumulator.push_str(&format!("{}", i)); - } - ast::LitInt(i, ast::SignedIntLit(_, ast::Minus)) | - ast::LitInt(i, ast::UnsuffixedIntLit(ast::Minus)) => { - accumulator.push_str(&format!("-{}", i)); - } - ast::LitBool(b) => { - accumulator.push_str(&format!("{}", b)); - } - ast::LitByte(..) | - ast::LitByteStr(..) => { - cx.span_err(e.span, "cannot concatenate a byte string literal"); - } - } - } - _ => { - cx.span_err(e.span, "expected a literal"); - } - } - } - base::MacEager::expr(cx.expr_str( - sp, - token::intern_and_get_ident(&accumulator[..]))) -} diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs deleted file mode 100644 index c2233202b2f..00000000000 --- a/src/libsyntax/ext/concat_idents.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{self, TokenTree}; -use codemap::Span; -use ext::base::*; -use ext::base; -use feature_gate; -use parse::token; -use parse::token::str_to_ident; -use ptr::P; - -pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) - -> Box<base::MacResult+'cx> { - if !cx.ecfg.enable_concat_idents() { - feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, - "concat_idents", - sp, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_CONCAT_IDENTS); - return base::DummyResult::expr(sp); - } - - let mut res_str = String::new(); - for (i, e) in tts.iter().enumerate() { - if i & 1 == 1 { - match *e { - TokenTree::Token(_, token::Comma) => {}, - _ => { - cx.span_err(sp, "concat_idents! expecting comma."); - return DummyResult::expr(sp); - }, - } - } else { - match *e { - TokenTree::Token(_, token::Ident(ident, _)) => { - res_str.push_str(&ident.name.as_str()) - }, - _ => { - cx.span_err(sp, "concat_idents! requires ident args."); - return DummyResult::expr(sp); - }, - } - } - } - let res = str_to_ident(&res_str); - - let e = P(ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprPath(None, - ast::Path { - span: sp, - global: false, - segments: vec!( - ast::PathSegment { - identifier: res, - parameters: ast::PathParameters::none(), - } - ) - } - ), - span: sp, - attrs: None, - }); - MacEager::expr(e) -} diff --git a/src/libsyntax/ext/deriving/bounds.rs b/src/libsyntax/ext/deriving/bounds.rs deleted file mode 100644 index 87a6d0805b5..00000000000 --- a/src/libsyntax/ext/deriving/bounds.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::MetaItem; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; - -pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt, - span: Span, - _: &MetaItem, - _: &Annotatable, - _: &mut FnMut(Annotatable)) -{ - cx.span_err(span, "this unsafe trait should be implemented explicitly"); -} - -pub fn expand_deriving_copy(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - let mut v = cx.crate_root.map(|s| vec![s]).unwrap_or(Vec::new()); - v.push("marker"); - v.push("Copy"); - let path = Path::new(v); - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path, - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: Vec::new(), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push); -} diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs deleted file mode 100644 index f1a2983479c..00000000000 --- a/src/libsyntax/ext/deriving/clone.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_clone(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::clone::Clone), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "clone", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: Vec::new(), - ret_ty: Self_, - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|c, s, sub| { - cs_clone("Clone", c, s, sub) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn cs_clone( - name: &str, - cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure) -> P<Expr> { - let ctor_path; - let all_fields; - let fn_path = cx.std_path(&["clone", "Clone", "clone"]); - let subcall = |field: &FieldInfo| { - let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; - - cx.expr_call_global(field.span, fn_path.clone(), args) - }; - - match *substr.fields { - Struct(ref af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident]); - all_fields = af; - } - EnumMatching(_, variant, ref af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.name]); - all_fields = af; - }, - EnumNonMatchingCollapsed (..) => { - cx.span_bug(trait_span, - &format!("non-matching enum variants in \ - `derive({})`", name)) - } - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, - &format!("static method in `derive({})`", name)) - } - } - - if !all_fields.is_empty() && all_fields[0].name.is_none() { - // enum-like - let subcalls = all_fields.iter().map(subcall).collect(); - let path = cx.expr_path(ctor_path); - cx.expr_call(trait_span, path, subcalls) - } else { - // struct-like - let fields = all_fields.iter().map(|field| { - let ident = match field.name { - Some(i) => i, - None => { - cx.span_bug(trait_span, - &format!("unnamed field in normal struct in \ - `derive({})`", name)) - } - }; - cx.field_imm(field.span, ident, subcall(field)) - }).collect::<Vec<_>>(); - - if fields.is_empty() { - // no fields, so construct like `None` - cx.expr_path(ctor_path) - } else { - cx.expr_struct(trait_span, ctor_path, fields) - } - } -} diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs deleted file mode 100644 index bd6b27fb44e..00000000000 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_eq(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> { - cs_same_method( - |cx, span, exprs| { - // create `a.<method>(); b.<method>(); c.<method>(); ...` - // (where method is `assert_receiver_is_total_eq`) - let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); - let block = cx.block(span, stmts, None); - cx.expr_block(block) - }, - Box::new(|cx, sp, _, _| { - cx.span_bug(sp, "non matching enums in derive(Eq)?") }), - cx, - span, - substr - ) - } - - let inline = cx.meta_word(span, InternedString::new("inline")); - let hidden = cx.meta_word(span, InternedString::new("hidden")); - let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden)); - let attrs = vec!(cx.attribute(span, inline), - cx.attribute(span, doc)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::cmp::Eq), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "assert_receiver_is_total_eq", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(), - ret_ty: nil_ty(), - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_total_eq_assert(a, b, c) - })) - } - ), - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs deleted file mode 100644 index ff36e01d6cc..00000000000 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast; -use ast::{MetaItem, Expr}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_ord(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::cmp::Ord), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "cmp", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), - ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_cmp(a, b, c) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - - -pub fn ordering_collapsed(cx: &mut ExtCtxt, - span: Span, - self_arg_tags: &[ast::Ident]) -> P<ast::Expr> { - let lft = cx.expr_ident(span, self_arg_tags[0]); - let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); - cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt]) -} - -pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P<Expr> { - let test_id = cx.ident_of("__test"); - let equals_path = cx.path_global(span, - cx.std_path(&["cmp", "Ordering", "Equal"])); - - let cmp_path = cx.std_path(&["cmp", "Ord", "cmp"]); - - /* - Builds: - - let __test = ::std::cmp::Ord::cmp(&self_field1, &other_field1); - if other == ::std::cmp::Ordering::Equal { - let __test = ::std::cmp::Ord::cmp(&self_field2, &other_field2); - if __test == ::std::cmp::Ordering::Equal { - ... - } else { - __test - } - } else { - __test - } - - FIXME #6449: These `if`s could/should be `match`es. - */ - cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - |cx, span, old, self_f, other_fs| { - // let __test = new; - // if __test == ::std::cmp::Ordering::Equal { - // old - // } else { - // __test - // } - - let new = { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), - }; - - let args = vec![ - cx.expr_addr_of(span, self_f), - cx.expr_addr_of(span, other_f.clone()), - ]; - - cx.expr_call_global(span, cmp_path.clone(), args) - }; - - let assign = cx.stmt_let(span, false, test_id, new); - - let cond = cx.expr_binary(span, ast::BiEq, - cx.expr_ident(span, test_id), - cx.expr_path(equals_path.clone())); - let if_ = cx.expr_if(span, - cond, - old, Some(cx.expr_ident(span, test_id))); - cx.expr_block(cx.block(span, vec!(assign), Some(if_))) - }, - cx.expr_path(equals_path.clone()), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derives(Ord)`") - } else { - ordering_collapsed(cx, span, tag_tuple) - } - }), - cx, span, substr) -} diff --git a/src/libsyntax/ext/deriving/cmp/partial_eq.rs b/src/libsyntax/ext/deriving/cmp/partial_eq.rs deleted file mode 100644 index 495761c499b..00000000000 --- a/src/libsyntax/ext/deriving/cmp/partial_eq.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr, self}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - // structures are equal if all fields are equal, and non equal, if - // any fields are not equal or if the enum variants are different - fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> { - cs_fold( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - }; - - let eq = cx.expr_binary(span, ast::BiEq, self_f, other_f.clone()); - - cx.expr_binary(span, ast::BiAnd, subexpr, eq) - }, - cx.expr_bool(span, true), - Box::new(|cx, span, _, _| cx.expr_bool(span, false)), - cx, span, substr) - } - fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> { - cs_fold( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - }; - - let eq = cx.expr_binary(span, ast::BiNe, self_f, other_f.clone()); - - cx.expr_binary(span, ast::BiOr, subexpr, eq) - }, - cx.expr_bool(span, false), - Box::new(|cx, span, _, _| cx.expr_bool(span, true)), - cx, span, substr) - } - - macro_rules! md { - ($name:expr, $f:ident) => { { - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - MethodDef { - name: $name, - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), - ret_ty: Literal(path_local!(bool)), - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - $f(a, b, c) - })) - } - } } - } - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::cmp::PartialEq), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - md!("eq", cs_eq), - md!("ne", cs_ne) - ), - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} diff --git a/src/libsyntax/ext/deriving/cmp/partial_ord.rs b/src/libsyntax/ext/deriving/cmp/partial_ord.rs deleted file mode 100644 index 084e3ef3f91..00000000000 --- a/src/libsyntax/ext/deriving/cmp/partial_ord.rs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::OrderingOp::*; - -use ast; -use ast::{MetaItem, Expr}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - macro_rules! md { - ($name:expr, $op:expr, $equal:expr) => { { - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - MethodDef { - name: $name, - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), - ret_ty: Literal(path_local!(bool)), - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_op($op, $equal, cx, span, substr) - })) - } - } } - } - - let ordering_ty = Literal(path_std!(cx, core::cmp::Ordering)); - let ret_ty = Literal(Path::new_(pathvec_std!(cx, core::option::Option), - None, - vec![Box::new(ordering_ty)], - true)); - - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - - let partial_cmp_def = MethodDef { - name: "partial_cmp", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![borrowed_self()], - ret_ty: ret_ty, - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr) - })) - }; - - let trait_def = TraitDef { - span: span, - attributes: vec![], - path: path_std!(cx, core::cmp::PartialOrd), - additional_bounds: vec![], - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec![ - partial_cmp_def, - md!("lt", true, false), - md!("le", true, true), - md!("gt", false, false), - md!("ge", false, true) - ], - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} - -#[derive(Copy, Clone)] -pub enum OrderingOp { - PartialCmpOp, LtOp, LeOp, GtOp, GeOp, -} - -pub fn some_ordering_collapsed(cx: &mut ExtCtxt, - span: Span, - op: OrderingOp, - self_arg_tags: &[ast::Ident]) -> P<ast::Expr> { - let lft = cx.expr_ident(span, self_arg_tags[0]); - let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); - let op_str = match op { - PartialCmpOp => "partial_cmp", - LtOp => "lt", LeOp => "le", - GtOp => "gt", GeOp => "ge", - }; - cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt]) -} - -pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P<Expr> { - let test_id = cx.ident_of("__test"); - let ordering = cx.path_global(span, - cx.std_path(&["cmp", "Ordering", "Equal"])); - let ordering = cx.expr_path(ordering); - let equals_expr = cx.expr_some(span, ordering); - - let partial_cmp_path = cx.std_path(&["cmp", "PartialOrd", "partial_cmp"]); - - /* - Builds: - - let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1); - if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { - let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2); - if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { - ... - } else { - __test - } - } else { - __test - } - - FIXME #6449: These `if`s could/should be `match`es. - */ - cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - |cx, span, old, self_f, other_fs| { - // let __test = new; - // if __test == Some(::std::cmp::Ordering::Equal) { - // old - // } else { - // __test - // } - - let new = { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), - }; - - let args = vec![ - cx.expr_addr_of(span, self_f), - cx.expr_addr_of(span, other_f.clone()), - ]; - - cx.expr_call_global(span, partial_cmp_path.clone(), args) - }; - - let assign = cx.stmt_let(span, false, test_id, new); - - let cond = cx.expr_binary(span, ast::BiEq, - cx.expr_ident(span, test_id), - equals_expr.clone()); - let if_ = cx.expr_if(span, - cond, - old, Some(cx.expr_ident(span, test_id))); - cx.expr_block(cx.block(span, vec!(assign), Some(if_))) - }, - equals_expr.clone(), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple) - } - }), - cx, span, substr) -} - -/// Strict inequality. -fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, - span: Span, substr: &Substructure) -> P<Expr> { - let op = if less {ast::BiLt} else {ast::BiGt}; - cs_fold( - false, // need foldr, - |cx, span, subexpr, self_f, other_fs| { - /* - build up a series of chain ||'s and &&'s from the inside - out (hence foldr) to get lexical ordering, i.e. for op == - `ast::lt` - - ``` - self.f1 < other.f1 || (!(other.f1 < self.f1) && - (self.f2 < other.f2 || (!(other.f2 < self.f2) && - (false) - )) - ) - ``` - - The optimiser should remove the redundancy. We explicitly - get use the binops to avoid auto-deref dereferencing too many - layers of pointers, if the type includes pointers. - */ - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - }; - - let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); - - let not_cmp = cx.expr_unary(span, ast::UnNot, - cx.expr_binary(span, op, other_f.clone(), self_f)); - - let and = cx.expr_binary(span, ast::BiAnd, not_cmp, subexpr); - cx.expr_binary(span, ast::BiOr, cmp, and) - }, - cx.expr_bool(span, equal), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - let op = match (less, equal) { - (true, true) => LeOp, (true, false) => LtOp, - (false, true) => GeOp, (false, false) => GtOp, - }; - some_ordering_collapsed(cx, span, op, tag_tuple) - } - }), - cx, span, substr) -} diff --git a/src/libsyntax/ext/deriving/debug.rs b/src/libsyntax/ext/deriving/debug.rs deleted file mode 100644 index 9488cfb86fc..00000000000 --- a/src/libsyntax/ext/deriving/debug.rs +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast; -use ast::{MetaItem, Expr}; -use codemap::{Span, respan}; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token; -use ptr::P; - -pub fn expand_deriving_debug(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - // &mut ::std::fmt::Formatter - let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))), - Borrowed(None, ast::MutMutable)); - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::fmt::Debug), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec![ - MethodDef { - name: "fmt", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(fmtr), - ret_ty: Literal(path_std!(cx, core::fmt::Result)), - attributes: Vec::new(), - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - show_substructure(a, b, c) - })) - } - ], - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} - -/// We use the debug builders to do the heavy lifting here -fn show_substructure(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P<Expr> { - // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build() - // or fmt.debug_tuple(<name>).field(&<fieldval>)....build() - // based on the "shape". - let ident = match *substr.fields { - Struct(_) => substr.type_ident, - EnumMatching(_, v, _) => v.node.name, - EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { - cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") - } - }; - - // We want to make sure we have the expn_id set so that we can use unstable methods - let span = Span { expn_id: cx.backtrace(), .. span }; - let name = cx.expr_lit(span, ast::Lit_::LitStr(ident.name.as_str(), - ast::StrStyle::CookedStr)); - let builder = token::str_to_ident("builder"); - let builder_expr = cx.expr_ident(span, builder.clone()); - - let fmt = substr.nonself_args[0].clone(); - - let stmts = match *substr.fields { - Struct(ref fields) | EnumMatching(_, _, ref fields) => { - let mut stmts = vec![]; - if fields.is_empty() || fields[0].name.is_none() { - // tuple struct/"normal" variant - let expr = cx.expr_method_call(span, - fmt, - token::str_to_ident("debug_tuple"), - vec![name]); - stmts.push(cx.stmt_let(span, true, builder, expr)); - - for field in fields { - // Use double indirection to make sure this works for unsized types - let field = cx.expr_addr_of(field.span, field.self_.clone()); - let field = cx.expr_addr_of(field.span, field); - - let expr = cx.expr_method_call(span, - builder_expr.clone(), - token::str_to_ident("field"), - vec![field]); - - // Use `let _ = expr;` to avoid triggering the - // unused_results lint. - stmts.push(stmt_let_undescore(cx, span, expr)); - } - } else { - // normal struct/struct variant - let expr = cx.expr_method_call(span, - fmt, - token::str_to_ident("debug_struct"), - vec![name]); - stmts.push(cx.stmt_let(span, true, builder, expr)); - - for field in fields { - let name = cx.expr_lit(field.span, ast::Lit_::LitStr( - field.name.unwrap().name.as_str(), - ast::StrStyle::CookedStr)); - - // Use double indirection to make sure this works for unsized types - let field = cx.expr_addr_of(field.span, field.self_.clone()); - let field = cx.expr_addr_of(field.span, field); - let expr = cx.expr_method_call(span, - builder_expr.clone(), - token::str_to_ident("field"), - vec![name, field]); - stmts.push(stmt_let_undescore(cx, span, expr)); - } - } - stmts - } - _ => unreachable!() - }; - - let expr = cx.expr_method_call(span, - builder_expr, - token::str_to_ident("finish"), - vec![]); - - let block = cx.block(span, stmts, Some(expr)); - cx.expr_block(block) -} - -fn stmt_let_undescore(cx: &mut ExtCtxt, - sp: Span, - expr: P<ast::Expr>) -> P<ast::Stmt> { - let local = P(ast::Local { - pat: cx.pat_wild(sp), - ty: None, - init: Some(expr), - id: ast::DUMMY_NODE_ID, - span: sp, - attrs: None, - }); - let decl = respan(sp, ast::DeclLocal(local)); - P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID))) -} diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs deleted file mode 100644 index 0fdcbec8447..00000000000 --- a/src/libsyntax/ext/deriving/decodable.rs +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more. - -use ast; -use ast::{MetaItem, Expr, MutMutable}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use parse::token; -use ptr::P; - -pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize") -} - -pub fn expand_deriving_decodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize") -} - -fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable), - krate: &'static str) -{ - if cx.crate_root != Some("std") { - // FIXME(#21880): lift this requirement. - cx.span_err(span, "this trait cannot be derived with #![no_std] \ - or #![no_core]"); - return - } - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: Path::new_(vec!(krate, "Decodable"), None, vec!(), true), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "decode", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("__D", vec!(Path::new_( - vec!(krate, "Decoder"), None, - vec!(), true)))) - }, - explicit_self: None, - args: vec!(Ptr(Box::new(Literal(Path::new_local("__D"))), - Borrowed(None, MutMutable))), - ret_ty: Literal(Path::new_( - pathvec_std!(cx, core::result::Result), - None, - vec!(Box::new(Self_), Box::new(Literal(Path::new_( - vec!["__D", "Error"], None, vec![], false - )))), - true - )), - attributes: Vec::new(), - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - decodable_substructure(a, b, c, krate) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure, - krate: &str) -> P<Expr> { - let decoder = substr.nonself_args[0].clone(); - let recurse = vec!(cx.ident_of(krate), - cx.ident_of("Decodable"), - cx.ident_of("decode")); - let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse)); - // throw an underscore in front to suppress unused variable warnings - let blkarg = cx.ident_of("_d"); - let blkdecoder = cx.expr_ident(trait_span, blkarg); - - return match *substr.fields { - StaticStruct(_, ref summary) => { - let nfields = match *summary { - Unnamed(ref fields) => fields.len(), - Named(ref fields) => fields.len() - }; - let read_struct_field = cx.ident_of("read_struct_field"); - - let path = cx.path_ident(trait_span, substr.type_ident); - let result = decode_static_fields(cx, - trait_span, - path, - summary, - |cx, span, name, field| { - cx.expr_try(span, - cx.expr_method_call(span, blkdecoder.clone(), read_struct_field, - vec!(cx.expr_str(span, name), - cx.expr_usize(span, field), - exprdecode.clone()))) - }); - let result = cx.expr_ok(trait_span, result); - cx.expr_method_call(trait_span, - decoder, - cx.ident_of("read_struct"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.expr_usize(trait_span, nfields), - cx.lambda_expr_1(trait_span, result, blkarg) - )) - } - StaticEnum(_, ref fields) => { - let variant = cx.ident_of("i"); - - let mut arms = Vec::new(); - let mut variants = Vec::new(); - let rvariant_arg = cx.ident_of("read_enum_variant_arg"); - - for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() { - variants.push(cx.expr_str(v_span, ident.name.as_str())); - - let path = cx.path(trait_span, vec![substr.type_ident, ident]); - let decoded = decode_static_fields(cx, - v_span, - path, - parts, - |cx, span, _, field| { - let idx = cx.expr_usize(span, field); - cx.expr_try(span, - cx.expr_method_call(span, blkdecoder.clone(), rvariant_arg, - vec!(idx, exprdecode.clone()))) - }); - - arms.push(cx.arm(v_span, - vec!(cx.pat_lit(v_span, cx.expr_usize(v_span, i))), - decoded)); - } - - arms.push(cx.arm_unreachable(trait_span)); - - let result = cx.expr_ok(trait_span, - cx.expr_match(trait_span, - cx.expr_ident(trait_span, variant), arms)); - let lambda = cx.lambda_expr(trait_span, vec!(blkarg, variant), result); - let variant_vec = cx.expr_vec(trait_span, variants); - let variant_vec = cx.expr_addr_of(trait_span, variant_vec); - let result = cx.expr_method_call(trait_span, blkdecoder, - cx.ident_of("read_enum_variant"), - vec!(variant_vec, lambda)); - cx.expr_method_call(trait_span, - decoder, - cx.ident_of("read_enum"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.lambda_expr_1(trait_span, result, blkarg) - )) - } - _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)") - }; -} - -/// Create a decoder for a single enum variant/struct: -/// - `outer_pat_path` is the path to this enum variant/struct -/// - `getarg` should retrieve the `usize`-th field with name `@str`. -fn decode_static_fields<F>(cx: &mut ExtCtxt, - trait_span: Span, - outer_pat_path: ast::Path, - fields: &StaticFields, - mut getarg: F) - -> P<Expr> where - F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P<Expr>, -{ - match *fields { - Unnamed(ref fields) => { - let path_expr = cx.expr_path(outer_pat_path); - if fields.is_empty() { - path_expr - } else { - let fields = fields.iter().enumerate().map(|(i, &span)| { - getarg(cx, span, - token::intern_and_get_ident(&format!("_field{}", i)), - i) - }).collect(); - - cx.expr_call(trait_span, path_expr, fields) - } - } - Named(ref fields) => { - // use the field's span to get nicer error messages. - let fields = fields.iter().enumerate().map(|(i, &(ident, span))| { - let arg = getarg(cx, span, ident.name.as_str(), i); - cx.field_imm(span, ident, arg) - }).collect(); - cx.expr_struct(trait_span, outer_pat_path, fields) - } - } -} diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs deleted file mode 100644 index 6a25088782a..00000000000 --- a/src/libsyntax/ext/deriving/default.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_default(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::default::Default), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "default", - generics: LifetimeBounds::empty(), - explicit_self: None, - args: Vec::new(), - ret_ty: Self_, - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - default_substructure(a, b, c) - })) - } - ), - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} - -fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> { - let default_ident = cx.std_path(&["default", "Default", "default"]); - let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new()); - - return match *substr.fields { - StaticStruct(_, ref summary) => { - match *summary { - Unnamed(ref fields) => { - if fields.is_empty() { - cx.expr_ident(trait_span, substr.type_ident) - } else { - let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); - cx.expr_call_ident(trait_span, substr.type_ident, exprs) - } - } - Named(ref fields) => { - let default_fields = fields.iter().map(|&(ident, span)| { - cx.field_imm(span, ident, default_call(span)) - }).collect(); - cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) - } - } - } - StaticEnum(..) => { - cx.span_err(trait_span, "`Default` cannot be derived for enums, only structs"); - // let compilation continue - cx.expr_usize(trait_span, 0) - } - _ => cx.span_bug(trait_span, "Non-static method in `derive(Default)`") - }; -} diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs deleted file mode 100644 index 786739938e5..00000000000 --- a/src/libsyntax/ext/deriving/encodable.rs +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The compiler code necessary to implement the `#[derive(Encodable)]` -//! (and `Decodable`, in decodable.rs) extension. The idea here is that -//! type-defining items may be tagged with `#[derive(Encodable, Decodable)]`. -//! -//! For example, a type like: -//! -//! ```ignore -//! #[derive(Encodable, Decodable)] -//! struct Node { id: usize } -//! ``` -//! -//! would generate two implementations like: -//! -//! ```ignore -//! impl<S: Encoder<E>, E> Encodable<S, E> for Node { -//! fn encode(&self, s: &mut S) -> Result<(), E> { -//! s.emit_struct("Node", 1, |this| { -//! this.emit_struct_field("id", 0, |this| { -//! Encodable::encode(&self.id, this) -//! /* this.emit_usize(self.id) can also be used */ -//! }) -//! }) -//! } -//! } -//! -//! impl<D: Decoder<E>, E> Decodable<D, E> for Node { -//! fn decode(d: &mut D) -> Result<Node, E> { -//! d.read_struct("Node", 1, |this| { -//! match this.read_struct_field("id", 0, |this| Decodable::decode(this)) { -//! Ok(id) => Ok(Node { id: id }), -//! Err(e) => Err(e), -//! } -//! }) -//! } -//! } -//! ``` -//! -//! Other interesting scenarios are when the item has type parameters or -//! references other non-built-in types. A type definition like: -//! -//! ```ignore -//! #[derive(Encodable, Decodable)] -//! struct Spanned<T> { node: T, span: Span } -//! ``` -//! -//! would yield functions like: -//! -//! ```ignore -//! impl< -//! S: Encoder<E>, -//! E, -//! T: Encodable<S, E> -//! > Encodable<S, E> for Spanned<T> { -//! fn encode(&self, s: &mut S) -> Result<(), E> { -//! s.emit_struct("Spanned", 2, |this| { -//! this.emit_struct_field("node", 0, |this| self.node.encode(this)) -//! .unwrap(); -//! this.emit_struct_field("span", 1, |this| self.span.encode(this)) -//! }) -//! } -//! } -//! -//! impl< -//! D: Decoder<E>, -//! E, -//! T: Decodable<D, E> -//! > Decodable<D, E> for Spanned<T> { -//! fn decode(d: &mut D) -> Result<Spanned<T>, E> { -//! d.read_struct("Spanned", 2, |this| { -//! Ok(Spanned { -//! node: this.read_struct_field("node", 0, |this| Decodable::decode(this)) -//! .unwrap(), -//! span: this.read_struct_field("span", 1, |this| Decodable::decode(this)) -//! .unwrap(), -//! }) -//! }) -//! } -//! } -//! ``` - -use ast::{MetaItem, Expr, ExprRet, MutMutable}; -use codemap::Span; -use ext::base::{ExtCtxt,Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token; -use ptr::P; - -pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize") -} - -pub fn expand_deriving_encodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize") -} - -fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable), - krate: &'static str) -{ - if cx.crate_root != Some("std") { - // FIXME(#21880): lift this requirement. - cx.span_err(span, "this trait cannot be derived with #![no_std] \ - or #![no_core]"); - return; - } - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: Path::new_(vec!(krate, "Encodable"), None, vec!(), true), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "encode", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("__S", vec!(Path::new_( - vec!(krate, "Encoder"), None, - vec!(), true)))) - }, - explicit_self: borrowed_explicit_self(), - args: vec!(Ptr(Box::new(Literal(Path::new_local("__S"))), - Borrowed(None, MutMutable))), - ret_ty: Literal(Path::new_( - pathvec_std!(cx, core::result::Result), - None, - vec!(Box::new(Tuple(Vec::new())), Box::new(Literal(Path::new_( - vec!["__S", "Error"], None, vec![], false - )))), - true - )), - attributes: Vec::new(), - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - encodable_substructure(a, b, c) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure) -> P<Expr> { - let encoder = substr.nonself_args[0].clone(); - // throw an underscore in front to suppress unused variable warnings - let blkarg = cx.ident_of("_e"); - let blkencoder = cx.expr_ident(trait_span, blkarg); - let encode = cx.ident_of("encode"); - - return match *substr.fields { - Struct(ref fields) => { - let emit_struct_field = cx.ident_of("emit_struct_field"); - let mut stmts = Vec::new(); - for (i, &FieldInfo { - name, - ref self_, - span, - .. - }) in fields.iter().enumerate() { - let name = match name { - Some(id) => id.name.as_str(), - None => { - token::intern_and_get_ident(&format!("_field{}", i)) - } - }; - let enc = cx.expr_method_call(span, self_.clone(), - encode, vec!(blkencoder.clone())); - let lambda = cx.lambda_expr_1(span, enc, blkarg); - let call = cx.expr_method_call(span, blkencoder.clone(), - emit_struct_field, - vec!(cx.expr_str(span, name), - cx.expr_usize(span, i), - lambda)); - - // last call doesn't need a try! - let last = fields.len() - 1; - let call = if i != last { - cx.expr_try(span, call) - } else { - cx.expr(span, ExprRet(Some(call))) - }; - stmts.push(cx.stmt_expr(call)); - } - - // unit structs have no fields and need to return Ok() - if stmts.is_empty() { - let ret_ok = cx.expr(trait_span, - ExprRet(Some(cx.expr_ok(trait_span, - cx.expr_tuple(trait_span, vec![]))))); - stmts.push(cx.stmt_expr(ret_ok)); - } - - let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); - cx.expr_method_call(trait_span, - encoder, - cx.ident_of("emit_struct"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.expr_usize(trait_span, fields.len()), - blk - )) - } - - EnumMatching(idx, variant, ref fields) => { - // We're not generating an AST that the borrow checker is expecting, - // so we need to generate a unique local variable to take the - // mutable loan out on, otherwise we get conflicts which don't - // actually exist. - let me = cx.stmt_let(trait_span, false, blkarg, encoder); - let encoder = cx.expr_ident(trait_span, blkarg); - let emit_variant_arg = cx.ident_of("emit_enum_variant_arg"); - let mut stmts = Vec::new(); - if !fields.is_empty() { - let last = fields.len() - 1; - for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() { - let enc = cx.expr_method_call(span, self_.clone(), - encode, vec!(blkencoder.clone())); - let lambda = cx.lambda_expr_1(span, enc, blkarg); - let call = cx.expr_method_call(span, blkencoder.clone(), - emit_variant_arg, - vec!(cx.expr_usize(span, i), - lambda)); - let call = if i != last { - cx.expr_try(span, call) - } else { - cx.expr(span, ExprRet(Some(call))) - }; - stmts.push(cx.stmt_expr(call)); - } - } else { - let ret_ok = cx.expr(trait_span, - ExprRet(Some(cx.expr_ok(trait_span, - cx.expr_tuple(trait_span, vec![]))))); - stmts.push(cx.stmt_expr(ret_ok)); - } - - let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); - let name = cx.expr_str(trait_span, variant.node.name.name.as_str()); - let call = cx.expr_method_call(trait_span, blkencoder, - cx.ident_of("emit_enum_variant"), - vec!(name, - cx.expr_usize(trait_span, idx), - cx.expr_usize(trait_span, fields.len()), - blk)); - let blk = cx.lambda_expr_1(trait_span, call, blkarg); - let ret = cx.expr_method_call(trait_span, - encoder, - cx.ident_of("emit_enum"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - blk - )); - cx.expr_block(cx.block(trait_span, vec!(me), Some(ret))) - } - - _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)") - }; -} diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs deleted file mode 100644 index bd89430d81d..00000000000 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ /dev/null @@ -1,1704 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Some code that abstracts away much of the boilerplate of writing -//! `derive` instances for traits. Among other things it manages getting -//! access to the fields of the 4 different sorts of structs and enum -//! variants, as well as creating the method and impl ast instances. -//! -//! Supported features (fairly exhaustive): -//! -//! - Methods taking any number of parameters of any type, and returning -//! any type, other than vectors, bottom and closures. -//! - Generating `impl`s for types with type parameters and lifetimes -//! (e.g. `Option<T>`), the parameters are automatically given the -//! current trait as a bound. (This includes separate type parameters -//! and lifetimes for methods.) -//! - Additional bounds on the type parameters (`TraitDef.additional_bounds`) -//! -//! The most important thing for implementers is the `Substructure` and -//! `SubstructureFields` objects. The latter groups 5 possibilities of the -//! arguments: -//! -//! - `Struct`, when `Self` is a struct (including tuple structs, e.g -//! `struct T(i32, char)`). -//! - `EnumMatching`, when `Self` is an enum and all the arguments are the -//! same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`) -//! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments -//! are not the same variant (e.g. `None`, `Some(1)` and `None`). -//! - `StaticEnum` and `StaticStruct` for static methods, where the type -//! being derived upon is either an enum or struct respectively. (Any -//! argument with type Self is just grouped among the non-self -//! arguments.) -//! -//! In the first two cases, the values from the corresponding fields in -//! all the arguments are grouped together. For `EnumNonMatchingCollapsed` -//! this isn't possible (different variants have different fields), so the -//! fields are inaccessible. (Previous versions of the deriving infrastructure -//! had a way to expand into code that could access them, at the cost of -//! generating exponential amounts of code; see issue #15375). There are no -//! fields with values in the static cases, so these are treated entirely -//! differently. -//! -//! The non-static cases have `Option<ident>` in several places associated -//! with field `expr`s. This represents the name of the field it is -//! associated with. It is only not `None` when the associated field has -//! an identifier in the source code. For example, the `x`s in the -//! following snippet -//! -//! ```rust -//! # #![allow(dead_code)] -//! struct A { x : i32 } -//! -//! struct B(i32); -//! -//! enum C { -//! C0(i32), -//! C1 { x: i32 } -//! } -//! ``` -//! -//! The `i32`s in `B` and `C0` don't have an identifier, so the -//! `Option<ident>`s would be `None` for them. -//! -//! In the static cases, the structure is summarised, either into the just -//! spans of the fields or a list of spans and the field idents (for tuple -//! structs and record structs, respectively), or a list of these, for -//! enums (one for each variant). For empty struct and empty enum -//! variants, it is represented as a count of 0. -//! -//! # "`cs`" functions -//! -//! The `cs_...` functions ("combine substructure) are designed to -//! make life easier by providing some pre-made recipes for common -//! threads; mostly calling the function being derived on all the -//! arguments and then combining them back together in some way (or -//! letting the user chose that). They are not meant to be the only -//! way to handle the structures that this code creates. -//! -//! # Examples -//! -//! The following simplified `PartialEq` is used for in-code examples: -//! -//! ```rust -//! trait PartialEq { -//! fn eq(&self, other: &Self) -> bool; -//! } -//! impl PartialEq for i32 { -//! fn eq(&self, other: &i32) -> bool { -//! *self == *other -//! } -//! } -//! ``` -//! -//! Some examples of the values of `SubstructureFields` follow, using the -//! above `PartialEq`, `A`, `B` and `C`. -//! -//! ## Structs -//! -//! When generating the `expr` for the `A` impl, the `SubstructureFields` is -//! -//! ```{.text} -//! Struct(vec![FieldInfo { -//! span: <span of x> -//! name: Some(<ident of x>), -//! self_: <expr for &self.x>, -//! other: vec![<expr for &other.x] -//! }]) -//! ``` -//! -//! For the `B` impl, called with `B(a)` and `B(b)`, -//! -//! ```{.text} -//! Struct(vec![FieldInfo { -//! span: <span of `i32`>, -//! name: None, -//! self_: <expr for &a> -//! other: vec![<expr for &b>] -//! }]) -//! ``` -//! -//! ## Enums -//! -//! When generating the `expr` for a call with `self == C0(a)` and `other -//! == C0(b)`, the SubstructureFields is -//! -//! ```{.text} -//! EnumMatching(0, <ast::Variant for C0>, -//! vec![FieldInfo { -//! span: <span of i32> -//! name: None, -//! self_: <expr for &a>, -//! other: vec![<expr for &b>] -//! }]) -//! ``` -//! -//! For `C1 {x}` and `C1 {x}`, -//! -//! ```{.text} -//! EnumMatching(1, <ast::Variant for C1>, -//! vec![FieldInfo { -//! span: <span of x> -//! name: Some(<ident of x>), -//! self_: <expr for &self.x>, -//! other: vec![<expr for &other.x>] -//! }]) -//! ``` -//! -//! For `C0(a)` and `C1 {x}` , -//! -//! ```{.text} -//! EnumNonMatchingCollapsed( -//! vec![<ident of self>, <ident of __arg_1>], -//! &[<ast::Variant for C0>, <ast::Variant for C1>], -//! &[<ident for self index value>, <ident of __arg_1 index value>]) -//! ``` -//! -//! It is the same for when the arguments are flipped to `C1 {x}` and -//! `C0(a)`; the only difference is what the values of the identifiers -//! <ident for self index value> and <ident of __arg_1 index value> will -//! be in the generated code. -//! -//! `EnumNonMatchingCollapsed` deliberately provides far less information -//! than is generally available for a given pair of variants; see #15375 -//! for discussion. -//! -//! ## Static -//! -//! A static method on the types above would result in, -//! -//! ```{.text} -//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)])) -//! -//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>])) -//! -//! StaticEnum(<ast::EnumDef of C>, -//! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])), -//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))]) -//! ``` - -pub use self::StaticFields::*; -pub use self::SubstructureFields::*; -use self::StructType::*; - -use std::cell::RefCell; -use std::collections::HashSet; -use std::vec; - -use abi::Abi; -use abi; -use ast; -use ast::{EnumDef, Expr, Ident, Generics, VariantData}; -use ast_util; -use attr; -use attr::AttrMetaMethods; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use codemap::{self, DUMMY_SP}; -use codemap::Span; -use diagnostic::SpanHandler; -use util::move_map::MoveMap; -use owned_slice::OwnedSlice; -use parse::token::{intern, InternedString}; -use parse::token::special_idents; -use ptr::P; - -use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty}; - -pub mod ty; - -pub struct TraitDef<'a> { - /// The span for the current #[derive(Foo)] header. - pub span: Span, - - pub attributes: Vec<ast::Attribute>, - - /// Path of the trait, including any type parameters - pub path: Path<'a>, - - /// Additional bounds required of any type parameters of the type, - /// other than the current trait - pub additional_bounds: Vec<Ty<'a>>, - - /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder` - pub generics: LifetimeBounds<'a>, - - /// Is it an `unsafe` trait? - pub is_unsafe: bool, - - pub methods: Vec<MethodDef<'a>>, - - pub associated_types: Vec<(ast::Ident, Ty<'a>)>, -} - - -pub struct MethodDef<'a> { - /// name of the method - pub name: &'a str, - /// List of generics, e.g. `R: rand::Rng` - pub generics: LifetimeBounds<'a>, - - /// Whether there is a self argument (outer Option) i.e. whether - /// this is a static function, and whether it is a pointer (inner - /// Option) - pub explicit_self: Option<Option<PtrTy<'a>>>, - - /// Arguments other than the self argument - pub args: Vec<Ty<'a>>, - - /// Return type - pub ret_ty: Ty<'a>, - - pub attributes: Vec<ast::Attribute>, - - // Is it an `unsafe fn`? - pub is_unsafe: bool, - - pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>, -} - -/// All the data about the data structure/method being derived upon. -pub struct Substructure<'a> { - /// ident of self - pub type_ident: Ident, - /// ident of the method - pub method_ident: Ident, - /// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments - pub self_args: &'a [P<Expr>], - /// verbatim access to any other arguments - pub nonself_args: &'a [P<Expr>], - pub fields: &'a SubstructureFields<'a> -} - -/// Summary of the relevant parts of a struct/enum field. -pub struct FieldInfo<'a> { - pub span: Span, - /// None for tuple structs/normal enum variants, Some for normal - /// structs/struct enum variants. - pub name: Option<Ident>, - /// The expression corresponding to this field of `self` - /// (specifically, a reference to it). - pub self_: P<Expr>, - /// The expressions corresponding to references to this field in - /// the other `Self` arguments. - pub other: Vec<P<Expr>>, - /// The attributes on the field - pub attrs: &'a [ast::Attribute], -} - -/// Fields for a static method -pub enum StaticFields { - /// Tuple structs/enum variants like this. - Unnamed(Vec<Span>), - /// Normal structs/struct variants. - Named(Vec<(Ident, Span)>), -} - -/// A summary of the possible sets of fields. -pub enum SubstructureFields<'a> { - Struct(Vec<FieldInfo<'a>>), - /// Matching variants of the enum: variant index, ast::Variant, - /// fields: the field name is only non-`None` in the case of a struct - /// variant. - EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo<'a>>), - - /// Non-matching variants of the enum, but with all state hidden from - /// the consequent code. The first component holds `Ident`s for all of - /// the `Self` arguments; the second component is a slice of all of the - /// variants for the enum itself, and the third component is a list of - /// `Ident`s bound to the variant index values for each of the actual - /// input `Self` arguments. - EnumNonMatchingCollapsed(Vec<Ident>, &'a [P<ast::Variant>], &'a [Ident]), - - /// A static method where `Self` is a struct. - StaticStruct(&'a ast::VariantData, StaticFields), - /// A static method where `Self` is an enum. - StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>), -} - - - -/// Combine the values of all the fields together. The last argument is -/// all the fields of all the structures. -pub type CombineSubstructureFunc<'a> = - Box<FnMut(&mut ExtCtxt, Span, &Substructure) -> P<Expr> + 'a>; - -/// Deal with non-matching enum variants. The tuple is a list of -/// identifiers (one for each `Self` argument, which could be any of the -/// variants since they have been collapsed together) and the identifiers -/// holding the variant index value for each of the `Self` arguments. The -/// last argument is all the non-`Self` args of the method being derived. -pub type EnumNonMatchCollapsedFunc<'a> = - Box<FnMut(&mut ExtCtxt, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>; - -pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) - -> RefCell<CombineSubstructureFunc<'a>> { - RefCell::new(f) -} - -/// This method helps to extract all the type parameters referenced from a -/// type. For a type parameter `<T>`, it looks for either a `TyPath` that -/// is not global and starts with `T`, or a `TyQPath`. -fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec<P<ast::Ty>> { - use visit; - - struct Visitor<'a> { - ty_param_names: &'a [ast::Name], - types: Vec<P<ast::Ty>>, - } - - impl<'a> visit::Visitor<'a> for Visitor<'a> { - fn visit_ty(&mut self, ty: &'a ast::Ty) { - match ty.node { - ast::TyPath(_, ref path) if !path.global => { - match path.segments.first() { - Some(segment) => { - if self.ty_param_names.contains(&segment.identifier.name) { - self.types.push(P(ty.clone())); - } - } - None => {} - } - } - _ => {} - } - - visit::walk_ty(self, ty) - } - } - - let mut visitor = Visitor { - ty_param_names: ty_param_names, - types: Vec::new(), - }; - - visit::Visitor::visit_ty(&mut visitor, ty); - - visitor.types -} - -impl<'a> TraitDef<'a> { - pub fn expand(&self, - cx: &mut ExtCtxt, - mitem: &ast::MetaItem, - item: &'a Annotatable, - push: &mut FnMut(Annotatable)) - { - match *item { - Annotatable::Item(ref item) => { - let newitem = match item.node { - ast::ItemStruct(ref struct_def, ref generics) => { - self.expand_struct_def(cx, - &struct_def, - item.ident, - generics) - } - ast::ItemEnum(ref enum_def, ref generics) => { - self.expand_enum_def(cx, - enum_def, - &item.attrs, - item.ident, - generics) - } - _ => { - cx.span_err(mitem.span, - "`derive` may only be applied to structs and enums"); - return; - } - }; - // Keep the lint attributes of the previous item to control how the - // generated implementations are linted - let mut attrs = newitem.attrs.clone(); - attrs.extend(item.attrs.iter().filter(|a| { - match &a.name()[..] { - "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, - _ => false, - } - }).cloned()); - push(Annotatable::Item(P(ast::Item { - attrs: attrs, - ..(*newitem).clone() - }))) - } - _ => { - cx.span_err(mitem.span, "`derive` may only be applied to structs and enums"); - } - } - } - - /// Given that we are deriving a trait `DerivedTrait` for a type like: - /// - /// ```ignore - /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait { - /// a: A, - /// b: B::Item, - /// b1: <B as DeclaredTrait>::Item, - /// c1: <C as WhereTrait>::Item, - /// c2: Option<<C as WhereTrait>::Item>, - /// ... - /// } - /// ``` - /// - /// create an impl like: - /// - /// ```ignore - /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where - /// C: WhereTrait, - /// A: DerivedTrait + B1 + ... + BN, - /// B: DerivedTrait + B1 + ... + BN, - /// C: DerivedTrait + B1 + ... + BN, - /// B::Item: DerivedTrait + B1 + ... + BN, - /// <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN, - /// ... - /// { - /// ... - /// } - /// ``` - /// - /// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and - /// therefore does not get bound by the derived trait. - fn create_derived_impl(&self, - cx: &mut ExtCtxt, - type_ident: Ident, - generics: &Generics, - field_tys: Vec<P<ast::Ty>>, - methods: Vec<P<ast::ImplItem>>) -> P<ast::Item> { - let trait_path = self.path.to_path(cx, self.span, type_ident, generics); - - // Transform associated types from `deriving::ty::Ty` into `ast::ImplItem` - let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| { - P(ast::ImplItem { - id: ast::DUMMY_NODE_ID, - span: self.span, - ident: ident, - vis: ast::Inherited, - attrs: Vec::new(), - node: ast::ImplItemKind::Type(type_def.to_ty(cx, - self.span, - type_ident, - generics - )), - }) - }); - - let Generics { mut lifetimes, ty_params, mut where_clause } = - self.generics.to_generics(cx, self.span, type_ident, generics); - let mut ty_params = ty_params.into_vec(); - - // Copy the lifetimes - lifetimes.extend(generics.lifetimes.iter().cloned()); - - // Create the type parameters. - ty_params.extend(generics.ty_params.iter().map(|ty_param| { - // I don't think this can be moved out of the loop, since - // a TyParamBound requires an ast id - let mut bounds: Vec<_> = - // extra restrictions on the generics parameters to the type being derived upon - self.additional_bounds.iter().map(|p| { - cx.typarambound(p.to_path(cx, self.span, - type_ident, generics)) - }).collect(); - - // require the current trait - bounds.push(cx.typarambound(trait_path.clone())); - - // also add in any bounds from the declaration - for declared_bound in ty_param.bounds.iter() { - bounds.push((*declared_bound).clone()); - } - - cx.typaram(self.span, - ty_param.ident, - OwnedSlice::from_vec(bounds), - None) - })); - - // and similarly for where clauses - where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| { - match *clause { - ast::WherePredicate::BoundPredicate(ref wb) => { - ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { - span: self.span, - bound_lifetimes: wb.bound_lifetimes.clone(), - bounded_ty: wb.bounded_ty.clone(), - bounds: OwnedSlice::from_vec(wb.bounds.iter().cloned().collect()) - }) - } - ast::WherePredicate::RegionPredicate(ref rb) => { - ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { - span: self.span, - lifetime: rb.lifetime, - bounds: rb.bounds.iter().cloned().collect() - }) - } - ast::WherePredicate::EqPredicate(ref we) => { - ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { - id: ast::DUMMY_NODE_ID, - span: self.span, - path: we.path.clone(), - ty: we.ty.clone() - }) - } - } - })); - - if !ty_params.is_empty() { - let ty_param_names: Vec<ast::Name> = ty_params.iter() - .map(|ty_param| ty_param.ident.name) - .collect(); - - let mut processed_field_types = HashSet::new(); - for field_ty in field_tys { - let tys = find_type_parameters(&*field_ty, &ty_param_names); - - for ty in tys { - // if we have already handled this type, skip it - if let ast::TyPath(_, ref p) = ty.node { - if p.segments.len() == 1 - && ty_param_names.contains(&p.segments[0].identifier.name) - || processed_field_types.contains(&p.segments) { - continue; - }; - processed_field_types.insert(p.segments.clone()); - } - let mut bounds: Vec<_> = self.additional_bounds.iter().map(|p| { - cx.typarambound(p.to_path(cx, self.span, type_ident, generics)) - }).collect(); - - // require the current trait - bounds.push(cx.typarambound(trait_path.clone())); - - let predicate = ast::WhereBoundPredicate { - span: self.span, - bound_lifetimes: vec![], - bounded_ty: ty, - bounds: OwnedSlice::from_vec(bounds), - }; - - let predicate = ast::WherePredicate::BoundPredicate(predicate); - where_clause.predicates.push(predicate); - } - } - } - - let trait_generics = Generics { - lifetimes: lifetimes, - ty_params: OwnedSlice::from_vec(ty_params), - where_clause: where_clause - }; - - // Create the reference to the trait. - let trait_ref = cx.trait_ref(trait_path); - - // Create the type parameters on the `self` path. - let self_ty_params = generics.ty_params.map(|ty_param| { - cx.ty_ident(self.span, ty_param.ident) - }); - - let self_lifetimes: Vec<ast::Lifetime> = - generics.lifetimes - .iter() - .map(|ld| ld.lifetime) - .collect(); - - // Create the type of `self`. - let self_type = cx.ty_path( - cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes, - self_ty_params.into_vec(), Vec::new())); - - let attr = cx.attribute( - self.span, - cx.meta_word(self.span, - InternedString::new("automatically_derived"))); - // Just mark it now since we know that it'll end up used downstream - attr::mark_used(&attr); - let opt_trait_ref = Some(trait_ref); - let ident = ast_util::impl_pretty_name(&opt_trait_ref, Some(&*self_type)); - let unused_qual = cx.attribute( - self.span, - cx.meta_list(self.span, - InternedString::new("allow"), - vec![cx.meta_word(self.span, - InternedString::new("unused_qualifications"))])); - let mut a = vec![attr, unused_qual]; - a.extend(self.attributes.iter().cloned()); - - let unsafety = if self.is_unsafe { - ast::Unsafety::Unsafe - } else { - ast::Unsafety::Normal - }; - - cx.item( - self.span, - ident, - a, - ast::ItemImpl(unsafety, - ast::ImplPolarity::Positive, - trait_generics, - opt_trait_ref, - self_type, - methods.into_iter().chain(associated_types).collect())) - } - - fn expand_struct_def(&self, - cx: &mut ExtCtxt, - struct_def: &'a VariantData, - type_ident: Ident, - generics: &Generics) -> P<ast::Item> { - let field_tys: Vec<P<ast::Ty>> = struct_def.fields().iter() - .map(|field| field.node.ty.clone()) - .collect(); - - let methods = self.methods.iter().map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args( - cx, self, type_ident, generics); - - let body = if method_def.is_static() { - method_def.expand_static_struct_method_body( - cx, - self, - struct_def, - type_ident, - &self_args[..], - &nonself_args[..]) - } else { - method_def.expand_struct_method_body(cx, - self, - struct_def, - type_ident, - &self_args[..], - &nonself_args[..]) - }; - - method_def.create_method(cx, - self, - type_ident, - generics, - abi::Rust, - explicit_self, - tys, - body) - }).collect(); - - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) - } - - fn expand_enum_def(&self, - cx: &mut ExtCtxt, - enum_def: &'a EnumDef, - type_attrs: &[ast::Attribute], - type_ident: Ident, - generics: &Generics) -> P<ast::Item> { - let mut field_tys = Vec::new(); - - for variant in &enum_def.variants { - field_tys.extend(variant.node.data.fields().iter() - .map(|field| field.node.ty.clone())); - } - - let methods = self.methods.iter().map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args(cx, self, - type_ident, generics); - - let body = if method_def.is_static() { - method_def.expand_static_enum_method_body( - cx, - self, - enum_def, - type_ident, - &self_args[..], - &nonself_args[..]) - } else { - method_def.expand_enum_method_body(cx, - self, - enum_def, - type_attrs, - type_ident, - self_args, - &nonself_args[..]) - }; - - method_def.create_method(cx, - self, - type_ident, - generics, - abi::Rust, - explicit_self, - tys, - body) - }).collect(); - - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) - } -} - -fn find_repr_type_name(diagnostic: &SpanHandler, - type_attrs: &[ast::Attribute]) -> &'static str { - let mut repr_type_name = "i32"; - for a in type_attrs { - for r in &attr::find_repr_attrs(diagnostic, a) { - repr_type_name = match *r { - attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue, - attr::ReprExtern => "i32", - - attr::ReprInt(_, attr::SignedInt(ast::TyIs)) => "isize", - attr::ReprInt(_, attr::SignedInt(ast::TyI8)) => "i8", - attr::ReprInt(_, attr::SignedInt(ast::TyI16)) => "i16", - attr::ReprInt(_, attr::SignedInt(ast::TyI32)) => "i32", - attr::ReprInt(_, attr::SignedInt(ast::TyI64)) => "i64", - - attr::ReprInt(_, attr::UnsignedInt(ast::TyUs)) => "usize", - attr::ReprInt(_, attr::UnsignedInt(ast::TyU8)) => "u8", - attr::ReprInt(_, attr::UnsignedInt(ast::TyU16)) => "u16", - attr::ReprInt(_, attr::UnsignedInt(ast::TyU32)) => "u32", - attr::ReprInt(_, attr::UnsignedInt(ast::TyU64)) => "u64", - } - } - } - repr_type_name -} - -impl<'a> MethodDef<'a> { - fn call_substructure_method(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - self_args: &[P<Expr>], - nonself_args: &[P<Expr>], - fields: &SubstructureFields) - -> P<Expr> { - let substructure = Substructure { - type_ident: type_ident, - method_ident: cx.ident_of(self.name), - self_args: self_args, - nonself_args: nonself_args, - fields: fields - }; - let mut f = self.combine_substructure.borrow_mut(); - let f: &mut CombineSubstructureFunc = &mut *f; - f(cx, trait_.span, &substructure) - } - - fn get_ret_ty(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - generics: &Generics, - type_ident: Ident) - -> P<ast::Ty> { - self.ret_ty.to_ty(cx, trait_.span, type_ident, generics) - } - - fn is_static(&self) -> bool { - self.explicit_self.is_none() - } - - fn split_self_nonself_args(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - generics: &Generics) - -> (ast::ExplicitSelf, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) { - - let mut self_args = Vec::new(); - let mut nonself_args = Vec::new(); - let mut arg_tys = Vec::new(); - let mut nonstatic = false; - - let ast_explicit_self = match self.explicit_self { - Some(ref self_ptr) => { - let (self_expr, explicit_self) = - ty::get_explicit_self(cx, trait_.span, self_ptr); - - self_args.push(self_expr); - nonstatic = true; - - explicit_self - } - None => codemap::respan(trait_.span, ast::SelfStatic), - }; - - for (i, ty) in self.args.iter().enumerate() { - let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics); - let ident = cx.ident_of(&format!("__arg_{}", i)); - arg_tys.push((ident, ast_ty)); - - let arg_expr = cx.expr_ident(trait_.span, ident); - - match *ty { - // for static methods, just treat any Self - // arguments as a normal arg - Self_ if nonstatic => { - self_args.push(arg_expr); - } - Ptr(ref ty, _) if **ty == Self_ && nonstatic => { - self_args.push(cx.expr_deref(trait_.span, arg_expr)) - } - _ => { - nonself_args.push(arg_expr); - } - } - } - - (ast_explicit_self, self_args, nonself_args, arg_tys) - } - - fn create_method(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - generics: &Generics, - abi: Abi, - explicit_self: ast::ExplicitSelf, - arg_types: Vec<(Ident, P<ast::Ty>)> , - body: P<Expr>) -> P<ast::ImplItem> { - // create the generics that aren't for Self - let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); - - let self_arg = match explicit_self.node { - ast::SelfStatic => None, - // creating fresh self id - _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable, special_idents::self_)) - }; - let args = { - let args = arg_types.into_iter().map(|(name, ty)| { - cx.arg(trait_.span, name, ty) - }); - self_arg.into_iter().chain(args).collect() - }; - - let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); - - let method_ident = cx.ident_of(self.name); - let fn_decl = cx.fn_decl(args, ret_type); - let body_block = cx.block_expr(body); - - let unsafety = if self.is_unsafe { - ast::Unsafety::Unsafe - } else { - ast::Unsafety::Normal - }; - - // Create the method. - P(ast::ImplItem { - id: ast::DUMMY_NODE_ID, - attrs: self.attributes.clone(), - span: trait_.span, - vis: ast::Inherited, - ident: method_ident, - node: ast::ImplItemKind::Method(ast::MethodSig { - generics: fn_generics, - abi: abi, - explicit_self: explicit_self, - unsafety: unsafety, - constness: ast::Constness::NotConst, - decl: fn_decl - }, body_block) - }) - } - - /// ```ignore - /// #[derive(PartialEq)] - /// struct A { x: i32, y: i32 } - /// - /// // equivalent to: - /// impl PartialEq for A { - /// fn eq(&self, __arg_1: &A) -> bool { - /// match *self { - /// A {x: ref __self_0_0, y: ref __self_0_1} => { - /// match *__arg_1 { - /// A {x: ref __self_1_0, y: ref __self_1_1} => { - /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1) - /// } - /// } - /// } - /// } - /// } - /// } - /// ``` - fn expand_struct_method_body<'b>(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - struct_def: &'b VariantData, - type_ident: Ident, - self_args: &[P<Expr>], - nonself_args: &[P<Expr>]) - -> P<Expr> { - - let mut raw_fields = Vec::new(); // Vec<[fields of self], - // [fields of next Self arg], [etc]> - let mut patterns = Vec::new(); - for i in 0..self_args.len() { - let struct_path= cx.path(DUMMY_SP, vec!( type_ident )); - let (pat, ident_expr) = - trait_.create_struct_pattern(cx, - struct_path, - struct_def, - &format!("__self_{}", - i), - ast::MutImmutable); - patterns.push(pat); - raw_fields.push(ident_expr); - } - - // transpose raw_fields - let fields = if !raw_fields.is_empty() { - let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter()); - let first_field = raw_fields.next().unwrap(); - let mut other_fields: Vec<vec::IntoIter<_>> - = raw_fields.collect(); - first_field.map(|(span, opt_id, field, attrs)| { - FieldInfo { - span: span, - name: opt_id, - self_: field, - other: other_fields.iter_mut().map(|l| { - match l.next().unwrap() { - (_, _, ex, _) => ex - } - }).collect(), - attrs: attrs, - } - }).collect() - } else { - cx.span_bug(trait_.span, - "no self arguments to non-static method in generic \ - `derive`") - }; - - // body of the inner most destructuring match - let mut body = self.call_substructure_method( - cx, - trait_, - type_ident, - self_args, - nonself_args, - &Struct(fields)); - - // make a series of nested matches, to destructure the - // structs. This is actually right-to-left, but it shouldn't - // matter. - for (arg_expr, pat) in self_args.iter().zip(patterns) { - body = cx.expr_match(trait_.span, arg_expr.clone(), - vec!( cx.arm(trait_.span, vec!(pat.clone()), body) )) - } - body - } - - fn expand_static_struct_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - struct_def: &VariantData, - type_ident: Ident, - self_args: &[P<Expr>], - nonself_args: &[P<Expr>]) - -> P<Expr> { - let summary = trait_.summarise_struct(cx, struct_def); - - self.call_substructure_method(cx, - trait_, - type_ident, - self_args, nonself_args, - &StaticStruct(struct_def, summary)) - } - - /// ```ignore - /// #[derive(PartialEq)] - /// enum A { - /// A1, - /// A2(i32) - /// } - /// - /// // is equivalent to - /// - /// impl PartialEq for A { - /// fn eq(&self, __arg_1: &A) -> ::bool { - /// match (&*self, &*__arg_1) { - /// (&A1, &A1) => true, - /// (&A2(ref __self_0), - /// &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)), - /// _ => { - /// let __self_vi = match *self { A1(..) => 0, A2(..) => 1 }; - /// let __arg_1_vi = match *__arg_1 { A1(..) => 0, A2(..) => 1 }; - /// false - /// } - /// } - /// } - /// } - /// ``` - /// - /// (Of course `__self_vi` and `__arg_1_vi` are unused for - /// `PartialEq`, and those subcomputations will hopefully be removed - /// as their results are unused. The point of `__self_vi` and - /// `__arg_1_vi` is for `PartialOrd`; see #15503.) - fn expand_enum_method_body<'b>(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - enum_def: &'b EnumDef, - type_attrs: &[ast::Attribute], - type_ident: Ident, - self_args: Vec<P<Expr>>, - nonself_args: &[P<Expr>]) - -> P<Expr> { - self.build_enum_match_tuple( - cx, trait_, enum_def, type_attrs, type_ident, self_args, nonself_args) - } - - - /// Creates a match for a tuple of all `self_args`, where either all - /// variants match, or it falls into a catch-all for when one variant - /// does not match. - - /// There are N + 1 cases because is a case for each of the N - /// variants where all of the variants match, and one catch-all for - /// when one does not match. - - /// As an optimization we generate code which checks whether all variants - /// match first which makes llvm see that C-like enums can be compiled into - /// a simple equality check (for PartialEq). - - /// The catch-all handler is provided access the variant index values - /// for each of the self-args, carried in precomputed variables. - - /// ```{.text} - /// let __self0_vi = unsafe { - /// std::intrinsics::discriminant_value(&self) } as i32; - /// let __self1_vi = unsafe { - /// std::intrinsics::discriminant_value(&__arg1) } as i32; - /// let __self2_vi = unsafe { - /// std::intrinsics::discriminant_value(&__arg2) } as i32; - /// - /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... { - /// match (...) { - /// (Variant1, Variant1, ...) => Body1 - /// (Variant2, Variant2, ...) => Body2, - /// ... - /// _ => ::core::intrinsics::unreachable() - /// } - /// } - /// else { - /// ... // catch-all remainder can inspect above variant index values. - /// } - /// ``` - fn build_enum_match_tuple<'b>( - &self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - enum_def: &'b EnumDef, - type_attrs: &[ast::Attribute], - type_ident: Ident, - self_args: Vec<P<Expr>>, - nonself_args: &[P<Expr>]) -> P<Expr> { - - let sp = trait_.span; - let variants = &enum_def.variants; - - let self_arg_names = self_args.iter().enumerate() - .map(|(arg_count, _self_arg)| { - if arg_count == 0 { - "__self".to_string() - } else { - format!("__arg_{}", arg_count) - } - }) - .collect::<Vec<String>>(); - - let self_arg_idents = self_arg_names.iter() - .map(|name|cx.ident_of(&name[..])) - .collect::<Vec<ast::Ident>>(); - - // The `vi_idents` will be bound, solely in the catch-all, to - // a series of let statements mapping each self_arg to an int - // value corresponding to its discriminant. - let vi_idents: Vec<ast::Ident> = self_arg_names.iter() - .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); - cx.ident_of(&vi_suffix[..]) }) - .collect::<Vec<ast::Ident>>(); - - // Builds, via callback to call_substructure_method, the - // delegated expression that handles the catch-all case, - // using `__variants_tuple` to drive logic if necessary. - let catch_all_substructure = EnumNonMatchingCollapsed( - self_arg_idents, &variants[..], &vi_idents[..]); - - // These arms are of the form: - // (Variant1, Variant1, ...) => Body1 - // (Variant2, Variant2, ...) => Body2 - // ... - // where each tuple has length = self_args.len() - let mut match_arms: Vec<ast::Arm> = variants.iter().enumerate() - .map(|(index, variant)| { - let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &str| { - let (p, idents) = trait_.create_enum_variant_pattern(cx, type_ident, - &**variant, - self_arg_name, - ast::MutImmutable); - (cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents) - }; - - // A single arm has form (&VariantK, &VariantK, ...) => BodyK - // (see "Final wrinkle" note below for why.) - let mut subpats = Vec::with_capacity(self_arg_names.len()); - let mut self_pats_idents = Vec::with_capacity(self_arg_names.len() - 1); - let first_self_pat_idents = { - let (p, idents) = mk_self_pat(cx, &self_arg_names[0]); - subpats.push(p); - idents - }; - for self_arg_name in &self_arg_names[1..] { - let (p, idents) = mk_self_pat(cx, &self_arg_name[..]); - subpats.push(p); - self_pats_idents.push(idents); - } - - // Here is the pat = `(&VariantK, &VariantK, ...)` - let single_pat = cx.pat_tuple(sp, subpats); - - // For the BodyK, we need to delegate to our caller, - // passing it an EnumMatching to indicate which case - // we are in. - - // All of the Self args have the same variant in these - // cases. So we transpose the info in self_pats_idents - // to gather the getter expressions together, in the - // form that EnumMatching expects. - - // The transposition is driven by walking across the - // arg fields of the variant for the first self pat. - let field_tuples = first_self_pat_idents.into_iter().enumerate() - // For each arg field of self, pull out its getter expr ... - .map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| { - // ... but FieldInfo also wants getter expr - // for matching other arguments of Self type; - // so walk across the *other* self_pats_idents - // and pull out getter for same field in each - // of them (using `field_index` tracked above). - // That is the heart of the transposition. - let others = self_pats_idents.iter().map(|fields| { - let (_, _opt_ident, ref other_getter_expr, _) = - fields[field_index]; - - // All Self args have same variant, so - // opt_idents are the same. (Assert - // here to make it self-evident that - // it is okay to ignore `_opt_ident`.) - assert!(opt_ident == _opt_ident); - - other_getter_expr.clone() - }).collect::<Vec<P<Expr>>>(); - - FieldInfo { span: sp, - name: opt_ident, - self_: self_getter_expr, - other: others, - attrs: attrs, - } - }).collect::<Vec<FieldInfo>>(); - - // Now, for some given VariantK, we have built up - // expressions for referencing every field of every - // Self arg, assuming all are instances of VariantK. - // Build up code associated with such a case. - let substructure = EnumMatching(index, - &**variant, - field_tuples); - let arm_expr = self.call_substructure_method( - cx, trait_, type_ident, &self_args[..], nonself_args, - &substructure); - - cx.arm(sp, vec![single_pat], arm_expr) - }).collect(); - // We will usually need the catch-all after matching the - // tuples `(VariantK, VariantK, ...)` for each VariantK of the - // enum. But: - // - // * when there is only one Self arg, the arms above suffice - // (and the deriving we call back into may not be prepared to - // handle EnumNonMatchCollapsed), and, - // - // * when the enum has only one variant, the single arm that - // is already present always suffices. - // - // * In either of the two cases above, if we *did* add a - // catch-all `_` match, it would trigger the - // unreachable-pattern error. - // - if variants.len() > 1 && self_args.len() > 1 { - // Build a series of let statements mapping each self_arg - // to its discriminant value. If this is a C-style enum - // with a specific repr type, then casts the values to - // that type. Otherwise casts to `i32` (the default repr - // type). - // - // i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving - // with three Self args, builds three statements: - // - // ``` - // let __self0_vi = unsafe { - // std::intrinsics::discriminant_value(&self) } as i32; - // let __self1_vi = unsafe { - // std::intrinsics::discriminant_value(&__arg1) } as i32; - // let __self2_vi = unsafe { - // std::intrinsics::discriminant_value(&__arg2) } as i32; - // ``` - let mut index_let_stmts: Vec<P<ast::Stmt>> = Vec::new(); - - //We also build an expression which checks whether all discriminants are equal - // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... - let mut discriminant_test = cx.expr_bool(sp, true); - - let target_type_name = - find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs); - - let mut first_ident = None; - for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { - let path = cx.std_path(&["intrinsics", "discriminant_value"]); - let call = cx.expr_call_global( - sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]); - let variant_value = cx.expr_block(P(ast::Block { - stmts: vec![], - expr: Some(call), - id: ast::DUMMY_NODE_ID, - rules: ast::UnsafeBlock(ast::CompilerGenerated), - span: sp })); - - let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name)); - let variant_disr = cx.expr_cast(sp, variant_value, target_ty); - let let_stmt = cx.stmt_let(sp, false, ident, variant_disr); - index_let_stmts.push(let_stmt); - - match first_ident { - Some(first) => { - let first_expr = cx.expr_ident(sp, first); - let id = cx.expr_ident(sp, ident); - let test = cx.expr_binary(sp, ast::BiEq, first_expr, id); - discriminant_test = cx.expr_binary(sp, ast::BiAnd, discriminant_test, test) - } - None => { - first_ident = Some(ident); - } - } - } - - let arm_expr = self.call_substructure_method( - cx, trait_, type_ident, &self_args[..], nonself_args, - &catch_all_substructure); - - //Since we know that all the arguments will match if we reach the match expression we - //add the unreachable intrinsics as the result of the catch all which should help llvm - //in optimizing it - let path = cx.std_path(&["intrinsics", "unreachable"]); - let call = cx.expr_call_global( - sp, path, vec![]); - let unreachable = cx.expr_block(P(ast::Block { - stmts: vec![], - expr: Some(call), - id: ast::DUMMY_NODE_ID, - rules: ast::UnsafeBlock(ast::CompilerGenerated), - span: sp })); - match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], unreachable)); - - // Final wrinkle: the self_args are expressions that deref - // down to desired l-values, but we cannot actually deref - // them when they are fed as r-values into a tuple - // expression; here add a layer of borrowing, turning - // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. - let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); - let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); - - //Lastly we create an expression which branches on all discriminants being equal - // if discriminant_test { - // match (...) { - // (Variant1, Variant1, ...) => Body1 - // (Variant2, Variant2, ...) => Body2, - // ... - // _ => ::core::intrinsics::unreachable() - // } - // } - // else { - // <delegated expression referring to __self0_vi, et al.> - // } - let all_match = cx.expr_match(sp, match_arg, match_arms); - let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr)); - cx.expr_block( - cx.block_all(sp, index_let_stmts, Some(arm_expr))) - } else if variants.is_empty() { - // As an additional wrinkle, For a zero-variant enum A, - // currently the compiler - // will accept `fn (a: &Self) { match *a { } }` - // but rejects `fn (a: &Self) { match (&*a,) { } }` - // as well as `fn (a: &Self) { match ( *a,) { } }` - // - // This means that the strategy of building up a tuple of - // all Self arguments fails when Self is a zero variant - // enum: rustc rejects the expanded program, even though - // the actual code tends to be impossible to execute (at - // least safely), according to the type system. - // - // The most expedient fix for this is to just let the - // code fall through to the catch-all. But even this is - // error-prone, since the catch-all as defined above would - // generate code like this: - // - // _ => { let __self0 = match *self { }; - // let __self1 = match *__arg_0 { }; - // <catch-all-expr> } - // - // Which is yields bindings for variables which type - // inference cannot resolve to unique types. - // - // One option to the above might be to add explicit type - // annotations. But the *only* reason to go down that path - // would be to try to make the expanded output consistent - // with the case when the number of enum variants >= 1. - // - // That just isn't worth it. In fact, trying to generate - // sensible code for *any* deriving on a zero-variant enum - // does not make sense. But at the same time, for now, we - // do not want to cause a compile failure just because the - // user happened to attach a deriving to their - // zero-variant enum. - // - // Instead, just generate a failing expression for the - // zero variant case, skipping matches and also skipping - // delegating back to the end user code entirely. - // - // (See also #4499 and #12609; note that some of the - // discussions there influence what choice we make here; - // e.g. if we feature-gate `match x { ... }` when x refers - // to an uninhabited type (e.g. a zero-variant enum or a - // type holding such an enum), but do not feature-gate - // zero-variant enums themselves, then attempting to - // derive Debug on such a type could here generate code - // that needs the feature gate enabled.) - - cx.expr_unreachable(sp) - } - else { - - // Final wrinkle: the self_args are expressions that deref - // down to desired l-values, but we cannot actually deref - // them when they are fed as r-values into a tuple - // expression; here add a layer of borrowing, turning - // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. - let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); - let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); - cx.expr_match(sp, match_arg, match_arms) - } - } - - fn expand_static_enum_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, - type_ident: Ident, - self_args: &[P<Expr>], - nonself_args: &[P<Expr>]) - -> P<Expr> { - let summary = enum_def.variants.iter().map(|v| { - let ident = v.node.name; - let summary = trait_.summarise_struct(cx, &v.node.data); - (ident, v.span, summary) - }).collect(); - self.call_substructure_method(cx, trait_, type_ident, - self_args, nonself_args, - &StaticEnum(enum_def, summary)) - } -} - -#[derive(PartialEq)] // dogfooding! -enum StructType { - Unknown, Record, Tuple -} - -// general helper methods. -impl<'a> TraitDef<'a> { - fn set_expn_info(&self, - cx: &mut ExtCtxt, - mut to_set: Span) -> Span { - let trait_name = match self.path.path.last() { - None => cx.span_bug(self.span, "trait with empty path in generic `derive`"), - Some(name) => *name - }; - to_set.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: to_set, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(intern(&format!("derive({})", trait_name))), - span: Some(self.span), - allow_internal_unstable: false, - } - }); - to_set - } - - fn summarise_struct(&self, - cx: &mut ExtCtxt, - struct_def: &VariantData) -> StaticFields { - let mut named_idents = Vec::new(); - let mut just_spans = Vec::new(); - for field in struct_def.fields(){ - let sp = self.set_expn_info(cx, field.span); - match field.node.kind { - ast::NamedField(ident, _) => named_idents.push((ident, sp)), - ast::UnnamedField(..) => just_spans.push(sp), - } - } - - match (just_spans.is_empty(), named_idents.is_empty()) { - (false, false) => cx.span_bug(self.span, - "a struct with named and unnamed \ - fields in generic `derive`"), - // named fields - (_, false) => Named(named_idents), - // tuple structs (includes empty structs) - (_, _) => Unnamed(just_spans) - } - } - - fn create_subpatterns(&self, - cx: &mut ExtCtxt, - field_paths: Vec<ast::SpannedIdent> , - mutbl: ast::Mutability) - -> Vec<P<ast::Pat>> { - field_paths.iter().map(|path| { - cx.pat(path.span, - ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None)) - }).collect() - } - - fn create_struct_pattern(&self, - cx: &mut ExtCtxt, - struct_path: ast::Path, - struct_def: &'a VariantData, - prefix: &str, - mutbl: ast::Mutability) - -> (P<ast::Pat>, Vec<(Span, Option<Ident>, - P<Expr>, - &'a [ast::Attribute])>) { - if struct_def.fields().is_empty() { - return (cx.pat_enum(self.span, struct_path, vec![]), vec![]); - } - - let mut paths = Vec::new(); - let mut ident_expr = Vec::new(); - let mut struct_type = Unknown; - - for (i, struct_field) in struct_def.fields().iter().enumerate() { - let sp = self.set_expn_info(cx, struct_field.span); - let opt_id = match struct_field.node.kind { - ast::NamedField(ident, _) if (struct_type == Unknown || - struct_type == Record) => { - struct_type = Record; - Some(ident) - } - ast::UnnamedField(..) if (struct_type == Unknown || - struct_type == Tuple) => { - struct_type = Tuple; - None - } - _ => { - cx.span_bug(sp, "a struct with named and unnamed fields in `derive`"); - } - }; - let ident = cx.ident_of(&format!("{}_{}", prefix, i)); - paths.push(codemap::Spanned{span: sp, node: ident}); - let val = cx.expr( - sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident))))); - ident_expr.push((sp, opt_id, val, &struct_field.node.attrs[..])); - } - - let subpats = self.create_subpatterns(cx, paths, mutbl); - - // struct_type is definitely not Unknown, since struct_def.fields - // must be nonempty to reach here - let pattern = if struct_type == Record { - let field_pats = subpats.into_iter().zip(&ident_expr) - .map(|(pat, &(_, id, _, _))| { - // id is guaranteed to be Some - codemap::Spanned { - span: pat.span, - node: ast::FieldPat { ident: id.unwrap(), pat: pat, is_shorthand: false }, - } - }).collect(); - cx.pat_struct(self.span, struct_path, field_pats) - } else { - cx.pat_enum(self.span, struct_path, subpats) - }; - - (pattern, ident_expr) - } - - fn create_enum_variant_pattern(&self, - cx: &mut ExtCtxt, - enum_ident: ast::Ident, - variant: &'a ast::Variant, - prefix: &str, - mutbl: ast::Mutability) - -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) { - let variant_ident = variant.node.name; - let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]); - self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) - } -} - -/* helpful premade recipes */ - -/// Fold the fields. `use_foldl` controls whether this is done -/// left-to-right (`true`) or right-to-left (`false`). -pub fn cs_fold<F>(use_foldl: bool, - mut f: F, - base: P<Expr>, - mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, - trait_span: Span, - substructure: &Substructure) - -> P<Expr> where - F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>, -{ - match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { - if use_foldl { - all_fields.iter().fold(base, |old, field| { - f(cx, - field.span, - old, - field.self_.clone(), - &field.other) - }) - } else { - all_fields.iter().rev().fold(base, |old, field| { - f(cx, - field.span, - old, - field.self_.clone(), - &field.other) - }) - } - }, - EnumNonMatchingCollapsed(ref all_args, _, tuple) => - enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple), - substructure.nonself_args), - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, "static function in `derive`") - } - } -} - - -/// Call the method that is being derived on all the fields, and then -/// process the collected results. i.e. -/// -/// ```ignore -/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1), -/// self_2.method(__arg_1_2, __arg_2_2)]) -/// ``` -#[inline] -pub fn cs_same_method<F>(f: F, - mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, - trait_span: Span, - substructure: &Substructure) - -> P<Expr> where - F: FnOnce(&mut ExtCtxt, Span, Vec<P<Expr>>) -> P<Expr>, -{ - match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { - // call self_n.method(other_1_n, other_2_n, ...) - let called = all_fields.iter().map(|field| { - cx.expr_method_call(field.span, - field.self_.clone(), - substructure.method_ident, - field.other.iter() - .map(|e| cx.expr_addr_of(field.span, e.clone())) - .collect()) - }).collect(); - - f(cx, trait_span, called) - }, - EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => - enum_nonmatch_f(cx, trait_span, (&all_self_args[..], tuple), - substructure.nonself_args), - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, "static function in `derive`") - } - } -} - -/// Fold together the results of calling the derived method on all the -/// fields. `use_foldl` controls whether this is done left-to-right -/// (`true`) or right-to-left (`false`). -#[inline] -pub fn cs_same_method_fold<F>(use_foldl: bool, - mut f: F, - base: P<Expr>, - enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, - trait_span: Span, - substructure: &Substructure) - -> P<Expr> where - F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>) -> P<Expr>, -{ - cs_same_method( - |cx, span, vals| { - if use_foldl { - vals.into_iter().fold(base.clone(), |old, new| { - f(cx, span, old, new) - }) - } else { - vals.into_iter().rev().fold(base.clone(), |old, new| { - f(cx, span, old, new) - }) - } - }, - enum_nonmatch_f, - cx, trait_span, substructure) -} - -/// Use a given binop to combine the result of calling the derived method -/// on all the fields. -#[inline] -pub fn cs_binop(binop: ast::BinOp_, base: P<Expr>, - enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, trait_span: Span, - substructure: &Substructure) -> P<Expr> { - cs_same_method_fold( - true, // foldl is good enough - |cx, span, old, new| { - cx.expr_binary(span, - binop, - old, new) - - }, - base, - enum_nonmatch_f, - cx, trait_span, substructure) -} - -/// cs_binop with binop == or -#[inline] -pub fn cs_or(enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, span: Span, - substructure: &Substructure) -> P<Expr> { - cs_binop(ast::BiOr, cx.expr_bool(span, false), - enum_nonmatch_f, - cx, span, substructure) -} - -/// cs_binop with binop == and -#[inline] -pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc, - cx: &mut ExtCtxt, span: Span, - substructure: &Substructure) -> P<Expr> { - cs_binop(ast::BiAnd, cx.expr_bool(span, true), - enum_nonmatch_f, - cx, span, substructure) -} diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs deleted file mode 100644 index 67826c9c6cd..00000000000 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! 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 self::PtrTy::*; -pub use self::Ty::*; - -use ast; -use ast::{Expr,Generics,Ident}; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use codemap::{Span,respan}; -use owned_slice::OwnedSlice; -use parse::token::special_idents; -use ptr::P; - -/// The types of pointers -#[derive(Clone, Eq, PartialEq)] -pub enum PtrTy<'a> { - /// &'lifetime mut - Borrowed(Option<&'a str>, ast::Mutability), - /// *mut - Raw(ast::Mutability), -} - -/// A path, e.g. `::std::option::Option::<i32>` (global). Has support -/// for type parameters and a lifetime. -#[derive(Clone, Eq, PartialEq)] -pub struct Path<'a> { - pub path: Vec<&'a str> , - pub lifetime: Option<&'a str>, - pub params: Vec<Box<Ty<'a>>>, - pub global: bool, -} - -impl<'a> Path<'a> { - pub fn new<'r>(path: Vec<&'r str> ) -> Path<'r> { - Path::new_(path, None, Vec::new(), true) - } - pub fn new_local<'r>(path: &'r str) -> Path<'r> { - Path::new_(vec!( path ), None, Vec::new(), false) - } - pub fn new_<'r>(path: Vec<&'r str> , - lifetime: Option<&'r str>, - params: Vec<Box<Ty<'r>>>, - global: bool) - -> Path<'r> { - Path { - path: path, - lifetime: lifetime, - params: params, - global: global - } - } - - 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 idents = self.path.iter().map(|s| cx.ident_of(*s)).collect(); - let lt = mk_lifetimes(cx, span, &self.lifetime); - let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); - - cx.path_all(span, self.global, idents, lt, tys, Vec::new()) - } -} - -/// A type. Supports pointers, Self, and literals -#[derive(Clone, Eq, PartialEq)] -pub enum Ty<'a> { - Self_, - /// &/Box/ Ty - Ptr(Box<Ty<'a>>, PtrTy<'a>), - /// mod::mod::Type<[lifetime], [Params...]>, including a plain type - /// parameter, and things like `i32` - Literal(Path<'a>), - /// includes unit - Tuple(Vec<Ty<'a>> ) -} - -pub fn borrowed_ptrty<'r>() -> PtrTy<'r> { - Borrowed(None, ast::MutImmutable) -} -pub fn borrowed<'r>(ty: Box<Ty<'r>>) -> Ty<'r> { - Ptr(ty, borrowed_ptrty()) -} - -pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> { - Some(Some(borrowed_ptrty())) -} - -pub fn borrowed_self<'r>() -> Ty<'r> { - borrowed(Box::new(Self_)) -} - -pub fn nil_ty<'r>() -> Ty<'r> { - Tuple(Vec::new()) -} - -fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option<ast::Lifetime> { - match *lt { - Some(ref s) => Some(cx.lifetime(span, cx.ident_of(*s).name)), - None => None - } -} - -fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec<ast::Lifetime> { - match *lt { - Some(ref s) => vec!(cx.lifetime(span, cx.ident_of(*s).name)), - None => vec!() - } -} - -impl<'a> Ty<'a> { - pub fn to_ty(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> P<ast::Ty> { - match *self { - Ptr(ref ty, ref ptr) => { - let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); - match *ptr { - Borrowed(ref lt, mutbl) => { - let lt = mk_lifetime(cx, span, lt); - cx.ty_rptr(span, raw_ty, lt, mutbl) - } - Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl) - } - } - Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) } - Self_ => { - cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) - } - Tuple(ref fields) => { - let ty = ast::TyTup(fields.iter() - .map(|f| f.to_ty(cx, span, self_ty, self_generics)) - .collect()); - cx.ty(span, ty) - } - } - } - - pub fn to_path(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> ast::Path { - match *self { - Self_ => { - let self_params = self_generics.ty_params.map(|ty_param| { - cx.ty_ident(span, ty_param.ident) - }); - let lifetimes = self_generics.lifetimes.iter() - .map(|d| d.lifetime) - .collect(); - - cx.path_all(span, false, vec!(self_ty), lifetimes, - self_params.into_vec(), Vec::new()) - } - Literal(ref p) => { - p.to_path(cx, span, self_ty, self_generics) - } - Ptr(..) => { cx.span_bug(span, "pointer in a path in generic `derive`") } - Tuple(..) => { cx.span_bug(span, "tuple in a path in generic `derive`") } - } - } -} - - -fn mk_ty_param(cx: &ExtCtxt, - span: Span, - name: &str, - bounds: &[Path], - self_ident: Ident, - self_generics: &Generics) - -> ast::TyParam { - let bounds = - bounds.iter().map(|b| { - let path = b.to_path(cx, span, self_ident, self_generics); - cx.typarambound(path) - }).collect(); - cx.typaram(span, cx.ident_of(name), bounds, None) -} - -fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>) - -> Generics { - Generics { - lifetimes: lifetimes, - ty_params: OwnedSlice::from_vec(ty_params), - where_clause: ast::WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: Vec::new(), - }, - } -} - -/// Lifetimes and bounds on type parameters -#[derive(Clone)] -pub struct LifetimeBounds<'a> { - pub lifetimes: Vec<(&'a str, Vec<&'a str>)>, - pub bounds: Vec<(&'a str, Vec<Path<'a>>)>, -} - -impl<'a> LifetimeBounds<'a> { - pub fn empty() -> LifetimeBounds<'a> { - LifetimeBounds { - lifetimes: Vec::new(), bounds: Vec::new() - } - } - pub fn to_generics(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> Generics { - let lifetimes = self.lifetimes.iter().map(|&(ref lt, ref bounds)| { - let bounds = - bounds.iter().map( - |b| cx.lifetime(span, cx.ident_of(*b).name)).collect(); - cx.lifetime_def(span, cx.ident_of(*lt).name, bounds) - }).collect(); - let ty_params = self.bounds.iter().map(|t| { - match *t { - (ref name, ref bounds) => { - mk_ty_param(cx, - span, - *name, - bounds, - self_ty, - self_generics) - } - } - }).collect(); - mk_generics(lifetimes, ty_params) - } -} - -pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option<PtrTy>) - -> (P<Expr>, ast::ExplicitSelf) { - // this constructs a fresh `self` path, which will match the fresh `self` binding - // created below. - let self_path = cx.expr_self(span); - match *self_ptr { - None => { - (self_path, respan(span, ast::SelfValue(special_idents::self_))) - } - Some(ref ptr) => { - let self_ty = respan( - span, - match *ptr { - Borrowed(ref lt, mutbl) => { - let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name)); - ast::SelfRegion(lt, mutbl, special_idents::self_) - } - Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition") - }); - let self_expr = cx.expr_deref(span, self_path); - (self_expr, self_ty) - } - } -} diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs deleted file mode 100644 index 96be774ebdc..00000000000 --- a/src/libsyntax/ext/deriving/hash.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr, MutMutable}; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use ptr::P; - -pub fn expand_deriving_hash(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - - let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, - vec!(), true); - let arg = Path::new_local("__H"); - let hash_trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path, - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "hash", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec![("__H", - vec![path_std!(cx, core::hash::Hasher)])], - }, - explicit_self: borrowed_explicit_self(), - args: vec!(Ptr(Box::new(Literal(arg)), Borrowed(None, MutMutable))), - ret_ty: nil_ty(), - attributes: vec![], - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - hash_substructure(a, b, c) - })) - } - ), - associated_types: Vec::new(), - }; - - hash_trait_def.expand(cx, mitem, item, push); -} - -fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> { - let state_expr = match (substr.nonself_args.len(), substr.nonself_args.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`") - }; - let call_hash = |span, thing_expr| { - let hash_path = { - let strs = cx.std_path(&["hash", "Hash", "hash"]); - - cx.expr_path(cx.path_global(span, strs)) - }; - let ref_thing = cx.expr_addr_of(span, thing_expr); - let expr = cx.expr_call(span, hash_path, vec!(ref_thing, state_expr.clone())); - cx.stmt_expr(expr) - }; - let mut stmts = Vec::new(); - - let fields = match *substr.fields { - Struct(ref fs) => fs, - EnumMatching(index, variant, ref fs) => { - // Determine the discriminant. We will feed this value to the byte - // iteration function. - let discriminant = match variant.node.disr_expr { - Some(ref d) => d.clone(), - None => cx.expr_usize(trait_span, index) - }; - - stmts.push(call_hash(trait_span, discriminant)); - - fs - } - _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`") - }; - - for &FieldInfo { ref self_, span, .. } in fields { - stmts.push(call_hash(span, self_.clone())); - } - - cx.expr_block(cx.block(trait_span, stmts, None)) -} diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs deleted file mode 100644 index d26bb794c88..00000000000 --- a/src/libsyntax/ext/deriving/mod.rs +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The compiler code necessary to implement the `#[derive]` extensions. -//! -//! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is -//! the standard library, and "std" is the core library. - -use ast::{MetaItem, MetaWord}; -use attr::AttrMetaMethods; -use ext::base::{ExtCtxt, SyntaxEnv, MultiDecorator, MultiItemDecorator, MultiModifier, Annotatable}; -use ext::build::AstBuilder; -use feature_gate; -use codemap::Span; -use parse::token::{intern, intern_and_get_ident}; - -macro_rules! pathvec { - ($($x:ident)::+) => ( - vec![ $( stringify!($x) ),+ ] - ) -} - -macro_rules! path { - ($($x:tt)*) => ( - ::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) ) - ) -} - -macro_rules! path_local { - ($x:ident) => ( - ::ext::deriving::generic::ty::Path::new_local(stringify!($x)) - ) -} - -macro_rules! pathvec_std { - ($cx:expr, $first:ident :: $($rest:ident)::+) => ({ - let mut v = pathvec!($($rest)::+); - if let Some(s) = $cx.crate_root { - v.insert(0, s); - } - v - }) -} - -macro_rules! path_std { - ($($x:tt)*) => ( - ::ext::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) ) - ) -} - -pub mod bounds; -pub mod clone; -pub mod encodable; -pub mod decodable; -pub mod hash; -pub mod debug; -pub mod default; -pub mod primitive; - -#[path="cmp/partial_eq.rs"] -pub mod partial_eq; -#[path="cmp/eq.rs"] -pub mod eq; -#[path="cmp/partial_ord.rs"] -pub mod partial_ord; -#[path="cmp/ord.rs"] -pub mod ord; - - -pub mod generic; - -fn expand_derive(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - annotatable: Annotatable) - -> Annotatable { - annotatable.map_item_or(|item| { - item.map(|mut item| { - if mitem.value_str().is_some() { - cx.span_err(mitem.span, "unexpected value in `derive`"); - } - - let traits = mitem.meta_item_list().unwrap_or(&[]); - if traits.is_empty() { - cx.span_warn(mitem.span, "empty trait list in `derive`"); - } - - for titem in traits.iter().rev() { - let tname = match titem.node { - MetaWord(ref tname) => tname, - _ => { - cx.span_err(titem.span, "malformed `derive` entry"); - continue; - } - }; - - if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) { - feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, - "custom_derive", - titem.span, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_CUSTOM_DERIVE); - continue; - } - - // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] - item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span, - intern_and_get_ident(&format!("derive_{}", tname))))); - } - - item - }) - }, |a| { - cx.span_err(span, "`derive` can only be applied to items"); - a - }) -} - -macro_rules! derive_traits { - ($( $name:expr => $func:path, )+) => { - pub fn register_all(env: &mut SyntaxEnv) { - // Define the #[derive_*] extensions. - $({ - struct DeriveExtension; - - impl MultiItemDecorator for DeriveExtension { - fn expand(&self, - ecx: &mut ExtCtxt, - sp: Span, - mitem: &MetaItem, - annotatable: &Annotatable, - push: &mut FnMut(Annotatable)) { - warn_if_deprecated(ecx, sp, $name); - $func(ecx, sp, mitem, annotatable, push); - } - } - - env.insert(intern(concat!("derive_", $name)), - MultiDecorator(Box::new(DeriveExtension))); - })+ - - env.insert(intern("derive"), - MultiModifier(Box::new(expand_derive))); - } - - fn is_builtin_trait(name: &str) -> bool { - match name { - $( $name )|+ => true, - _ => false, - } - } - } -} - -derive_traits! { - "Clone" => clone::expand_deriving_clone, - - "Hash" => hash::expand_deriving_hash, - - "RustcEncodable" => encodable::expand_deriving_rustc_encodable, - - "RustcDecodable" => decodable::expand_deriving_rustc_decodable, - - "PartialEq" => partial_eq::expand_deriving_partial_eq, - "Eq" => eq::expand_deriving_eq, - "PartialOrd" => partial_ord::expand_deriving_partial_ord, - "Ord" => ord::expand_deriving_ord, - - "Debug" => debug::expand_deriving_debug, - - "Default" => default::expand_deriving_default, - - "FromPrimitive" => primitive::expand_deriving_from_primitive, - - "Send" => bounds::expand_deriving_unsafe_bound, - "Sync" => bounds::expand_deriving_unsafe_bound, - "Copy" => bounds::expand_deriving_copy, - - // deprecated - "Encodable" => encodable::expand_deriving_encodable, - "Decodable" => decodable::expand_deriving_decodable, -} - -#[inline] // because `name` is a compile-time constant -fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) { - if let Some(replacement) = match name { - "Encodable" => Some("RustcEncodable"), - "Decodable" => Some("RustcDecodable"), - _ => None, - } { - ecx.span_warn(sp, &format!("derive({}) is deprecated in favor of derive({})", - name, replacement)); - } -} diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs deleted file mode 100644 index 07b58778358..00000000000 --- a/src/libsyntax/ext/deriving/primitive.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{MetaItem, Expr}; -use ast; -use codemap::Span; -use ext::base::{ExtCtxt, Annotatable}; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::num::FromPrimitive), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - methods: vec!( - MethodDef { - name: "from_i64", - generics: LifetimeBounds::empty(), - explicit_self: None, - args: vec!(Literal(path_local!(i64))), - ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option), - None, - vec!(Box::new(Self_)), - true)), - // #[inline] liable to cause code-bloat - attributes: attrs.clone(), - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|c, s, sub| { - cs_from("i64", c, s, sub) - })), - }, - MethodDef { - name: "from_u64", - generics: LifetimeBounds::empty(), - explicit_self: None, - args: vec!(Literal(path_local!(u64))), - ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option), - None, - vec!(Box::new(Self_)), - true)), - // #[inline] liable to cause code-bloat - attributes: attrs, - is_unsafe: false, - combine_substructure: combine_substructure(Box::new(|c, s, sub| { - cs_from("u64", c, s, sub) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> { - let n = match (substr.nonself_args.len(), substr.nonself_args.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(FromPrimitive)`") - }; - - match *substr.fields { - StaticStruct(..) => { - cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs"); - return cx.expr_fail(trait_span, InternedString::new("")); - } - StaticEnum(enum_def, _) => { - if enum_def.variants.is_empty() { - cx.span_err(trait_span, - "`FromPrimitive` cannot be derived for enums with no variants"); - return cx.expr_fail(trait_span, InternedString::new("")); - } - - let mut arms = Vec::new(); - - for variant in &enum_def.variants { - let def = &variant.node.data; - if !def.is_unit() { - cx.span_err(trait_span, "`FromPrimitive` cannot be derived \ - for enums with non-unit variants"); - return cx.expr_fail(trait_span, - InternedString::new("")); - } - - let span = variant.span; - - // expr for `$n == $variant as $name` - let path = cx.path(span, vec![substr.type_ident, variant.node.name]); - let variant = cx.expr_path(path); - let ty = cx.ty_ident(span, cx.ident_of(name)); - let cast = cx.expr_cast(span, variant.clone(), ty); - let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast); - - // expr for `Some($variant)` - let body = cx.expr_some(span, variant); - - // arm for `_ if $guard => $body` - let arm = ast::Arm { - attrs: vec!(), - pats: vec!(cx.pat_wild(span)), - guard: Some(guard), - body: body, - }; - - arms.push(arm); - } - - // arm for `_ => None` - let arm = ast::Arm { - attrs: vec!(), - pats: vec!(cx.pat_wild(trait_span)), - guard: None, - body: cx.expr_none(trait_span), - }; - arms.push(arm); - - cx.expr_match(trait_span, n.clone(), arms) - } - _ => cx.span_bug(trait_span, "expected StaticEnum in derive(FromPrimitive)") - } -} diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs deleted file mode 100644 index d85071e78af..00000000000 --- a/src/libsyntax/ext/env.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/* - * The compiler code necessary to support the env! extension. Eventually this - * should all get sucked into either the compiler syntax extension plugin - * interface. - */ - -use ast; -use codemap::Span; -use ext::base::*; -use ext::base; -use ext::build::AstBuilder; -use parse::token; - -use std::env; - -pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box<base::MacResult+'cx> { - let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { - None => return DummyResult::expr(sp), - Some(v) => v - }; - - let e = match env::var(&var[..]) { - Err(..) => { - cx.expr_path(cx.path_all(sp, - true, - cx.std_path(&["option", "Option", "None"]), - Vec::new(), - vec!(cx.ty_rptr(sp, - cx.ty_ident(sp, - cx.ident_of("str")), - Some(cx.lifetime(sp, - cx.ident_of( - "'static").name)), - ast::MutImmutable)), - Vec::new())) - } - Ok(s) => { - cx.expr_call_global(sp, - cx.std_path(&["option", "Option", "Some"]), - vec!(cx.expr_str(sp, - token::intern_and_get_ident( - &s[..])))) - } - }; - MacEager::expr(e) -} - -pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box<base::MacResult+'cx> { - let mut exprs = match get_exprs_from_tts(cx, sp, tts) { - Some(ref exprs) if exprs.is_empty() => { - cx.span_err(sp, "env! takes 1 or 2 arguments"); - return DummyResult::expr(sp); - } - None => return DummyResult::expr(sp), - Some(exprs) => exprs.into_iter() - }; - - let var = match expr_to_string(cx, - exprs.next().unwrap(), - "expected string literal") { - None => return DummyResult::expr(sp), - Some((v, _style)) => v - }; - let msg = match exprs.next() { - None => { - token::intern_and_get_ident(&format!("environment variable `{}` \ - not defined", - var)) - } - Some(second) => { - match expr_to_string(cx, second, "expected string literal") { - None => return DummyResult::expr(sp), - Some((s, _style)) => s - } - } - }; - - match exprs.next() { - None => {} - Some(_) => { - cx.span_err(sp, "env! takes 1 or 2 arguments"); - return DummyResult::expr(sp); - } - } - - let e = match env::var(&var[..]) { - Err(_) => { - cx.span_err(sp, &msg); - cx.expr_usize(sp, 0) - } - Ok(s) => cx.expr_str(sp, token::intern_and_get_ident(&s)) - }; - MacEager::expr(e) -} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 573f4cfe8fa..b1afe2bb69c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -21,7 +21,7 @@ use attr::{AttrMetaMethods, WithAttrs}; use codemap; use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use ext::base::*; -use feature_gate::{self, Features, GatedCfgAttr}; +use feature_gate::{self, Features}; use fold; use fold::*; use util::move_map::MoveMap; @@ -1276,15 +1276,11 @@ impl<'feat> ExpansionConfig<'feat> { } } -pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess, - cfg: ExpansionConfig<'feat>, - // these are the macros being imported to this crate: - imported_macros: Vec<ast::MacroDef>, - user_exts: Vec<NamedSyntaxExtension>, - feature_gated_cfgs: &mut Vec<GatedCfgAttr>, - c: Crate) -> (Crate, HashSet<Name>) { - let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg, - feature_gated_cfgs); +pub fn expand_crate(mut cx: ExtCtxt, + // these are the macros being imported to this crate: + imported_macros: Vec<ast::MacroDef>, + user_exts: Vec<NamedSyntaxExtension>, + c: Crate) -> (Crate, HashSet<Name>) { if std_inject::no_core(&c) { cx.crate_root = None; } else if std_inject::no_std(&c) { @@ -1305,7 +1301,7 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess, let mut ret = expander.fold_crate(c); ret.exported_macros = expander.cx.exported_macros.clone(); - parse_sess.span_diagnostic.handler().abort_if_errors(); + cx.parse_sess.span_diagnostic.handler().abort_if_errors(); ret }; return (ret, cx.syntax_env.names); @@ -1401,6 +1397,7 @@ mod tests { use ast; use ast::Name; use codemap; + use ext::base::ExtCtxt; use ext::mtwt; use fold::Folder; use parse; @@ -1471,7 +1468,9 @@ mod tests { src, Vec::new(), &sess); // should fail: - expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast); + let mut gated_cfgs = vec![]; + let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs); + expand_crate(ecx, vec![], vec![], crate_ast); } // make sure that macros can't escape modules @@ -1484,7 +1483,9 @@ mod tests { "<test>".to_string(), src, Vec::new(), &sess); - expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast); + let mut gated_cfgs = vec![]; + let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs); + expand_crate(ecx, vec![], vec![], crate_ast); } // macro_use modules should allow macros to escape @@ -1496,14 +1497,18 @@ mod tests { "<test>".to_string(), src, Vec::new(), &sess); - expand_crate(&sess, test_ecfg(), vec!(), vec!(), &mut vec![], crate_ast); + let mut gated_cfgs = vec![]; + let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs); + expand_crate(ecx, vec![], vec![], crate_ast); } fn expand_crate_str(crate_str: String) -> ast::Crate { let ps = parse::ParseSess::new(); let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod()); // the cfg argument actually does matter, here... - expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast).0 + let mut gated_cfgs = vec![]; + let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut gated_cfgs); + expand_crate(ecx, vec![], vec![], crate_ast).0 } // find the pat_ident paths in a crate diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs deleted file mode 100644 index 904cf0c4776..00000000000 --- a/src/libsyntax/ext/format.rs +++ /dev/null @@ -1,715 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use self::ArgumentType::*; -use self::Position::*; - -use ast; -use codemap::{Span, respan}; -use ext::base::*; -use ext::base; -use ext::build::AstBuilder; -use fmt_macros as parse; -use fold::Folder; -use parse::token::special_idents; -use parse::token; -use ptr::P; - -use std::collections::HashMap; - -#[derive(PartialEq)] -enum ArgumentType { - Known(String), - Unsigned -} - -enum Position { - Exact(usize), - Named(String), -} - -struct Context<'a, 'b:'a> { - ecx: &'a mut ExtCtxt<'b>, - /// The macro's call site. References to unstable formatting internals must - /// use this span to pass the stability checker. - macsp: Span, - /// The span of the format string literal. - fmtsp: Span, - - /// Parsed argument expressions and the types that we've found so far for - /// them. - args: Vec<P<ast::Expr>>, - arg_types: Vec<Option<ArgumentType>>, - /// Parsed named expressions and the types that we've found for them so far. - /// Note that we keep a side-array of the ordering of the named arguments - /// found to be sure that we can translate them in the same order that they - /// were declared in. - names: HashMap<String, P<ast::Expr>>, - name_types: HashMap<String, ArgumentType>, - name_ordering: Vec<String>, - - /// The latest consecutive literal strings, or empty if there weren't any. - literal: String, - - /// Collection of the compiled `rt::Argument` structures - pieces: Vec<P<ast::Expr>>, - /// Collection of string literals - str_pieces: Vec<P<ast::Expr>>, - /// Stays `true` if all formatting parameters are default (as in "{}{}"). - all_pieces_simple: bool, - - name_positions: HashMap<String, usize>, - - /// Updated as arguments are consumed or methods are entered - nest_level: usize, - next_arg: usize, -} - -/// Parses the arguments from the given list of tokens, returning None -/// if there's a parse error so we can continue parsing other format! -/// expressions. -/// -/// If parsing succeeds, the return value is: -/// ```ignore -/// Some((fmtstr, unnamed arguments, ordering of named arguments, -/// named arguments)) -/// ``` -fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Option<(P<ast::Expr>, Vec<P<ast::Expr>>, Vec<String>, - HashMap<String, P<ast::Expr>>)> { - let mut args = Vec::new(); - let mut names = HashMap::<String, P<ast::Expr>>::new(); - let mut order = Vec::new(); - - let mut p = ecx.new_parser_from_tts(tts); - - if p.token == token::Eof { - ecx.span_err(sp, "requires at least a format string argument"); - return None; - } - let fmtstr = panictry!(p.parse_expr()); - let mut named = false; - while p.token != token::Eof { - if !panictry!(p.eat(&token::Comma)) { - ecx.span_err(sp, "expected token: `,`"); - return None; - } - if p.token == token::Eof { break } // accept trailing commas - if named || (p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq)) { - named = true; - let ident = match p.token { - token::Ident(i, _) => { - panictry!(p.bump()); - i - } - _ if named => { - ecx.span_err(p.span, - "expected ident, positional arguments \ - cannot follow named arguments"); - return None; - } - _ => { - ecx.span_err(p.span, - &format!("expected ident for named argument, found `{}`", - p.this_token_to_string())); - return None; - } - }; - let name: &str = &ident.name.as_str(); - - panictry!(p.expect(&token::Eq)); - let e = panictry!(p.parse_expr()); - match names.get(name) { - None => {} - Some(prev) => { - ecx.span_err(e.span, - &format!("duplicate argument named `{}`", - name)); - ecx.parse_sess.span_diagnostic.span_note(prev.span, "previously here"); - continue - } - } - order.push(name.to_string()); - names.insert(name.to_string(), e); - } else { - args.push(panictry!(p.parse_expr())); - } - } - Some((fmtstr, args, order, names)) -} - -impl<'a, 'b> Context<'a, 'b> { - /// Verifies one piece of a parse string. All errors are not emitted as - /// fatal so we can continue giving errors about this and possibly other - /// format strings. - fn verify_piece(&mut self, p: &parse::Piece) { - match *p { - parse::String(..) => {} - parse::NextArgument(ref arg) => { - // width/precision first, if they have implicit positional - // parameters it makes more sense to consume them first. - self.verify_count(arg.format.width); - self.verify_count(arg.format.precision); - - // argument second, if it's an implicit positional parameter - // it's written second, so it should come after width/precision. - let pos = match arg.position { - parse::ArgumentNext => { - let i = self.next_arg; - if self.check_positional_ok() { - self.next_arg += 1; - } - Exact(i) - } - parse::ArgumentIs(i) => Exact(i), - parse::ArgumentNamed(s) => Named(s.to_string()), - }; - - let ty = Known(arg.format.ty.to_string()); - self.verify_arg_type(pos, ty); - } - } - } - - fn verify_count(&mut self, c: parse::Count) { - match c { - parse::CountImplied | parse::CountIs(..) => {} - parse::CountIsParam(i) => { - self.verify_arg_type(Exact(i), Unsigned); - } - parse::CountIsName(s) => { - self.verify_arg_type(Named(s.to_string()), Unsigned); - } - parse::CountIsNextParam => { - if self.check_positional_ok() { - let next_arg = self.next_arg; - self.verify_arg_type(Exact(next_arg), Unsigned); - self.next_arg += 1; - } - } - } - } - - fn check_positional_ok(&mut self) -> bool { - if self.nest_level != 0 { - self.ecx.span_err(self.fmtsp, "cannot use implicit positional \ - arguments nested inside methods"); - false - } else { - true - } - } - - fn describe_num_args(&self) -> String { - match self.args.len() { - 0 => "no arguments given".to_string(), - 1 => "there is 1 argument".to_string(), - x => format!("there are {} arguments", x), - } - } - - fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) { - match arg { - Exact(arg) => { - if self.args.len() <= arg { - let msg = format!("invalid reference to argument `{}` ({})", - arg, self.describe_num_args()); - - self.ecx.span_err(self.fmtsp, &msg[..]); - return; - } - { - let arg_type = match self.arg_types[arg] { - None => None, - Some(ref x) => Some(x) - }; - self.verify_same(self.args[arg].span, &ty, arg_type); - } - if self.arg_types[arg].is_none() { - self.arg_types[arg] = Some(ty); - } - } - - Named(name) => { - let span = match self.names.get(&name) { - Some(e) => e.span, - None => { - let msg = format!("there is no argument named `{}`", name); - self.ecx.span_err(self.fmtsp, &msg[..]); - return; - } - }; - self.verify_same(span, &ty, self.name_types.get(&name)); - if !self.name_types.contains_key(&name) { - self.name_types.insert(name.clone(), ty); - } - // Assign this named argument a slot in the arguments array if - // it hasn't already been assigned a slot. - if !self.name_positions.contains_key(&name) { - let slot = self.name_positions.len(); - self.name_positions.insert(name, slot); - } - } - } - } - - /// When we're keeping track of the types that are declared for certain - /// arguments, we assume that `None` means we haven't seen this argument - /// yet, `Some(None)` means that we've seen the argument, but no format was - /// specified, and `Some(Some(x))` means that the argument was declared to - /// have type `x`. - /// - /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true - /// that: `Some(None) == Some(Some(x))` - fn verify_same(&self, - sp: Span, - ty: &ArgumentType, - before: Option<&ArgumentType>) { - let cur = match before { - None => return, - Some(t) => t, - }; - if *ty == *cur { - return - } - match (cur, ty) { - (&Known(ref cur), &Known(ref ty)) => { - self.ecx.span_err(sp, - &format!("argument redeclared with type `{}` when \ - it was previously `{}`", - *ty, - *cur)); - } - (&Known(ref cur), _) => { - self.ecx.span_err(sp, - &format!("argument used to format with `{}` was \ - attempted to not be used for formatting", - *cur)); - } - (_, &Known(ref ty)) => { - self.ecx.span_err(sp, - &format!("argument previously used as a format \ - argument attempted to be used as `{}`", - *ty)); - } - (_, _) => { - self.ecx.span_err(sp, "argument declared with multiple formats"); - } - } - } - - fn rtpath(ecx: &ExtCtxt, s: &str) -> Vec<ast::Ident> { - ecx.std_path(&["fmt", "rt", "v1", s]) - } - - fn trans_count(&self, c: parse::Count) -> P<ast::Expr> { - let sp = self.macsp; - let count = |c, arg| { - let mut path = Context::rtpath(self.ecx, "Count"); - path.push(self.ecx.ident_of(c)); - match arg { - Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]), - None => self.ecx.expr_path(self.ecx.path_global(sp, path)), - } - }; - match c { - parse::CountIs(i) => count("Is", Some(self.ecx.expr_usize(sp, i))), - parse::CountIsParam(i) => { - count("Param", Some(self.ecx.expr_usize(sp, i))) - } - parse::CountImplied => count("Implied", None), - parse::CountIsNextParam => count("NextParam", None), - parse::CountIsName(n) => { - let i = match self.name_positions.get(n) { - Some(&i) => i, - None => 0, // error already emitted elsewhere - }; - let i = i + self.args.len(); - count("Param", Some(self.ecx.expr_usize(sp, i))) - } - } - } - - /// Translate the accumulated string literals to a literal expression - fn trans_literal_string(&mut self) -> P<ast::Expr> { - let sp = self.fmtsp; - let s = token::intern_and_get_ident(&self.literal); - self.literal.clear(); - self.ecx.expr_str(sp, s) - } - - /// Translate a `parse::Piece` to a static `rt::Argument` or append - /// to the `literal` string. - fn trans_piece(&mut self, piece: &parse::Piece) -> Option<P<ast::Expr>> { - let sp = self.macsp; - match *piece { - parse::String(s) => { - self.literal.push_str(s); - None - } - parse::NextArgument(ref arg) => { - // Translate the position - let pos = { - let pos = |c, arg| { - let mut path = Context::rtpath(self.ecx, "Position"); - path.push(self.ecx.ident_of(c)); - match arg { - Some(i) => { - let arg = self.ecx.expr_usize(sp, i); - self.ecx.expr_call_global(sp, path, vec![arg]) - } - None => { - self.ecx.expr_path(self.ecx.path_global(sp, path)) - } - } - }; - match arg.position { - // These two have a direct mapping - parse::ArgumentNext => pos("Next", None), - parse::ArgumentIs(i) => pos("At", Some(i)), - - // Named arguments are converted to positional arguments - // at the end of the list of arguments - parse::ArgumentNamed(n) => { - let i = match self.name_positions.get(n) { - Some(&i) => i, - None => 0, // error already emitted elsewhere - }; - let i = i + self.args.len(); - pos("At", Some(i)) - } - } - }; - - let simple_arg = parse::Argument { - position: parse::ArgumentNext, - format: parse::FormatSpec { - fill: arg.format.fill, - align: parse::AlignUnknown, - flags: 0, - precision: parse::CountImplied, - width: parse::CountImplied, - ty: arg.format.ty - } - }; - - let fill = match arg.format.fill { Some(c) => c, None => ' ' }; - - if *arg != simple_arg || fill != ' ' { - self.all_pieces_simple = false; - } - - // Translate the format - let fill = self.ecx.expr_lit(sp, ast::LitChar(fill)); - let align = |name| { - let mut p = Context::rtpath(self.ecx, "Alignment"); - p.push(self.ecx.ident_of(name)); - self.ecx.path_global(sp, p) - }; - let align = match arg.format.align { - parse::AlignLeft => align("Left"), - parse::AlignRight => align("Right"), - parse::AlignCenter => align("Center"), - parse::AlignUnknown => align("Unknown"), - }; - let align = self.ecx.expr_path(align); - let flags = self.ecx.expr_u32(sp, arg.format.flags); - let prec = self.trans_count(arg.format.precision); - let width = self.trans_count(arg.format.width); - let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "FormatSpec")); - let fmt = self.ecx.expr_struct(sp, path, vec!( - self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill), - self.ecx.field_imm(sp, self.ecx.ident_of("align"), align), - self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags), - self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec), - self.ecx.field_imm(sp, self.ecx.ident_of("width"), width))); - - let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "Argument")); - Some(self.ecx.expr_struct(sp, path, vec!( - self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos), - self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt)))) - } - } - } - - fn static_array(ecx: &mut ExtCtxt, - name: &str, - piece_ty: P<ast::Ty>, - pieces: Vec<P<ast::Expr>>) - -> P<ast::Expr> { - let sp = piece_ty.span; - let ty = ecx.ty_rptr(sp, - ecx.ty(sp, ast::TyVec(piece_ty)), - Some(ecx.lifetime(sp, special_idents::static_lifetime.name)), - ast::MutImmutable); - let slice = ecx.expr_vec_slice(sp, pieces); - // static instead of const to speed up codegen by not requiring this to be inlined - let st = ast::ItemStatic(ty, ast::MutImmutable, slice); - - let name = ecx.ident_of(name); - let item = ecx.item(sp, name, vec![], st); - let decl = respan(sp, ast::DeclItem(item)); - - // Wrap the declaration in a block so that it forms a single expression. - ecx.expr_block(ecx.block(sp, - vec![P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))], - Some(ecx.expr_ident(sp, name)))) - } - - /// Actually builds the expression which the iformat! block will be expanded - /// to - fn into_expr(mut self) -> P<ast::Expr> { - let mut locals = Vec::new(); - let mut names = vec![None; self.name_positions.len()]; - let mut pats = Vec::new(); - let mut heads = Vec::new(); - - // First, build up the static array which will become our precompiled - // format "string" - let static_lifetime = self.ecx.lifetime(self.fmtsp, special_idents::static_lifetime.name); - let piece_ty = self.ecx.ty_rptr( - self.fmtsp, - self.ecx.ty_ident(self.fmtsp, self.ecx.ident_of("str")), - Some(static_lifetime), - ast::MutImmutable); - let pieces = Context::static_array(self.ecx, - "__STATIC_FMTSTR", - piece_ty, - self.str_pieces); - - - // Right now there is a bug such that for the expression: - // foo(bar(&1)) - // the lifetime of `1` doesn't outlast the call to `bar`, so it's not - // valid for the call to `foo`. To work around this all arguments to the - // format! string are shoved into locals. Furthermore, we shove the address - // of each variable because we don't want to move out of the arguments - // passed to this function. - for (i, e) in self.args.into_iter().enumerate() { - let arg_ty = match self.arg_types[i].as_ref() { - Some(ty) => ty, - None => continue // error already generated - }; - - let name = self.ecx.ident_of(&format!("__arg{}", i)); - pats.push(self.ecx.pat_ident(e.span, name)); - locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, - self.ecx.expr_ident(e.span, name))); - heads.push(self.ecx.expr_addr_of(e.span, e)); - } - for name in &self.name_ordering { - let e = match self.names.remove(name) { - Some(e) => e, - None => continue - }; - let arg_ty = match self.name_types.get(name) { - Some(ty) => ty, - None => continue - }; - - let lname = self.ecx.ident_of(&format!("__arg{}", - *name)); - pats.push(self.ecx.pat_ident(e.span, lname)); - names[*self.name_positions.get(name).unwrap()] = - Some(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, - self.ecx.expr_ident(e.span, lname))); - heads.push(self.ecx.expr_addr_of(e.span, e)); - } - - // Now create a vector containing all the arguments - let args = locals.into_iter().chain(names.into_iter().map(|a| a.unwrap())); - - let args_array = self.ecx.expr_vec(self.fmtsp, args.collect()); - - // Constructs an AST equivalent to: - // - // match (&arg0, &arg1) { - // (tmp0, tmp1) => args_array - // } - // - // It was: - // - // let tmp0 = &arg0; - // let tmp1 = &arg1; - // args_array - // - // Because of #11585 the new temporary lifetime rule, the enclosing - // statements for these temporaries become the let's themselves. - // If one or more of them are RefCell's, RefCell borrow() will also - // end there; they don't last long enough for args_array to use them. - // The match expression solves the scope problem. - // - // Note, it may also very well be transformed to: - // - // match arg0 { - // ref tmp0 => { - // match arg1 => { - // ref tmp1 => args_array } } } - // - // But the nested match expression is proved to perform not as well - // as series of let's; the first approach does. - let pat = self.ecx.pat_tuple(self.fmtsp, pats); - let arm = self.ecx.arm(self.fmtsp, vec!(pat), args_array); - let head = self.ecx.expr(self.fmtsp, ast::ExprTup(heads)); - let result = self.ecx.expr_match(self.fmtsp, head, vec!(arm)); - - let args_slice = self.ecx.expr_addr_of(self.fmtsp, result); - - // Now create the fmt::Arguments struct with all our locals we created. - let (fn_name, fn_args) = if self.all_pieces_simple { - ("new_v1", vec![pieces, args_slice]) - } else { - // Build up the static array which will store our precompiled - // nonstandard placeholders, if there are any. - let piece_ty = self.ecx.ty_path(self.ecx.path_global( - self.macsp, - Context::rtpath(self.ecx, "Argument"))); - let fmt = Context::static_array(self.ecx, - "__STATIC_FMTARGS", - piece_ty, - self.pieces); - - ("new_v1_formatted", vec![pieces, args_slice, fmt]) - }; - - let path = self.ecx.std_path(&["fmt", "Arguments", fn_name]); - self.ecx.expr_call_global(self.macsp, path, fn_args) - } - - fn format_arg(ecx: &ExtCtxt, macsp: Span, sp: Span, - ty: &ArgumentType, arg: P<ast::Expr>) - -> P<ast::Expr> { - let trait_ = match *ty { - Known(ref tyname) => { - match &tyname[..] { - "" => "Display", - "?" => "Debug", - "e" => "LowerExp", - "E" => "UpperExp", - "o" => "Octal", - "p" => "Pointer", - "b" => "Binary", - "x" => "LowerHex", - "X" => "UpperHex", - _ => { - ecx.span_err(sp, - &format!("unknown format trait `{}`", - *tyname)); - "Dummy" - } - } - } - Unsigned => { - let path = ecx.std_path(&["fmt", "ArgumentV1", "from_usize"]); - return ecx.expr_call_global(macsp, path, vec![arg]) - } - }; - - let path = ecx.std_path(&["fmt", trait_, "fmt"]); - let format_fn = ecx.path_global(sp, path); - let path = ecx.std_path(&["fmt", "ArgumentV1", "new"]); - ecx.expr_call_global(macsp, path, vec![arg, ecx.expr_path(format_fn)]) - } -} - -pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) - -> Box<base::MacResult+'cx> { - - match parse_args(ecx, sp, tts) { - Some((efmt, args, order, names)) => { - MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, - args, order, names)) - } - None => DummyResult::expr(sp) - } -} - -/// Take the various parts of `format_args!(efmt, args..., name=names...)` -/// and construct the appropriate formatting expression. -pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, - efmt: P<ast::Expr>, - args: Vec<P<ast::Expr>>, - name_ordering: Vec<String>, - names: HashMap<String, P<ast::Expr>>) - -> P<ast::Expr> { - let arg_types: Vec<_> = (0..args.len()).map(|_| None).collect(); - let macsp = ecx.call_site(); - // Expand the format literal so that efmt.span will have a backtrace. This - // is essential for locating a bug when the format literal is generated in - // a macro. (e.g. println!("{}"), which uses concat!($fmt, "\n")). - let efmt = ecx.expander().fold_expr(efmt); - let mut cx = Context { - ecx: ecx, - args: args, - arg_types: arg_types, - names: names, - name_positions: HashMap::new(), - name_types: HashMap::new(), - name_ordering: name_ordering, - nest_level: 0, - next_arg: 0, - literal: String::new(), - pieces: Vec::new(), - str_pieces: Vec::new(), - all_pieces_simple: true, - macsp: macsp, - fmtsp: efmt.span, - }; - let fmt = match expr_to_string(cx.ecx, - efmt, - "format argument must be a string literal.") { - Some((fmt, _)) => fmt, - None => return DummyResult::raw_expr(sp) - }; - - let mut parser = parse::Parser::new(&fmt); - - loop { - match parser.next() { - Some(piece) => { - if !parser.errors.is_empty() { break } - cx.verify_piece(&piece); - match cx.trans_piece(&piece) { - Some(piece) => { - let s = cx.trans_literal_string(); - cx.str_pieces.push(s); - cx.pieces.push(piece); - } - None => {} - } - } - None => break - } - } - if !parser.errors.is_empty() { - cx.ecx.span_err(cx.fmtsp, &format!("invalid format string: {}", - parser.errors.remove(0))); - return DummyResult::raw_expr(sp); - } - if !cx.literal.is_empty() { - let s = cx.trans_literal_string(); - cx.str_pieces.push(s); - } - - // Make sure that all arguments were used and all arguments have types. - for (i, ty) in cx.arg_types.iter().enumerate() { - if ty.is_none() { - cx.ecx.span_err(cx.args[i].span, "argument never used"); - } - } - for (name, e) in &cx.names { - if !cx.name_types.contains_key(name) { - cx.ecx.span_err(e.span, "named argument never used"); - } - } - - cx.into_expr() -} diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs deleted file mode 100644 index 5f7ce8d9941..00000000000 --- a/src/libsyntax/ext/log_syntax.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast; -use codemap; -use ext::base; -use feature_gate; -use print; - -pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt, - sp: codemap::Span, - tts: &[ast::TokenTree]) - -> Box<base::MacResult+'cx> { - if !cx.ecfg.enable_log_syntax() { - feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, - "log_syntax", - sp, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_LOG_SYNTAX); - return base::DummyResult::any(sp); - } - - println!("{}", print::pprust::tts_to_string(tts)); - - // any so that `log_syntax` can be invoked as an expression and item. - base::DummyResult::any(sp) -} diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs deleted file mode 100644 index 628b88d1353..00000000000 --- a/src/libsyntax/ext/trace_macros.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::TokenTree; -use codemap::Span; -use ext::base::ExtCtxt; -use ext::base; -use feature_gate; -use parse::token::keywords; - - -pub fn expand_trace_macros(cx: &mut ExtCtxt, - sp: Span, - tt: &[TokenTree]) - -> Box<base::MacResult+'static> { - if !cx.ecfg.enable_trace_macros() { - feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, - "trace_macros", - sp, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_TRACE_MACROS); - return base::DummyResult::any(sp); - } - - match (tt.len(), tt.first()) { - (1, Some(&TokenTree::Token(_, ref tok))) if tok.is_keyword(keywords::True) => { - cx.set_trace_macros(true); - } - (1, Some(&TokenTree::Token(_, ref tok))) if tok.is_keyword(keywords::False) => { - cx.set_trace_macros(false); - } - _ => cx.span_err(sp, "trace_macros! accepts only `true` or `false`"), - } - - base::DummyResult::any(sp) -} diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 4498120a78f..73d7025b4f1 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -37,7 +37,6 @@ #![feature(str_escape)] #![feature(unicode)] -extern crate fmt_macros; extern crate serialize; extern crate term; extern crate libc; @@ -110,21 +109,12 @@ pub mod print { } pub mod ext { - pub mod asm; pub mod base; pub mod build; - pub mod cfg; - pub mod concat; - pub mod concat_idents; - pub mod deriving; - pub mod env; pub mod expand; - pub mod format; - pub mod log_syntax; pub mod mtwt; pub mod quote; pub mod source_util; - pub mod trace_macros; pub mod tt { pub mod transcribe; |
