diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2019-12-29 16:39:31 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2019-12-30 19:18:16 +0300 |
| commit | b683de4ad79242fdeebcae2afefb72c1530babe9 (patch) | |
| tree | e46daf86fae68f2246b1dd80500f4a504d452b84 /src/libsyntax_ext/deriving | |
| parent | 0fb43801368ae8b5931583f813071120bed55c35 (diff) | |
| download | rust-b683de4ad79242fdeebcae2afefb72c1530babe9.tar.gz rust-b683de4ad79242fdeebcae2afefb72c1530babe9.zip | |
Rename directories for some crates from `syntax_x` to `rustc_x`
`syntax_expand` -> `rustc_expand` `syntax_pos` -> `rustc_span` `syntax_ext` -> `rustc_builtin_macros`
Diffstat (limited to 'src/libsyntax_ext/deriving')
| -rw-r--r-- | src/libsyntax_ext/deriving/bounds.rs | 29 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/clone.rs | 225 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/cmp/eq.rs | 104 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/cmp/ord.rs | 113 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/cmp/partial_eq.rs | 112 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/cmp/partial_ord.rs | 302 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/debug.rs | 137 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/decodable.rs | 225 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/default.rs | 83 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/encodable.rs | 287 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/generic/mod.rs | 1812 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/generic/ty.rs | 283 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/hash.rs | 92 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/mod.rs | 171 |
14 files changed, 0 insertions, 3975 deletions
diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs deleted file mode 100644 index 9793ac1ca08..00000000000 --- a/src/libsyntax_ext/deriving/bounds.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::path_std; - -use syntax::ast::MetaItem; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::Span; - -pub fn expand_deriving_copy( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), -) { - let trait_def = TraitDef { - span, - attributes: Vec::new(), - path: path_std!(cx, marker::Copy), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: true, - 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 171e4104c0a..00000000000 --- a/src/libsyntax_ext/deriving/clone.rs +++ /dev/null @@ -1,225 +0,0 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::path_std; - -use syntax::ast::{self, Expr, GenericArg, Generics, ItemKind, MetaItem, VariantData}; -use syntax::ptr::P; -use syntax::symbol::{kw, sym, Symbol}; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::Span; - -pub fn expand_deriving_clone( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), -) { - // check if we can use a short form - // - // the short form is `fn clone(&self) -> Self { *self }` - // - // we can use the short form if: - // - the item is Copy (unfortunately, all we can check is whether it's also deriving Copy) - // - there are no generic parameters (after specialization this limitation can be removed) - // if we used the short form with generics, we'd have to bound the generics with - // Clone + Copy, and then there'd be no Clone impl at all if the user fills in something - // that is Clone but not Copy. and until specialization we can't write both impls. - // - the item is a union with Copy fields - // Unions with generic parameters still can derive Clone because they require Copy - // for deriving, Clone alone is not enough. - // Whever Clone is implemented for fields is irrelevant so we don't assert it. - let bounds; - let substructure; - let is_shallow; - match *item { - Annotatable::Item(ref annitem) => match annitem.kind { - ItemKind::Struct(_, Generics { ref params, .. }) - | ItemKind::Enum(_, Generics { ref params, .. }) => { - let container_id = cx.current_expansion.id.expn_data().parent; - if cx.resolver.has_derive_copy(container_id) - && !params.iter().any(|param| match param.kind { - ast::GenericParamKind::Type { .. } => true, - _ => false, - }) - { - bounds = vec![]; - is_shallow = true; - substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_shallow("Clone", c, s, sub, false) - })); - } else { - bounds = vec![]; - is_shallow = false; - substructure = - combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub))); - } - } - ItemKind::Union(..) => { - bounds = vec![Literal(path_std!(cx, marker::Copy))]; - is_shallow = true; - substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_shallow("Clone", c, s, sub, true) - })); - } - _ => { - bounds = vec![]; - is_shallow = false; - substructure = - combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub))); - } - }, - - _ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"), - } - - let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; - let trait_def = TraitDef { - span, - attributes: Vec::new(), - path: path_std!(cx, clone::Clone), - additional_bounds: bounds, - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: true, - methods: vec![MethodDef { - name: "clone", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: Vec::new(), - ret_ty: Self_, - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: false, - combine_substructure: substructure, - }], - associated_types: Vec::new(), - }; - - trait_def.expand_ext(cx, mitem, item, push, is_shallow) -} - -fn cs_clone_shallow( - name: &str, - cx: &mut ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, - is_union: bool, -) -> P<Expr> { - fn assert_ty_bounds( - cx: &mut ExtCtxt<'_>, - stmts: &mut Vec<ast::Stmt>, - ty: P<ast::Ty>, - span: Span, - helper_name: &str, - ) { - // Generate statement `let _: helper_name<ty>;`, - // set the expn ID so we can use the unstable struct. - let span = cx.with_def_site_ctxt(span); - let assert_path = cx.path_all( - span, - true, - cx.std_path(&[sym::clone, Symbol::intern(helper_name)]), - vec![GenericArg::Type(ty)], - ); - stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); - } - fn process_variant(cx: &mut ExtCtxt<'_>, stmts: &mut Vec<ast::Stmt>, variant: &VariantData) { - for field in variant.fields() { - // let _: AssertParamIsClone<FieldTy>; - assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsClone"); - } - } - - let mut stmts = Vec::new(); - if is_union { - // let _: AssertParamIsCopy<Self>; - let self_ty = - cx.ty_path(cx.path_ident(trait_span, ast::Ident::with_dummy_span(kw::SelfUpper))); - assert_ty_bounds(cx, &mut stmts, self_ty, trait_span, "AssertParamIsCopy"); - } else { - match *substr.fields { - StaticStruct(vdata, ..) => { - process_variant(cx, &mut stmts, vdata); - } - StaticEnum(enum_def, ..) => { - for variant in &enum_def.variants { - process_variant(cx, &mut stmts, &variant.data); - } - } - _ => cx.span_bug( - trait_span, - &format!( - "unexpected substructure in \ - shallow `derive({})`", - name - ), - ), - } - } - stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span)))); - cx.expr_block(cx.block(trait_span, stmts)) -} - -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(&[sym::clone, sym::Clone, sym::clone]); - let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo<'_>| { - let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; - cx.expr_call_global(field.span, fn_path.clone(), args) - }; - - let vdata; - match *substr.fields { - Struct(vdata_, ref af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident]); - all_fields = af; - vdata = vdata_; - } - EnumMatching(.., variant, ref af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.ident]); - all_fields = af; - vdata = &variant.data; - } - EnumNonMatchingCollapsed(..) => { - cx.span_bug(trait_span, &format!("non-matching enum variants in `derive({})`", name,)) - } - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, &format!("associated function in `derive({})`", name)) - } - } - - match *vdata { - VariantData::Struct(..) => { - 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,), - ), - }; - let call = subcall(cx, field); - cx.field_imm(field.span, ident, call) - }) - .collect::<Vec<_>>(); - - cx.expr_struct(trait_span, ctor_path, fields) - } - VariantData::Tuple(..) => { - let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect(); - let path = cx.expr_path(ctor_path); - cx.expr_call(trait_span, path, subcalls) - } - VariantData::Unit(..) => cx.expr_path(ctor_path), - } -} diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs deleted file mode 100644 index f292ec0e428..00000000000 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::path_std; - -use syntax::ast::{self, Expr, GenericArg, Ident, MetaItem}; -use syntax::ptr::P; -use syntax::symbol::{sym, Symbol}; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::Span; - -pub fn expand_deriving_eq( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), -) { - let inline = cx.meta_word(span, sym::inline); - let hidden = syntax::attr::mk_nested_word_item(Ident::new(sym::hidden, span)); - let doc = syntax::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]); - let attrs = vec![cx.attribute(inline), cx.attribute(doc)]; - let trait_def = TraitDef { - span, - attributes: Vec::new(), - path: path_std!(cx, cmp::Eq), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: true, - 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, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_total_eq_assert(a, b, c) - })), - }], - associated_types: Vec::new(), - }; - - super::inject_impl_of_structural_trait( - cx, - span, - item, - path_std!(cx, marker::StructuralEq), - push, - ); - - trait_def.expand_ext(cx, mitem, item, push, true) -} - -fn cs_total_eq_assert( - cx: &mut ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, -) -> P<Expr> { - fn assert_ty_bounds( - cx: &mut ExtCtxt<'_>, - stmts: &mut Vec<ast::Stmt>, - ty: P<ast::Ty>, - span: Span, - helper_name: &str, - ) { - // Generate statement `let _: helper_name<ty>;`, - // set the expn ID so we can use the unstable struct. - let span = cx.with_def_site_ctxt(span); - let assert_path = cx.path_all( - span, - true, - cx.std_path(&[sym::cmp, Symbol::intern(helper_name)]), - vec![GenericArg::Type(ty)], - ); - stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); - } - fn process_variant( - cx: &mut ExtCtxt<'_>, - stmts: &mut Vec<ast::Stmt>, - variant: &ast::VariantData, - ) { - for field in variant.fields() { - // let _: AssertParamIsEq<FieldTy>; - assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsEq"); - } - } - - let mut stmts = Vec::new(); - match *substr.fields { - StaticStruct(vdata, ..) => { - process_variant(cx, &mut stmts, vdata); - } - StaticEnum(enum_def, ..) => { - for variant in &enum_def.variants { - process_variant(cx, &mut stmts, &variant.data); - } - } - _ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`"), - } - cx.expr_block(cx.block(trait_span, stmts)) -} diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs deleted file mode 100644 index e009763da1b..00000000000 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::path_std; - -use syntax::ast::{self, Expr, MetaItem}; -use syntax::ptr::P; -use syntax::symbol::sym; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::Span; - -pub fn expand_deriving_ord( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), -) { - let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; - let trait_def = TraitDef { - span, - attributes: Vec::new(), - path: path_std!(cx, cmp::Ord), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: false, - methods: vec![MethodDef { - name: "cmp", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(borrowed_self(), "other")], - ret_ty: Literal(path_std!(cx, cmp::Ordering)), - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: true, - 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, ast::Ident::new(sym::cmp, span), vec![rgt]) -} - -pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { - let test_id = ast::Ident::new(sym::cmp, span); - let equals_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); - - let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]); - - // Builds: - // - // match ::std::cmp::Ord::cmp(&self_field1, &other_field1) { - // ::std::cmp::Ordering::Equal => - // match ::std::cmp::Ord::cmp(&self_field2, &other_field2) { - // ::std::cmp::Ordering::Equal => { - // ... - // } - // cmp => cmp - // }, - // cmp => cmp - // } - // - 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| { - // match new { - // ::std::cmp::Ordering::Equal => old, - // cmp => cmp - // } - - let new = { - let other_f = match other_fs { - [o_f] => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"), - }; - - 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 eq_arm = cx.arm(span, cx.pat_path(span, equals_path.clone()), old); - let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); - - cx.expr_match(span, new, vec![eq_arm, neq_arm]) - }, - 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 `derive(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 91c13b76a00..00000000000 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ /dev/null @@ -1,112 +0,0 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::{path_local, path_std}; - -use syntax::ast::{BinOpKind, Expr, MetaItem}; -use syntax::ptr::P; -use syntax::symbol::sym; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::Span; - -pub fn expand_deriving_partial_eq( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn 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_op( - cx: &mut ExtCtxt<'_>, - span: Span, - substr: &Substructure<'_>, - op: BinOpKind, - combiner: BinOpKind, - base: bool, - ) -> P<Expr> { - let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| { - let other_f = match other_fs { - [o_f] => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), - }; - - cx.expr_binary(span, op, self_f, other_f.clone()) - }; - - cs_fold1( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let eq = op(cx, span, self_f, other_fs); - cx.expr_binary(span, combiner, subexpr, eq) - }, - |cx, args| { - match args { - Some((span, self_f, other_fs)) => { - // Special-case the base case to generate cleaner code. - op(cx, span, self_f, other_fs) - } - None => cx.expr_bool(span, base), - } - }, - Box::new(|cx, span, _, _| cx.expr_bool(span, !base)), - cx, - span, - substr, - ) - } - - fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { - cs_op(cx, span, substr, BinOpKind::Eq, BinOpKind::And, true) - } - fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { - cs_op(cx, span, substr, BinOpKind::Ne, BinOpKind::Or, false) - } - - macro_rules! md { - ($name:expr, $f:ident) => {{ - let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; - MethodDef { - name: $name, - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(borrowed_self(), "other")], - ret_ty: Literal(path_local!(bool)), - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|a, b, c| $f(a, b, c))), - } - }}; - } - - super::inject_impl_of_structural_trait( - cx, - span, - item, - path_std!(cx, marker::StructuralPartialEq), - push, - ); - - // avoid defining `ne` if we can - // c-like enums, enums without any fields and structs without fields - // can safely define only `eq`. - let mut methods = vec![md!("eq", cs_eq)]; - if !is_type_without_fields(item) { - methods.push(md!("ne", cs_ne)); - } - - let trait_def = TraitDef { - span, - attributes: Vec::new(), - path: path_std!(cx, cmp::PartialEq), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: false, - methods, - 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 760ed325f36..00000000000 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ /dev/null @@ -1,302 +0,0 @@ -pub use OrderingOp::*; - -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::{path_local, path_std, pathvec_std}; - -use syntax::ast::{self, BinOpKind, Expr, MetaItem}; -use syntax::ptr::P; -use syntax::symbol::{sym, Symbol}; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::Span; - -pub fn expand_deriving_partial_ord( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), -) { - macro_rules! md { - ($name:expr, $op:expr, $equal:expr) => {{ - let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; - MethodDef { - name: $name, - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(borrowed_self(), "other")], - ret_ty: Literal(path_local!(bool)), - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_op($op, $equal, cx, span, substr) - })), - } - }}; - } - - let ordering_ty = Literal(path_std!(cx, cmp::Ordering)); - let ret_ty = Literal(Path::new_( - pathvec_std!(cx, option::Option), - None, - vec![Box::new(ordering_ty)], - PathKind::Std, - )); - - let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; - - let partial_cmp_def = MethodDef { - name: "partial_cmp", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(borrowed_self(), "other")], - ret_ty, - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr) - })), - }; - - // avoid defining extra methods if we can - // c-like enums, enums without any fields and structs without fields - // can safely define only `partial_cmp`. - let methods = if is_type_without_fields(item) { - vec![partial_cmp_def] - } else { - vec![ - partial_cmp_def, - md!("lt", true, false), - md!("le", true, true), - md!("gt", false, false), - md!("ge", false, true), - ] - }; - - let trait_def = TraitDef { - span, - attributes: vec![], - path: path_std!(cx, cmp::PartialOrd), - additional_bounds: vec![], - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: false, - methods, - 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, span), vec![rgt]) -} - -pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { - let test_id = ast::Ident::new(sym::cmp, span); - let ordering = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); - let ordering_expr = cx.expr_path(ordering.clone()); - let equals_expr = cx.expr_some(span, ordering_expr); - - let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]); - - // Builds: - // - // match ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1) { - // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => - // match ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2) { - // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => { - // ... - // } - // cmp => cmp - // }, - // cmp => cmp - // } - // - 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| { - // match new { - // Some(::std::cmp::Ordering::Equal) => old, - // cmp => cmp - // } - - let new = { - let other_f = match other_fs { - [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 eq_arm = cx.arm(span, cx.pat_some(span, cx.pat_path(span, ordering.clone())), old); - let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); - - cx.expr_match(span, new, vec![eq_arm, neq_arm]) - }, - equals_expr, - 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, - inclusive: bool, - cx: &mut ExtCtxt<'_>, - span: Span, - substr: &Substructure<'_>, -) -> P<Expr> { - let ordering_path = |cx: &mut ExtCtxt<'_>, name: &str| { - cx.expr_path( - cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, Symbol::intern(name)])), - ) - }; - - let par_cmp = |cx: &mut ExtCtxt<'_>, span, self_f: P<Expr>, other_fs: &[P<Expr>], default| { - let other_f = match other_fs { - [o_f] => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), - }; - - // `PartialOrd::partial_cmp(self.fi, other.fi)` - let cmp_path = cx.expr_path( - cx.path_global(span, cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp])), - ); - let cmp = cx.expr_call( - span, - cmp_path, - vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())], - ); - - let default = ordering_path(cx, default); - // `Option::unwrap_or(_, Ordering::Equal)` - let unwrap_path = cx.expr_path( - cx.path_global(span, cx.std_path(&[sym::option, sym::Option, sym::unwrap_or])), - ); - cx.expr_call(span, unwrap_path, vec![cmp, default]) - }; - - let fold = cs_fold1( - false, // need foldr - |cx, span, subexpr, self_f, other_fs| { - // build up a series of `partial_cmp`s from the inside - // out (hence foldr) to get lexical ordering, i.e., for op == - // `ast::lt` - // - // ``` - // Ordering::then_with( - // Option::unwrap_or( - // PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal) - // ), - // Option::unwrap_or( - // PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater) - // ) - // ) - // == Ordering::Less - // ``` - // - // and for op == - // `ast::le` - // - // ``` - // Ordering::then_with( - // Option::unwrap_or( - // PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal) - // ), - // Option::unwrap_or( - // PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater) - // ) - // ) - // != Ordering::Greater - // ``` - // - // 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. - - // `Option::unwrap_or(PartialOrd::partial_cmp(self.fi, other.fi), Ordering::Equal)` - let par_cmp = par_cmp(cx, span, self_f, other_fs, "Equal"); - - // `Ordering::then_with(Option::unwrap_or(..), ..)` - let then_with_path = cx.expr_path( - cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::then_with])), - ); - cx.expr_call(span, then_with_path, vec![par_cmp, cx.lambda0(span, subexpr)]) - }, - |cx, args| match args { - Some((span, self_f, other_fs)) => { - let opposite = if less { "Greater" } else { "Less" }; - par_cmp(cx, span, self_f, other_fs, opposite) - } - None => cx.expr_bool(span, inclusive), - }, - 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, inclusive) { - (false, false) => GtOp, - (false, true) => GeOp, - (true, false) => LtOp, - (true, true) => LeOp, - }; - some_ordering_collapsed(cx, span, op, tag_tuple) - } - }), - cx, - span, - substr, - ); - - match *substr.fields { - EnumMatching(.., ref all_fields) | Struct(.., ref all_fields) if !all_fields.is_empty() => { - let ordering = ordering_path(cx, if less ^ inclusive { "Less" } else { "Greater" }); - let comp_op = if inclusive { BinOpKind::Ne } else { BinOpKind::Eq }; - - cx.expr_binary(span, comp_op, fold, ordering) - } - _ => fold, - } -} diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs deleted file mode 100644 index c145b63274e..00000000000 --- a/src/libsyntax_ext/deriving/debug.rs +++ /dev/null @@ -1,137 +0,0 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::path_std; - -use syntax::ast::{self, Ident}; -use syntax::ast::{Expr, MetaItem}; -use syntax::ptr::P; -use syntax::symbol::sym; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::{Span, DUMMY_SP}; - -pub fn expand_deriving_debug( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), -) { - // &mut ::std::fmt::Formatter - let fmtr = - Ptr(Box::new(Literal(path_std!(cx, fmt::Formatter))), Borrowed(None, ast::Mutability::Mut)); - - let trait_def = TraitDef { - span, - attributes: Vec::new(), - path: path_std!(cx, fmt::Debug), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: false, - methods: vec![MethodDef { - name: "fmt", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(fmtr, "f")], - ret_ty: Literal(path_std!(cx, fmt::Result)), - attributes: Vec::new(), - is_unsafe: false, - unify_fieldless_variants: 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, vdata, fields) = match substr.fields { - Struct(vdata, fields) => (substr.type_ident, *vdata, fields), - EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields), - EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { - cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") - } - }; - - // We want to make sure we have the ctxt set so that we can use unstable methods - let span = cx.with_def_site_ctxt(span); - let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); - let builder = cx.ident_of("debug_trait_builder", span); - let builder_expr = cx.expr_ident(span, builder.clone()); - - let fmt = substr.nonself_args[0].clone(); - - let mut stmts = vec![]; - match vdata { - ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => { - // tuple struct/"normal" variant - let expr = cx.expr_method_call(span, fmt, cx.ident_of("debug_tuple", span), 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(), - Ident::new(sym::field, span), - vec![field], - ); - - // Use `let _ = expr;` to avoid triggering the - // unused_results lint. - stmts.push(stmt_let_undescore(cx, span, expr)); - } - } - ast::VariantData::Struct(..) => { - // normal struct/struct variant - let expr = - cx.expr_method_call(span, fmt, cx.ident_of("debug_struct", span), vec![name]); - stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); - - for field in fields { - let name = cx.expr_lit( - field.span, - ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked), - ); - - // 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(), - Ident::new(sym::field, span), - vec![name, field], - ); - stmts.push(stmt_let_undescore(cx, span, expr)); - } - } - } - - let expr = cx.expr_method_call(span, builder_expr, cx.ident_of("finish", span), vec![]); - - stmts.push(cx.stmt_expr(expr)); - let block = cx.block(span, stmts); - cx.expr_block(block) -} - -fn stmt_let_undescore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> 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: ast::AttrVec::new(), - }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } -} diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs deleted file mode 100644 index 7f21440d49a..00000000000 --- a/src/libsyntax_ext/deriving/decodable.rs +++ /dev/null @@ -1,225 +0,0 @@ -//! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more. - -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::pathvec_std; - -use syntax::ast; -use syntax::ast::{Expr, MetaItem, Mutability}; -use syntax::ptr::P; -use syntax::symbol::Symbol; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::Span; - -pub fn expand_deriving_rustc_decodable( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), -) { - let krate = "rustc_serialize"; - let typaram = "__D"; - - let trait_def = TraitDef { - span, - attributes: Vec::new(), - path: Path::new_(vec![krate, "Decodable"], None, vec![], PathKind::Global), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: false, - methods: vec![MethodDef { - name: "decode", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec![( - typaram, - vec![Path::new_(vec![krate, "Decoder"], None, vec![], PathKind::Global)], - )], - }, - explicit_self: None, - args: vec![( - Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)), - "d", - )], - ret_ty: Literal(Path::new_( - pathvec_std!(cx, result::Result), - None, - vec![ - Box::new(Self_), - Box::new(Literal(Path::new_( - vec![typaram, "Error"], - None, - vec![], - PathKind::Local, - ))), - ], - PathKind::Std, - )), - attributes: Vec::new(), - is_unsafe: false, - unify_fieldless_variants: 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, trait_span), - cx.ident_of("Decodable", trait_span), - cx.ident_of("decode", trait_span), - ]; - 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", trait_span); - 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", trait_span); - - 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", trait_span), - vec![ - cx.expr_str(trait_span, substr.type_ident.name), - cx.expr_usize(trait_span, nfields), - cx.lambda1(trait_span, result, blkarg), - ], - ) - } - StaticEnum(_, ref fields) => { - let variant = cx.ident_of("i", trait_span); - - let mut arms = Vec::with_capacity(fields.len() + 1); - let mut variants = Vec::with_capacity(fields.len()); - let rvariant_arg = cx.ident_of("read_enum_variant_arg", trait_span); - - for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() { - variants.push(cx.expr_str(v_span, ident.name)); - - 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, 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(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", trait_span), - vec![variant_vec, lambda], - ); - cx.expr_method_call( - trait_span, - decoder, - cx.ident_of("read_enum", trait_span), - vec![ - cx.expr_str(trait_span, substr.type_ident.name), - cx.lambda1(trait_span, result, blkarg), - ], - ) - } - _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"), - }; -} - -/// Creates 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, Symbol, usize) -> P<Expr>, -{ - match *fields { - Unnamed(ref fields, is_tuple) => { - let path_expr = cx.expr_path(outer_pat_path); - if !is_tuple { - path_expr - } else { - let fields = fields - .iter() - .enumerate() - .map(|(i, &span)| getarg(cx, span, Symbol::intern(&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, 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 d623e1fa4cc..00000000000 --- a/src/libsyntax_ext/deriving/default.rs +++ /dev/null @@ -1,83 +0,0 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::path_std; - -use syntax::ast::{Expr, MetaItem}; -use syntax::ptr::P; -use syntax::span_err; -use syntax::symbol::{kw, sym}; -use syntax_expand::base::{Annotatable, DummyResult, ExtCtxt}; -use syntax_pos::Span; - -use rustc_error_codes::*; - -pub fn expand_deriving_default( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), -) { - let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; - let trait_def = TraitDef { - span, - attributes: Vec::new(), - path: path_std!(cx, default::Default), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: false, - methods: vec![MethodDef { - name: "default", - generics: LifetimeBounds::empty(), - explicit_self: None, - args: Vec::new(), - ret_ty: Self_, - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: 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> { - // Note that `kw::Default` is "default" and `sym::Default` is "Default"! - let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::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, is_tuple) => { - if !is_tuple { - 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(..) => { - span_err!(cx, trait_span, E0665, "`Default` cannot be derived for enums, only structs"); - // let compilation continue - DummyResult::raw_expr(trait_span, true) - } - _ => cx.span_bug(trait_span, "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 98b0160d6e8..00000000000 --- a/src/libsyntax_ext/deriving/encodable.rs +++ /dev/null @@ -1,287 +0,0 @@ -//! The compiler code necessary to implement the `#[derive(RustcEncodable)]` -//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that -//! type-defining items may be tagged with -//! `#[derive(RustcEncodable, RustcDecodable)]`. -//! -//! For example, a type like: -//! -//! ``` -//! #[derive(RustcEncodable, RustcDecodable)] -//! struct Node { id: usize } -//! ``` -//! -//! would generate two implementations like: -//! -//! ``` -//! # struct Node { id: usize } -//! 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: -//! -//! ``` -//! # #[derive(RustcEncodable, RustcDecodable)] -//! # struct Span; -//! #[derive(RustcEncodable, RustcDecodable)] -//! struct Spanned<T> { node: T, span: Span } -//! ``` -//! -//! would yield functions like: -//! -//! ``` -//! # #[derive(RustcEncodable, RustcDecodable)] -//! # struct Span; -//! # struct Spanned<T> { node: T, span: Span } -//! 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 crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::pathvec_std; - -use syntax::ast::{Expr, ExprKind, MetaItem, Mutability}; -use syntax::ptr::P; -use syntax::symbol::Symbol; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::Span; - -pub fn expand_deriving_rustc_encodable( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), -) { - let krate = "rustc_serialize"; - let typaram = "__S"; - - let trait_def = TraitDef { - span, - attributes: Vec::new(), - path: Path::new_(vec![krate, "Encodable"], None, vec![], PathKind::Global), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: false, - methods: vec![MethodDef { - name: "encode", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec![( - typaram, - vec![Path::new_(vec![krate, "Encoder"], None, vec![], PathKind::Global)], - )], - }, - explicit_self: borrowed_explicit_self(), - args: vec![( - Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)), - "s", - )], - ret_ty: Literal(Path::new_( - pathvec_std!(cx, result::Result), - None, - vec![ - Box::new(Tuple(Vec::new())), - Box::new(Literal(Path::new_( - vec![typaram, "Error"], - None, - vec![], - PathKind::Local, - ))), - ], - PathKind::Std, - )), - attributes: Vec::new(), - is_unsafe: false, - unify_fieldless_variants: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - encodable_substructure(a, b, c, krate) - })), - }], - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn encodable_substructure( - cx: &mut ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, - krate: &'static str, -) -> 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", trait_span); - let blkencoder = cx.expr_ident(trait_span, blkarg); - let fn_path = cx.expr_path(cx.path_global( - trait_span, - vec![ - cx.ident_of(krate, trait_span), - cx.ident_of("Encodable", trait_span), - cx.ident_of("encode", trait_span), - ], - )); - - return match *substr.fields { - Struct(_, ref fields) => { - let emit_struct_field = cx.ident_of("emit_struct_field", trait_span); - let mut stmts = Vec::new(); - for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() { - let name = match name { - Some(id) => id.name, - None => Symbol::intern(&format!("_field{}", i)), - }; - let self_ref = cx.expr_addr_of(span, self_.clone()); - let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda1(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, ExprKind::Ret(Some(call))) - }; - - let stmt = cx.stmt_expr(call); - stmts.push(stmt); - } - - // unit structs have no fields and need to return Ok() - let blk = if stmts.is_empty() { - let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, vec![])); - cx.lambda1(trait_span, ok, blkarg) - } else { - cx.lambda_stmts_1(trait_span, stmts, blkarg) - }; - - cx.expr_method_call( - trait_span, - encoder, - cx.ident_of("emit_struct", trait_span), - vec![ - cx.expr_str(trait_span, substr.type_ident.name), - 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", trait_span); - 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 self_ref = cx.expr_addr_of(span, self_.clone()); - let enc = - cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda1(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, ExprKind::Ret(Some(call))) - }; - stmts.push(cx.stmt_expr(call)); - } - } else { - let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, vec![])); - let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok))); - 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.ident.name); - let call = cx.expr_method_call( - trait_span, - blkencoder, - cx.ident_of("emit_enum_variant", trait_span), - vec![ - name, - cx.expr_usize(trait_span, idx), - cx.expr_usize(trait_span, fields.len()), - blk, - ], - ); - let blk = cx.lambda1(trait_span, call, blkarg); - let ret = cx.expr_method_call( - trait_span, - encoder, - cx.ident_of("emit_enum", trait_span), - vec![cx.expr_str(trait_span, substr.type_ident.name), blk], - ); - cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(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 7d7b73ebb42..00000000000 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ /dev/null @@ -1,1812 +0,0 @@ -//! 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 implementors 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 summarized, 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 StaticFields::*; -pub use SubstructureFields::*; - -use std::cell::RefCell; -use std::iter; -use std::vec; - -use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind}; -use syntax::ast::{GenericArg, GenericParamKind, VariantData}; -use syntax::attr; -use syntax::ptr::P; -use syntax::sess::ParseSess; -use syntax::source_map::respan; -use syntax::symbol::{kw, sym, Symbol}; -use syntax::util::map_in_place::MapInPlace; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::Span; - -use ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty}; - -use crate::deriving; - -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, - - /// Can this trait be derived for unions? - pub supports_unions: 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>>, - - /// Arguments other than the self argument - pub args: Vec<(Ty<'a>, &'a str)>, - - /// Returns type - pub ret_ty: Ty<'a>, - - pub attributes: Vec<ast::Attribute>, - - // Is it an `unsafe fn`? - pub is_unsafe: bool, - - /// Can we combine fieldless variants for enums into a single match arm? - pub unify_fieldless_variants: 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 and unit structs/enum variants like this. - Unnamed(Vec<Span>, bool /*is tuple*/), - /// Normal structs/struct variants. - Named(Vec<(Ident, Span)>), -} - -/// A summary of the possible sets of fields. -pub enum SubstructureFields<'a> { - Struct(&'a ast::VariantData, Vec<FieldInfo<'a>>), - /// Matching variants of the enum: variant index, variant count, ast::Variant, - /// fields: the field name is only non-`None` in the case of a struct - /// variant. - EnumMatching(usize, 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 [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<dyn 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<dyn FnMut(&mut ExtCtxt<'_>, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>; - -pub fn combine_substructure( - f: CombineSubstructureFunc<'_>, -) -> RefCell<CombineSubstructureFunc<'_>> { - 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], - cx: &ExtCtxt<'_>, -) -> Vec<P<ast::Ty>> { - use syntax::visit; - - struct Visitor<'a, 'b> { - cx: &'a ExtCtxt<'b>, - ty_param_names: &'a [ast::Name], - types: Vec<P<ast::Ty>>, - } - - impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { - fn visit_ty(&mut self, ty: &'a ast::Ty) { - if let ast::TyKind::Path(_, ref path) = ty.kind { - if let Some(segment) = path.segments.first() { - if self.ty_param_names.contains(&segment.ident.name) { - self.types.push(P(ty.clone())); - } - } - } - - visit::walk_ty(self, ty) - } - - fn visit_mac(&mut self, mac: &ast::Mac) { - self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros"); - } - } - - let mut visitor = Visitor { cx, 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 dyn FnMut(Annotatable), - ) { - self.expand_ext(cx, mitem, item, push, false); - } - - pub fn expand_ext( - self, - cx: &mut ExtCtxt<'_>, - mitem: &ast::MetaItem, - item: &'a Annotatable, - push: &mut dyn FnMut(Annotatable), - from_scratch: bool, - ) { - match *item { - Annotatable::Item(ref item) => { - let is_packed = item.attrs.iter().any(|attr| { - for r in attr::find_repr_attrs(&cx.parse_sess, attr) { - if let attr::ReprPacked(_) = r { - return true; - } - } - false - }); - let has_no_type_params = match item.kind { - ast::ItemKind::Struct(_, ref generics) - | ast::ItemKind::Enum(_, ref generics) - | ast::ItemKind::Union(_, ref generics) => { - !generics.params.iter().any(|param| match param.kind { - ast::GenericParamKind::Type { .. } => true, - _ => false, - }) - } - _ => { - // Non-ADT derive is an error, but it should have been - // set earlier; see - // libsyntax_expand/expand.rs:MacroExpander::fully_expand_fragment() - // libsyntax_expand/base.rs:Annotatable::derive_allowed() - return; - } - }; - let container_id = cx.current_expansion.id.expn_data().parent; - let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id); - let use_temporaries = is_packed && always_copy; - - let newitem = match item.kind { - ast::ItemKind::Struct(ref struct_def, ref generics) => self.expand_struct_def( - cx, - &struct_def, - item.ident, - generics, - from_scratch, - use_temporaries, - ), - ast::ItemKind::Enum(ref enum_def, ref generics) => { - // We ignore `use_temporaries` here, because - // `repr(packed)` enums cause an error later on. - // - // This can only cause further compilation errors - // downstream in blatantly illegal code, so it - // is fine. - self.expand_enum_def( - cx, - enum_def, - &item.attrs, - item.ident, - generics, - from_scratch, - ) - } - ast::ItemKind::Union(ref struct_def, ref generics) => { - if self.supports_unions { - self.expand_struct_def( - cx, - &struct_def, - item.ident, - generics, - from_scratch, - use_temporaries, - ) - } else { - cx.span_err(mitem.span, "this trait cannot be derived for unions"); - return; - } - } - _ => unreachable!(), - }; - // 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| { - [ - sym::allow, - sym::warn, - sym::deny, - sym::forbid, - sym::stable, - sym::unstable, - ] - .contains(&a.name_or_empty()) - }) - .cloned(), - ); - push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))) - } - _ => { - // Non-Item derive is an error, but it should have been - // set earlier; see - // libsyntax_expand/expand.rs:MacroExpander::fully_expand_fragment() - // libsyntax_expand/base.rs:Annotatable::derive_allowed() - return; - } - } - } - - /// Given that we are deriving a trait `DerivedTrait` for a type like: - /// - /// ```ignore (only-for-syntax-highlight) - /// 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 (only-for-syntax-highlight) - /// 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<ast::AssocItem>, - ) -> 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::AssocItem` - let associated_types = - self.associated_types.iter().map(|&(ident, ref type_def)| ast::AssocItem { - id: ast::DUMMY_NODE_ID, - span: self.span, - ident, - vis: respan(self.span.shrink_to_lo(), ast::VisibilityKind::Inherited), - defaultness: ast::Defaultness::Final, - attrs: Vec::new(), - generics: Generics::default(), - kind: ast::AssocItemKind::TyAlias( - Vec::new(), - Some(type_def.to_ty(cx, self.span, type_ident, generics)), - ), - tokens: None, - }); - - let Generics { mut params, mut where_clause, span } = - self.generics.to_generics(cx, self.span, type_ident, generics); - - // Create the generic parameters - params.extend(generics.params.iter().map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => param.clone(), - GenericParamKind::Type { .. } => { - // I don't think this can be moved out of the loop, since - // a GenericBound requires an ast id - let bounds: Vec<_> = - // extra restrictions on the generics parameters to the - // type being derived upon - self.additional_bounds.iter().map(|p| { - cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)) - }).chain( - // require the current trait - iter::once(cx.trait_bound(trait_path.clone())) - ).chain( - // also add in any bounds from the declaration - param.bounds.iter().cloned() - ).collect(); - - cx.typaram(self.span, param.ident, vec![], bounds, None) - } - GenericParamKind::Const { .. } => param.clone(), - })); - - // 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_generic_params: wb.bound_generic_params.clone(), - bounded_ty: wb.bounded_ty.clone(), - bounds: 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, - lhs_ty: we.lhs_ty.clone(), - rhs_ty: we.rhs_ty.clone(), - }) - } - } - })); - - { - // Extra scope required here so ty_params goes out of scope before params is moved - - let mut ty_params = params - .iter() - .filter_map(|param| match param.kind { - ast::GenericParamKind::Type { .. } => Some(param), - _ => None, - }) - .peekable(); - - if ty_params.peek().is_some() { - let ty_param_names: Vec<ast::Name> = - ty_params.map(|ty_param| ty_param.ident.name).collect(); - - for field_ty in field_tys { - let tys = find_type_parameters(&field_ty, &ty_param_names, cx); - - for ty in tys { - // if we have already handled this type, skip it - if let ast::TyKind::Path(_, ref p) = ty.kind { - if p.segments.len() == 1 - && ty_param_names.contains(&p.segments[0].ident.name) - { - continue; - }; - } - let mut bounds: Vec<_> = self - .additional_bounds - .iter() - .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) - .collect(); - - // require the current trait - bounds.push(cx.trait_bound(trait_path.clone())); - - let predicate = ast::WhereBoundPredicate { - span: self.span, - bound_generic_params: Vec::new(), - bounded_ty: ty, - bounds, - }; - - let predicate = ast::WherePredicate::BoundPredicate(predicate); - where_clause.predicates.push(predicate); - } - } - } - } - - let trait_generics = Generics { params, where_clause, span }; - - // Create the reference to the trait. - let trait_ref = cx.trait_ref(trait_path); - - let self_params: Vec<_> = generics - .params - .iter() - .map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - GenericArg::Lifetime(cx.lifetime(self.span, param.ident)) - } - GenericParamKind::Type { .. } => { - GenericArg::Type(cx.ty_ident(self.span, param.ident)) - } - GenericParamKind::Const { .. } => { - GenericArg::Const(cx.const_ident(self.span, param.ident)) - } - }) - .collect(); - - // Create the type of `self`. - let path = cx.path_all(self.span, false, vec![type_ident], self_params); - let self_type = cx.ty_path(path); - - let attr = cx.attribute(cx.meta_word(self.span, sym::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 unused_qual = { - let word = syntax::attr::mk_nested_word_item(Ident::new( - Symbol::intern("unused_qualifications"), - self.span, - )); - let list = syntax::attr::mk_list_item(Ident::new(sym::allow, self.span), vec![word]); - cx.attribute(list) - }; - - 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::invalid(), - a, - ast::ItemKind::Impl( - unsafety, - ast::ImplPolarity::Positive, - ast::Defaultness::Final, - 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, - from_scratch: bool, - use_temporaries: bool, - ) -> P<ast::Item> { - let field_tys: Vec<P<ast::Ty>> = - struct_def.fields().iter().map(|field| field.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 from_scratch || 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[..], - use_temporaries, - ) - }; - - method_def.create_method(cx, self, type_ident, generics, 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, - from_scratch: bool, - ) -> P<ast::Item> { - let mut field_tys = Vec::new(); - - for variant in &enum_def.variants { - field_tys.extend(variant.data.fields().iter().map(|field| field.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 from_scratch || 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, explicit_self, tys, body) - }) - .collect(); - - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) - } -} - -fn find_repr_type_name(sess: &ParseSess, type_attrs: &[ast::Attribute]) -> &'static str { - let mut repr_type_name = "isize"; - for a in type_attrs { - for r in &attr::find_repr_attrs(sess, a) { - repr_type_name = match *r { - attr::ReprPacked(_) - | attr::ReprSimd - | attr::ReprAlign(_) - | attr::ReprTransparent => continue, - - attr::ReprC => "i32", - - attr::ReprInt(attr::SignedInt(ast::IntTy::Isize)) => "isize", - attr::ReprInt(attr::SignedInt(ast::IntTy::I8)) => "i8", - attr::ReprInt(attr::SignedInt(ast::IntTy::I16)) => "i16", - attr::ReprInt(attr::SignedInt(ast::IntTy::I32)) => "i32", - attr::ReprInt(attr::SignedInt(ast::IntTy::I64)) => "i64", - attr::ReprInt(attr::SignedInt(ast::IntTy::I128)) => "i128", - - attr::ReprInt(attr::UnsignedInt(ast::UintTy::Usize)) => "usize", - attr::ReprInt(attr::UnsignedInt(ast::UintTy::U8)) => "u8", - attr::ReprInt(attr::UnsignedInt(ast::UintTy::U16)) => "u16", - attr::ReprInt(attr::UnsignedInt(ast::UintTy::U32)) => "u32", - attr::ReprInt(attr::UnsignedInt(ast::UintTy::U64)) => "u64", - attr::ReprInt(attr::UnsignedInt(ast::UintTy::U128)) => "u128", - } - } - } - 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, - method_ident: cx.ident_of(self.name, trait_.span), - self_args, - nonself_args, - 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, - ) -> (Option<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 = self.explicit_self.as_ref().map(|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 - }); - - for (ty, name) in self.args.iter() { - let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics); - let ident = cx.ident_of(name, trait_.span); - 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 (if let Self_ = **ty { true } else { false }) && 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, - explicit_self: Option<ast::ExplicitSelf>, - arg_types: Vec<(Ident, P<ast::Ty>)>, - body: P<Expr>, - ) -> ast::AssocItem { - // Create the generics that aren't for `Self`. - let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); - - let args = { - let self_args = explicit_self.map(|explicit_self| { - let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(trait_.span); - ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident) - }); - let nonself_args = - arg_types.into_iter().map(|(name, ty)| cx.param(trait_.span, name, ty)); - self_args.into_iter().chain(nonself_args).collect() - }; - - let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); - - let method_ident = cx.ident_of(self.name, trait_.span); - let fn_decl = cx.fn_decl(args, ast::FunctionRetTy::Ty(ret_type)); - let body_block = cx.block_expr(body); - - let unsafety = if self.is_unsafe { ast::Unsafety::Unsafe } else { ast::Unsafety::Normal }; - - let trait_lo_sp = trait_.span.shrink_to_lo(); - - let sig = ast::FnSig { - header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() }, - decl: fn_decl, - }; - - // Create the method. - ast::AssocItem { - id: ast::DUMMY_NODE_ID, - attrs: self.attributes.clone(), - generics: fn_generics, - span: trait_.span, - vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited), - defaultness: ast::Defaultness::Final, - ident: method_ident, - kind: ast::AssocItemKind::Fn(sig, Some(body_block)), - tokens: None, - } - } - - /// ``` - /// #[derive(PartialEq)] - /// # struct Dummy; - /// struct A { x: i32, y: i32 } - /// - /// // equivalent to: - /// impl PartialEq for A { - /// fn eq(&self, other: &A) -> bool { - /// match *self { - /// A {x: ref __self_0_0, y: ref __self_0_1} => { - /// match *other { - /// 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) - /// } - /// } - /// } - /// } - /// } - /// } - /// - /// // or if A is repr(packed) - note fields are matched by-value - /// // instead of by-reference. - /// impl PartialEq for A { - /// fn eq(&self, other: &A) -> bool { - /// match *self { - /// A {x: __self_0_0, y: __self_0_1} => { - /// match other { - /// A {x: __self_1_0, y: __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>], - use_temporaries: bool, - ) -> 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(trait_.span, vec![type_ident]); - let (pat, ident_expr) = trait_.create_struct_pattern( - cx, - struct_path, - struct_def, - &format!("__self_{}", i), - ast::Mutability::Not, - use_temporaries, - ); - 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, - name: opt_id, - self_: field, - other: other_fields - .iter_mut() - .map(|l| match l.next().unwrap() { - (.., ex, _) => ex, - }) - .collect(), - attrs, - }) - .collect() - } else { - cx.span_bug(trait_.span, "no `self` parameter for 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(struct_def, 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, 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), - ) - } - - /// ``` - /// #[derive(PartialEq)] - /// # struct Dummy; - /// enum A { - /// A1, - /// A2(i32) - /// } - /// - /// // is equivalent to - /// - /// impl PartialEq for A { - /// fn eq(&self, other: &A) -> ::bool { - /// match (&*self, &*other) { - /// (&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 *other { 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, - mut self_args: Vec<P<Expr>>, - nonself_args: &[P<Expr>], - ) -> P<Expr> { - let sp = trait_.span; - let variants = &enum_def.variants; - - let self_arg_names = iter::once("__self".to_string()) - .chain( - self_args - .iter() - .enumerate() - .skip(1) - .map(|(arg_count, _self_arg)| format!("__arg_{}", arg_count)), - ) - .collect::<Vec<String>>(); - - let self_arg_idents = - self_arg_names.iter().map(|name| cx.ident_of(name, sp)).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 = self_arg_names - .iter() - .map(|name| { - let vi_suffix = format!("{}_vi", &name[..]); - cx.ident_of(&vi_suffix[..], trait_.span) - }) - .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[..]); - - let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty()); - - // 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() - .filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty())) - .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::Mutability::Not, - ); - (cx.pat(sp, PatKind::Ref(p, ast::Mutability::Not)), 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, - } - }) - .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, variants.len(), variant, field_tuples); - let arm_expr = self.call_substructure_method( - cx, - trait_, - type_ident, - &self_args[..], - nonself_args, - &substructure, - ); - - cx.arm(sp, single_pat, arm_expr) - }) - .collect(); - - let default = match first_fieldless { - Some(v) if self.unify_fieldless_variants => { - // We need a default case that handles the fieldless variants. - // The index and actual variant aren't meaningful in this case, - // so just use whatever - let substructure = EnumMatching(0, variants.len(), v, Vec::new()); - Some(self.call_substructure_method( - cx, - trait_, - type_ident, - &self_args[..], - nonself_args, - &substructure, - )) - } - _ if variants.len() > 1 && self_args.len() > 1 => { - // 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 - Some(deriving::call_intrinsic(cx, sp, "unreachable", vec![])) - } - _ => None, - }; - if let Some(arm) = default { - match_arms.push(cx.arm(sp, cx.pat_wild(sp), arm)); - } - - // 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<ast::Stmt> = Vec::with_capacity(vi_idents.len() + 1); - - // 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, type_attrs); - - let mut first_ident = None; - for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { - let self_addr = cx.expr_addr_of(sp, self_arg.clone()); - let variant_value = - deriving::call_intrinsic(cx, sp, "discriminant_value", vec![self_addr]); - - let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name, sp)); - 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, BinOpKind::Eq, first_expr, id); - discriminant_test = - cx.expr_binary(sp, BinOpKind::And, 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, - ); - - // Final wrinkle: the self_args are expressions that deref - // down to desired places, 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, ...)`. - self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg)); - let match_arg = cx.expr(sp, ast::ExprKind::Tup(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)); - index_let_stmts.push(cx.stmt_expr(arm_expr)); - cx.expr_block(cx.block(sp, index_let_stmts)) - } 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.) - - deriving::call_intrinsic(cx, sp, "unreachable", vec![]) - } else { - // Final wrinkle: the self_args are expressions that deref - // down to desired places, 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, ...)`. - self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg)); - let match_arg = cx.expr(sp, ast::ExprKind::Tup(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 sp = v.span.with_ctxt(trait_.span.ctxt()); - let summary = trait_.summarise_struct(cx, &v.data); - (v.ident, sp, summary) - }) - .collect(); - self.call_substructure_method( - cx, - trait_, - type_ident, - self_args, - nonself_args, - &StaticEnum(enum_def, summary), - ) - } -} - -// general helper methods. -impl<'a> TraitDef<'a> { - 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 = field.span.with_ctxt(self.span.ctxt()); - match field.ident { - Some(ident) => named_idents.push((ident, sp)), - _ => just_spans.push(sp), - } - } - - let is_tuple = if let ast::VariantData::Tuple(..) = struct_def { true } else { false }; - 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), - // unnamed fields - (false, _) => Unnamed(just_spans, is_tuple), - // empty - _ => Named(Vec::new()), - } - } - - fn create_subpatterns( - &self, - cx: &mut ExtCtxt<'_>, - field_paths: Vec<ast::Ident>, - mutbl: ast::Mutability, - use_temporaries: bool, - ) -> Vec<P<ast::Pat>> { - field_paths - .iter() - .map(|path| { - let binding_mode = if use_temporaries { - ast::BindingMode::ByValue(ast::Mutability::Not) - } else { - ast::BindingMode::ByRef(mutbl) - }; - cx.pat(path.span, PatKind::Ident(binding_mode, (*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, - use_temporaries: bool, - ) -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) { - let mut paths = Vec::new(); - let mut ident_exprs = Vec::new(); - for (i, struct_field) in struct_def.fields().iter().enumerate() { - let sp = struct_field.span.with_ctxt(self.span.ctxt()); - let ident = cx.ident_of(&format!("{}_{}", prefix, i), self.span); - paths.push(ident.with_span_pos(sp)); - let val = cx.expr_path(cx.path_ident(sp, ident)); - let val = if use_temporaries { val } else { cx.expr_deref(sp, val) }; - let val = cx.expr(sp, ast::ExprKind::Paren(val)); - - ident_exprs.push((sp, struct_field.ident, val, &struct_field.attrs[..])); - } - - let subpats = self.create_subpatterns(cx, paths, mutbl, use_temporaries); - let pattern = match *struct_def { - VariantData::Struct(..) => { - let field_pats = subpats - .into_iter() - .zip(&ident_exprs) - .map(|(pat, &(sp, ident, ..))| { - if ident.is_none() { - cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); - } - ast::FieldPat { - ident: ident.unwrap(), - is_shorthand: false, - attrs: ast::AttrVec::new(), - id: ast::DUMMY_NODE_ID, - span: pat.span.with_ctxt(self.span.ctxt()), - pat, - is_placeholder: false, - } - }) - .collect(); - cx.pat_struct(self.span, struct_path, field_pats) - } - VariantData::Tuple(..) => cx.pat_tuple_struct(self.span, struct_path, subpats), - VariantData::Unit(..) => cx.pat_path(self.span, struct_path), - }; - - (pattern, ident_exprs) - } - - 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 sp = variant.span.with_ctxt(self.span.ctxt()); - let variant_path = cx.path(sp, vec![enum_ident, variant.ident]); - let use_temporaries = false; // enums can't be repr(packed) - self.create_struct_pattern(cx, variant_path, &variant.data, prefix, mutbl, use_temporaries) - } -} - -// helpful premade recipes - -pub fn cs_fold_fields<'a, F>( - use_foldl: bool, - mut f: F, - base: P<Expr>, - cx: &mut ExtCtxt<'_>, - all_fields: &[FieldInfo<'a>], -) -> P<Expr> -where - F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>, -{ - 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)) - } -} - -pub fn cs_fold_enumnonmatch( - mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>, - cx: &mut ExtCtxt<'_>, - trait_span: Span, - substructure: &Substructure<'_>, -) -> P<Expr> { - match *substructure.fields { - EnumNonMatchingCollapsed(ref all_args, _, tuple) => { - enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple), substructure.nonself_args) - } - _ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed"), - } -} - -pub fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> { - cx.span_bug(trait_span, "static function in `derive`") -} - -/// 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, - 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>]) -> P<Expr>, -{ - match *substructure.fields { - EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => { - cs_fold_fields(use_foldl, f, base, cx, all_fields) - } - EnumNonMatchingCollapsed(..) => { - cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure) - } - StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span), - } -} - -/// Function to fold over fields, with three cases, to generate more efficient and concise code. -/// When the `substructure` has grouped fields, there are two cases: -/// Zero fields: call the base case function with `None` (like the usual base case of `cs_fold`). -/// One or more fields: call the base case function on the first value (which depends on -/// `use_fold`), and use that as the base case. Then perform `cs_fold` on the remainder of the -/// fields. -/// When the `substructure` is a `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f` -/// is returned. Statics may not be folded over. -/// See `cs_op` in `partial_ord.rs` for a model example. -pub fn cs_fold1<F, B>( - use_foldl: bool, - f: F, - mut b: B, - 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>, - B: FnMut(&mut ExtCtxt<'_>, Option<(Span, P<Expr>, &[P<Expr>])>) -> P<Expr>, -{ - match *substructure.fields { - EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => { - let (base, all_fields) = match (all_fields.is_empty(), use_foldl) { - (false, true) => { - let field = &all_fields[0]; - let args = (field.span, field.self_.clone(), &field.other[..]); - (b(cx, Some(args)), &all_fields[1..]) - } - (false, false) => { - let idx = all_fields.len() - 1; - let field = &all_fields[idx]; - let args = (field.span, field.self_.clone(), &field.other[..]); - (b(cx, Some(args)), &all_fields[..idx]) - } - (true, _) => (b(cx, None), &all_fields[..]), - }; - - cs_fold_fields(use_foldl, f, base, cx, all_fields) - } - EnumNonMatchingCollapsed(..) => { - cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure) - } - StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span), - } -} - -/// Returns `true` if the type has no value fields -/// (for an enum, no variant has any fields) -pub fn is_type_without_fields(item: &Annotatable) -> bool { - if let Annotatable::Item(ref item) = *item { - match item.kind { - ast::ItemKind::Enum(ref enum_def, _) => { - enum_def.variants.iter().all(|v| v.data.fields().is_empty()) - } - ast::ItemKind::Struct(ref variant_data, _) => variant_data.fields().is_empty(), - _ => false, - } - } else { - false - } -} diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs deleted file mode 100644 index 7eab15aff77..00000000000 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ /dev/null @@ -1,283 +0,0 @@ -//! 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 PtrTy::*; -pub use Ty::*; - -use syntax::ast::{self, Expr, GenericArg, GenericParamKind, Generics, Ident, SelfKind}; -use syntax::ptr::P; -use syntax::source_map::{respan, DUMMY_SP}; -use syntax_expand::base::ExtCtxt; -use syntax_pos::symbol::kw; -use syntax_pos::Span; - -/// The types of pointers -#[derive(Clone)] -pub enum PtrTy { - /// &'lifetime mut - Borrowed(Option<Ident>, ast::Mutability), - /// *mut - #[allow(dead_code)] - Raw(ast::Mutability), -} - -/// A path, e.g., `::std::option::Option::<i32>` (global). Has support -/// for type parameters and a lifetime. -#[derive(Clone)] -pub struct Path<'a> { - path: Vec<&'a str>, - lifetime: Option<Ident>, - params: Vec<Box<Ty<'a>>>, - kind: PathKind, -} - -#[derive(Clone)] -pub enum PathKind { - Local, - Global, - Std, -} - -impl<'a> Path<'a> { - pub fn new(path: Vec<&str>) -> Path<'_> { - Path::new_(path, None, Vec::new(), PathKind::Std) - } - pub fn new_local(path: &str) -> Path<'_> { - Path::new_(vec![path], None, Vec::new(), PathKind::Local) - } - pub fn new_<'r>( - path: Vec<&'r str>, - lifetime: Option<Ident>, - params: Vec<Box<Ty<'r>>>, - kind: PathKind, - ) -> Path<'r> { - Path { path, lifetime, params, kind } - } - - pub fn to_ty( - &self, - cx: &ExtCtxt<'_>, - span: Span, - self_ty: Ident, - self_generics: &Generics, - ) -> P<ast::Ty> { - cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) - } - pub fn to_path( - &self, - cx: &ExtCtxt<'_>, - span: Span, - self_ty: Ident, - self_generics: &Generics, - ) -> ast::Path { - let mut idents = self.path.iter().map(|s| cx.ident_of(*s, span)).collect(); - let lt = mk_lifetimes(cx, span, &self.lifetime); - let tys: Vec<P<ast::Ty>> = - self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); - let params = lt - .into_iter() - .map(|lt| GenericArg::Lifetime(lt)) - .chain(tys.into_iter().map(|ty| GenericArg::Type(ty))) - .collect(); - - match self.kind { - PathKind::Global => cx.path_all(span, true, idents, params), - PathKind::Local => cx.path_all(span, false, idents, params), - PathKind::Std => { - let def_site = cx.with_def_site_ctxt(DUMMY_SP); - idents.insert(0, Ident::new(kw::DollarCrate, def_site)); - cx.path_all(span, false, idents, params) - } - } - } -} - -/// A type. Supports pointers, Self, and literals. -#[derive(Clone)] -pub enum Ty<'a> { - Self_, - /// &/Box/ Ty - Ptr(Box<Ty<'a>>, PtrTy), - /// 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() -> PtrTy { - Borrowed(None, ast::Mutability::Not) -} -pub fn borrowed(ty: Box<Ty<'_>>) -> Ty<'_> { - Ptr(ty, borrowed_ptrty()) -} - -pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> { - 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<Ident>) -> Option<ast::Lifetime> { - lt.map(|ident| cx.lifetime(span, ident)) -} - -fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Vec<ast::Lifetime> { - mk_lifetime(cx, span, lt).into_iter().collect() -} - -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::TyKind::Tup( - 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, - generics: &Generics, - ) -> ast::Path { - match *self { - Self_ => { - let params: Vec<_> = generics - .params - .iter() - .map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident }) - } - GenericParamKind::Type { .. } => { - GenericArg::Type(cx.ty_ident(span, param.ident)) - } - GenericParamKind::Const { .. } => { - GenericArg::Const(cx.const_ident(span, param.ident)) - } - }) - .collect(); - - cx.path_all(span, false, vec![self_ty], params) - } - Literal(ref p) => p.to_path(cx, span, self_ty, 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, - attrs: &[ast::Attribute], - bounds: &[Path<'_>], - self_ident: Ident, - self_generics: &Generics, -) -> ast::GenericParam { - let bounds = bounds - .iter() - .map(|b| { - let path = b.to_path(cx, span, self_ident, self_generics); - cx.trait_bound(path) - }) - .collect(); - cx.typaram(span, cx.ident_of(name, span), attrs.to_owned(), bounds, None) -} - -fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics { - Generics { params, where_clause: ast::WhereClause { predicates: Vec::new(), span }, span } -} - -/// 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 generic_params = self - .lifetimes - .iter() - .map(|&(lt, ref bounds)| { - let bounds = bounds - .iter() - .map(|b| ast::GenericBound::Outlives(cx.lifetime(span, Ident::from_str(b)))); - cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds.collect()) - }) - .chain(self.bounds.iter().map(|t| { - let (name, ref bounds) = *t; - mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics) - })) - .collect(); - - mk_generics(generic_params, span) - } -} - -pub fn get_explicit_self( - cx: &ExtCtxt<'_>, - span: Span, - self_ptr: &Option<PtrTy>, -) -> (P<Expr>, ast::ExplicitSelf) { - // this constructs a fresh `self` path - let self_path = cx.expr_self(span); - match *self_ptr { - None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Not))), - Some(ref ptr) => { - let self_ty = respan( - span, - match *ptr { - Borrowed(ref lt, mutbl) => { - let lt = lt.map(|s| cx.lifetime(span, s)); - SelfKind::Region(lt, mutbl) - } - 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 acf18ac70e6..00000000000 --- a/src/libsyntax_ext/deriving/hash.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::{self, path_std, pathvec_std}; - -use syntax::ast::{Expr, MetaItem, Mutability}; -use syntax::ptr::P; -use syntax::symbol::sym; -use syntax_expand::base::{Annotatable, ExtCtxt}; -use syntax_pos::Span; - -pub fn expand_deriving_hash( - cx: &mut ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), -) { - let path = Path::new_(pathvec_std!(cx, hash::Hash), None, vec![], PathKind::Std); - - let typaram = "__H"; - - let arg = Path::new_local(typaram); - let hash_trait_def = TraitDef { - span, - attributes: Vec::new(), - path, - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: false, - methods: vec![MethodDef { - name: "hash", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec![(typaram, vec![path_std!(cx, hash::Hasher)])], - }, - explicit_self: borrowed_explicit_self(), - args: vec![(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mut)), "state")], - ret_ty: nil_ty(), - attributes: vec![], - is_unsafe: false, - unify_fieldless_variants: true, - 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 { - &[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(&[sym::hash, sym::Hash, sym::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) | EnumMatching(_, 1, .., ref fs) => fs, - EnumMatching(.., ref fs) => { - let variant_value = deriving::call_intrinsic( - cx, - trait_span, - "discriminant_value", - vec![cx.expr_self(trait_span)], - ); - - stmts.push(call_hash(trait_span, variant_value)); - - fs - } - _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`"), - }; - - stmts.extend( - fields.iter().map(|FieldInfo { ref self_, span, .. }| call_hash(*span, self_.clone())), - ); - - cx.expr_block(cx.block(trait_span, stmts)) -} diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs deleted file mode 100644 index ca4d4fbc5bd..00000000000 --- a/src/libsyntax_ext/deriving/mod.rs +++ /dev/null @@ -1,171 +0,0 @@ -//! The compiler code necessary to implement the `#[derive]` extensions. - -use syntax::ast::{self, ItemKind, MetaItem}; -use syntax::ptr::P; -use syntax::symbol::{sym, Symbol}; -use syntax_expand::base::{Annotatable, ExtCtxt, MultiItemModifier}; -use syntax_pos::Span; - -macro path_local($x:ident) { - generic::ty::Path::new_local(stringify!($x)) -} - -macro pathvec_std($cx:expr, $($rest:ident)::+) {{ - vec![ $( stringify!($rest) ),+ ] -}} - -macro path_std($($x:tt)*) { - generic::ty::Path::new( pathvec_std!( $($x)* ) ) -} - -pub mod bounds; -pub mod clone; -pub mod debug; -pub mod decodable; -pub mod default; -pub mod encodable; -pub mod hash; - -#[path = "cmp/eq.rs"] -pub mod eq; -#[path = "cmp/ord.rs"] -pub mod ord; -#[path = "cmp/partial_eq.rs"] -pub mod partial_eq; -#[path = "cmp/partial_ord.rs"] -pub mod partial_ord; - -pub mod generic; - -crate struct BuiltinDerive( - crate fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)), -); - -impl MultiItemModifier for BuiltinDerive { - fn expand( - &self, - ecx: &mut ExtCtxt<'_>, - span: Span, - meta_item: &MetaItem, - item: Annotatable, - ) -> Vec<Annotatable> { - // FIXME: Built-in derives often forget to give spans contexts, - // so we are doing it here in a centralized way. - let span = ecx.with_def_site_ctxt(span); - let mut items = Vec::new(); - (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a)); - items - } -} - -/// Constructs an expression that calls an intrinsic -fn call_intrinsic( - cx: &ExtCtxt<'_>, - span: Span, - intrinsic: &str, - args: Vec<P<ast::Expr>>, -) -> P<ast::Expr> { - let span = cx.with_def_site_ctxt(span); - let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]); - let call = cx.expr_call_global(span, path, args); - - cx.expr_block(P(ast::Block { - stmts: vec![cx.stmt_expr(call)], - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), - span, - })) -} - -// Injects `impl<...> Structural for ItemType<...> { }`. In particular, -// does *not* add `where T: Structural` for parameters `T` in `...`. -// (That's the main reason we cannot use TraitDef here.) -fn inject_impl_of_structural_trait( - cx: &mut ExtCtxt<'_>, - span: Span, - item: &Annotatable, - structural_path: generic::ty::Path<'_>, - push: &mut dyn FnMut(Annotatable), -) { - let item = match *item { - Annotatable::Item(ref item) => item, - _ => { - // Non-Item derive is an error, but it should have been - // set earlier; see - // libsyntax_expand/expand.rs:MacroExpander::fully_expand_fragment() - // libsyntax_expand/base.rs:Annotatable::derive_allowed() - return; - } - }; - - let generics = match item.kind { - ItemKind::Struct(_, ref generics) | ItemKind::Enum(_, ref generics) => generics, - // Do not inject `impl Structural for Union`. (`PartialEq` does not - // support unions, so we will see error downstream.) - ItemKind::Union(..) => return, - _ => unreachable!(), - }; - - // Create generics param list for where clauses and impl headers - let mut generics = generics.clone(); - - // Create the type of `self`. - // - // in addition, remove defaults from type params (impls cannot have them). - let self_params: Vec<_> = generics - .params - .iter_mut() - .map(|param| match &mut param.kind { - ast::GenericParamKind::Lifetime => { - ast::GenericArg::Lifetime(cx.lifetime(span, param.ident)) - } - ast::GenericParamKind::Type { default } => { - *default = None; - ast::GenericArg::Type(cx.ty_ident(span, param.ident)) - } - ast::GenericParamKind::Const { ty: _ } => { - ast::GenericArg::Const(cx.const_ident(span, param.ident)) - } - }) - .collect(); - - let type_ident = item.ident; - - let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics)); - let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params)); - - // It would be nice to also encode constraint `where Self: Eq` (by adding it - // onto `generics` cloned above). Unfortunately, that strategy runs afoul of - // rust-lang/rust#48214. So we perform that additional check in the compiler - // itself, instead of encoding it here. - - // Keep the lint and stability attributes of the original item, to control - // how the generated implementation is linted. - let mut attrs = Vec::new(); - attrs.extend( - item.attrs - .iter() - .filter(|a| { - [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable] - .contains(&a.name_or_empty()) - }) - .cloned(), - ); - - let newitem = cx.item( - span, - ast::Ident::invalid(), - attrs, - ItemKind::Impl( - ast::Unsafety::Normal, - ast::ImplPolarity::Positive, - ast::Defaultness::Final, - generics, - Some(trait_ref), - self_type, - Vec::new(), - ), - ); - - push(Annotatable::Item(newitem)); -} |
