From 4e9e091e91ea2ad8a6f45a9b20ff331d4bca7a23 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 16 May 2014 14:23:04 -0700 Subject: syntax: Tighten search paths for inner modules This is an implementation of RFC 16. A module can now only be loaded if the module declaring `mod name;` "owns" the current directory. A module is considered as owning its directory if it meets one of the following criteria: * It is the top-level crate file * It is a `mod.rs` file * It was loaded via `#[path]` * It was loaded via `include!` * The module was declared via an inline `mod foo { ... }` statement For example, this directory structure is now invalid // lib.rs mod foo; // foo.rs mod bar; // bar.rs; fn bar() {} With this change `foo.rs` must be renamed to `foo/mod.rs`, and `bar.rs` must be renamed to `foo/bar.rs`. This makes it clear that `bar` is a submodule of `foo`, and can only be accessed through `foo`. RFC: 0016-module-file-system-hierarchy Closes #14180 [breaking-change] --- src/libsyntax/ext/deriving/generic.rs | 1304 ----------------------------- src/libsyntax/ext/deriving/generic/mod.rs | 1304 +++++++++++++++++++++++++++++ src/libsyntax/ext/deriving/generic/ty.rs | 267 ++++++ src/libsyntax/ext/deriving/ty.rs | 267 ------ src/libsyntax/ext/source_util.rs | 2 + src/libsyntax/parse/mod.rs | 7 +- src/libsyntax/parse/parser.rs | 50 +- 7 files changed, 1623 insertions(+), 1578 deletions(-) delete mode 100644 src/libsyntax/ext/deriving/generic.rs create mode 100644 src/libsyntax/ext/deriving/generic/mod.rs create mode 100644 src/libsyntax/ext/deriving/generic/ty.rs delete mode 100644 src/libsyntax/ext/deriving/ty.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs deleted file mode 100644 index 6df4da89402..00000000000 --- a/src/libsyntax/ext/deriving/generic.rs +++ /dev/null @@ -1,1304 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -Some code that abstracts away much of the boilerplate of writing -`deriving` 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`), 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, e.g. the `Ord` instance - requires an explicit `Eq` bound at the - moment. (`TraitDef.additional_bounds`) - -Unsupported: FIXME #6257: calling methods on reference fields, -e.g. deriving TotalEq/TotalOrd/Clone don't work on `struct A(&int)`, -because of how the auto-dereferencing happens. - -The most important thing for implementers is the `Substructure` and -`SubstructureFields` objects. The latter groups 5 possibilities of the -arguments: - -- `Struct`, when `Self` is a struct (including tuple structs, e.g - `struct T(int, 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)`) -- `EnumNonMatching` when `Self` is an enum and the arguments are not - the same variant (e.g. `None`, `Some(1)` and `None`). If - `const_nonmatching` is true, this will contain an empty list. -- `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. In the `EnumNonMatching` case -this isn't possible (different variants have different fields), so the -fields are grouped by which argument they come from. There are no -fields with values in the static cases, so these are treated entirely -differently. - -The non-static cases have `Option` 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 -struct A { x : int } - -struct B(int); - -enum C { - C0(int), - C1 { x: int } -} -``` - -The `int`s in `B` and `C0` don't have an identifier, so the -`Option`s would be `None` for them. - -In the static cases, the structure is summarised, either into the just -spans of the fields or a list of spans and the field idents (for tuple -structs and record structs, respectively), or a list of these, for -enums (one for each variant). For empty struct and empty enum -variants, it is represented as a count of 0. - -# Examples - -The following simplified `Eq` is used for in-code examples: - -```rust -trait Eq { - fn eq(&self, other: &Self); -} -impl Eq for int { - fn eq(&self, other: &int) -> bool { - *self == *other - } -} -``` - -Some examples of the values of `SubstructureFields` follow, using the -above `Eq`, `A`, `B` and `C`. - -## Structs - -When generating the `expr` for the `A` impl, the `SubstructureFields` is - -~~~notrust -Struct(~[FieldInfo { - span: - name: Some(), - self_: , - other: ~[, - name: None, - - ~[] - }]) -~~~ - -## Enums - -When generating the `expr` for a call with `self == C0(a)` and `other -== C0(b)`, the SubstructureFields is - -~~~notrust -EnumMatching(0, , - ~[FieldInfo { - span: - name: None, - self_: , - other: ~[] - }]) -~~~ - -For `C1 {x}` and `C1 {x}`, - -~~~notrust -EnumMatching(1, , - ~[FieldInfo { - span: - name: Some(), - self_: , - other: ~[] - }]) -~~~ - -For `C0(a)` and `C1 {x}` , - -~~~notrust -EnumNonMatching(~[(0, , - ~[(, None, )]), - (1, , - ~[(, Some(), - )])]) -~~~ - -(and vice versa, but with the order of the outermost list flipped.) - -## Static - -A static method on the above would result in, - -~~~~notrust -StaticStruct(, Named(~[(, )])) - -StaticStruct(, Unnamed(~[])) - -StaticEnum(, ~[(, , Unnamed(~[])), - (, , - Named(~[(, )]))]) -~~~ - -*/ - -use std::cell::RefCell; - -use ast; -use ast::{P, EnumDef, Expr, Ident, Generics, StructDef}; -use ast_util; -use attr::AttrMetaMethods; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use codemap; -use codemap::Span; -use owned_slice::OwnedSlice; -use parse::token::InternedString; - -pub use self::ty::*; -mod ty; - -pub struct TraitDef<'a> { - /// The span for the current #[deriving(Foo)] header. - pub span: Span, - - pub attributes: Vec, - - /// 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>, - - /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder` - pub generics: LifetimeBounds<'a>, - - pub methods: Vec>, -} - - -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>>, - - /// Arguments other than the self argument - pub args: Vec>, - - /// Return type - pub ret_ty: Ty<'a>, - - pub attributes: Vec, - - /// if the value of the nonmatching enums is independent of the - /// actual enum variants, i.e. can use _ => .. match. - pub const_nonmatching: bool, - - pub combine_substructure: RefCell>, -} - -/// 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 [@Expr], - /// verbatim access to any other arguments - pub nonself_args: &'a [@Expr], - pub fields: &'a SubstructureFields<'a> -} - -/// Summary of the relevant parts of a struct/enum field. -pub struct FieldInfo { - pub span: Span, - /// None for tuple structs/normal enum variants, Some for normal - /// structs/struct enum variants. - pub name: Option, - /// The expression corresponding to this field of `self` - /// (specifically, a reference to it). - pub self_: @Expr, - /// The expressions corresponding to references to this field in - /// the other Self arguments. - pub other: Vec<@Expr>, -} - -/// Fields for a static method -pub enum StaticFields { - /// Tuple structs/enum variants like this - Unnamed(Vec ), - /// Normal structs/struct variants. - Named(Vec<(Ident, Span)> ) -} - -/// A summary of the possible sets of fields. See above for details -/// and examples -pub enum SubstructureFields<'a> { - Struct(Vec ), - /** - Matching variants of the enum: variant index, ast::Variant, - fields: the field name is only non-`None` in the case of a struct - variant. - */ - EnumMatching(uint, &'a ast::Variant, Vec ), - - /** - non-matching variants of the enum, [(variant index, ast::Variant, - [field span, field ident, fields])] (i.e. all fields for self are in the - first tuple, for other1 are in the second tuple, etc.) - */ - EnumNonMatching(&'a [(uint, P, Vec<(Span, Option, @Expr)> )]), - - /// A static method where Self is a struct. - StaticStruct(&'a ast::StructDef, 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, see above for details. -*/ -pub type CombineSubstructureFunc<'a> = - |&mut ExtCtxt, Span, &Substructure|: 'a -> @Expr; - -/** -Deal with non-matching enum variants, the arguments are a list -representing each variant: (variant index, ast::Variant instance, -[variant fields]), and a list of the nonself args of the type -*/ -pub type EnumNonMatchFunc<'a> = - |&mut ExtCtxt, - Span, - &[(uint, P, Vec<(Span, Option, @Expr)> )], - &[@Expr]|: 'a - -> @Expr; - -pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) - -> RefCell> { - RefCell::new(f) -} - - -impl<'a> TraitDef<'a> { - pub fn expand(&self, - cx: &mut ExtCtxt, - _mitem: @ast::MetaItem, - item: @ast::Item, - push: |@ast::Item|) { - let newitem = match item.node { - ast::ItemStruct(struct_def, ref generics) => { - self.expand_struct_def(cx, - struct_def, - item.ident, - generics) - } - ast::ItemEnum(ref enum_def, ref generics) => { - self.expand_enum_def(cx, - enum_def, - item.ident, - generics) - } - _ => return - }; - // Keep the lint attributes of the previous item to control how the - // generated implementations are linted - let mut attrs = newitem.attrs.clone(); - attrs.extend(item.attrs.iter().filter(|a| { - match a.name().get() { - "allow" | "warn" | "deny" | "forbid" => true, - _ => false, - } - }).map(|a| a.clone())); - push(@ast::Item { - attrs: attrs, - ..(*newitem).clone() - }) - } - - /** - * - * Given that we are deriving a trait `Tr` for a type `T<'a, ..., - * 'z, A, ..., Z>`, creates an impl like: - * - * ```ignore - * impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T { ... } - * ``` - * - * where B1, B2, ... are the bounds given by `bounds_paths`.' - * - */ - fn create_derived_impl(&self, - cx: &mut ExtCtxt, - type_ident: Ident, - generics: &Generics, - methods: Vec<@ast::Method> ) -> @ast::Item { - let trait_path = self.path.to_path(cx, self.span, type_ident, generics); - - let Generics { mut lifetimes, ty_params } = - self.generics.to_generics(cx, self.span, type_ident, generics); - let mut ty_params = ty_params.into_vec(); - - // Copy the lifetimes - lifetimes.extend(generics.lifetimes.iter().map(|l| *l)); - - // Create the type parameters. - ty_params.extend(generics.ty_params.iter().map(|ty_param| { - // I don't think this can be moved out of the loop, since - // a TyParamBound requires an ast id - let mut bounds: Vec<_> = - // extra restrictions on the generics parameters to the type being derived upon - self.additional_bounds.iter().map(|p| { - cx.typarambound(p.to_path(cx, self.span, - type_ident, generics)) - }).collect(); - // require the current trait - bounds.push(cx.typarambound(trait_path.clone())); - - cx.typaram(self.span, - ty_param.ident, - ty_param.sized, - OwnedSlice::from_vec(bounds), - None) - })); - let trait_generics = Generics { - lifetimes: lifetimes, - ty_params: OwnedSlice::from_vec(ty_params) - }; - - // Create the reference to the trait. - let trait_ref = cx.trait_ref(trait_path); - - // Create the type parameters on the `self` path. - let self_ty_params = generics.ty_params.map(|ty_param| { - cx.ty_ident(self.span, ty_param.ident) - }); - - let self_lifetimes = generics.lifetimes.clone(); - - // Create the type of `self`. - let self_type = cx.ty_path( - cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes, - self_ty_params.into_vec()), None); - - let attr = cx.attribute( - self.span, - cx.meta_word(self.span, - InternedString::new("automatically_derived"))); - let opt_trait_ref = Some(trait_ref); - let ident = ast_util::impl_pretty_name(&opt_trait_ref, self_type); - cx.item( - self.span, - ident, - (vec!(attr)).append(self.attributes.as_slice()), - ast::ItemImpl(trait_generics, opt_trait_ref, - self_type, methods)) - } - - fn expand_struct_def(&self, - cx: &mut ExtCtxt, - struct_def: &StructDef, - type_ident: Ident, - generics: &Generics) -> @ast::Item { - let methods = self.methods.iter().map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args( - cx, self, type_ident, generics); - - let body = if method_def.is_static() { - method_def.expand_static_struct_method_body( - cx, - self, - struct_def, - type_ident, - self_args.as_slice(), - nonself_args.as_slice()) - } else { - method_def.expand_struct_method_body(cx, - self, - struct_def, - type_ident, - self_args.as_slice(), - nonself_args.as_slice()) - }; - - method_def.create_method(cx, self, - type_ident, generics, - explicit_self, tys, - body) - }).collect(); - - self.create_derived_impl(cx, type_ident, generics, methods) - } - - fn expand_enum_def(&self, - cx: &mut ExtCtxt, - enum_def: &EnumDef, - type_ident: Ident, - generics: &Generics) -> @ast::Item { - let methods = self.methods.iter().map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args(cx, self, - type_ident, generics); - - let body = if method_def.is_static() { - method_def.expand_static_enum_method_body( - cx, - self, - enum_def, - type_ident, - self_args.as_slice(), - nonself_args.as_slice()) - } else { - method_def.expand_enum_method_body(cx, - self, - enum_def, - type_ident, - self_args.as_slice(), - nonself_args.as_slice()) - }; - - method_def.create_method(cx, self, - type_ident, generics, - explicit_self, tys, - body) - }).collect(); - - self.create_derived_impl(cx, type_ident, generics, methods) - } -} - -impl<'a> MethodDef<'a> { - fn call_substructure_method(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - self_args: &[@Expr], - nonself_args: &[@Expr], - fields: &SubstructureFields) - -> @Expr { - let substructure = Substructure { - type_ident: type_ident, - method_ident: cx.ident_of(self.name), - self_args: self_args, - nonself_args: nonself_args, - fields: fields - }; - let mut f = self.combine_substructure.borrow_mut(); - let f: &mut CombineSubstructureFunc = &mut *f; - (*f)(cx, trait_.span, &substructure) - } - - fn get_ret_ty(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - generics: &Generics, - type_ident: Ident) - -> P { - self.ret_ty.to_ty(cx, trait_.span, type_ident, generics) - } - - fn is_static(&self) -> bool { - self.explicit_self.is_none() - } - - fn split_self_nonself_args(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - generics: &Generics) - -> (ast::ExplicitSelf, Vec<@Expr> , Vec<@Expr> , Vec<(Ident, P)> ) { - - let mut self_args = Vec::new(); - let mut nonself_args = Vec::new(); - let mut arg_tys = Vec::new(); - let mut nonstatic = false; - - let ast_explicit_self = match self.explicit_self { - Some(ref self_ptr) => { - let (self_expr, explicit_self) = - ty::get_explicit_self(cx, trait_.span, self_ptr); - - self_args.push(self_expr); - nonstatic = true; - - explicit_self - } - None => codemap::respan(trait_.span, ast::SelfStatic), - }; - - for (i, ty) in self.args.iter().enumerate() { - let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics); - let ident = cx.ident_of(format!("__arg_{}", i)); - arg_tys.push((ident, ast_ty)); - - let arg_expr = cx.expr_ident(trait_.span, ident); - - match *ty { - // for static methods, just treat any Self - // arguments as a normal arg - Self if nonstatic => { - self_args.push(arg_expr); - } - Ptr(box Self, _) if 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: ast::ExplicitSelf, - arg_types: Vec<(Ident, P)> , - body: @Expr) -> @ast::Method { - // create the generics that aren't for Self - let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); - - let self_arg = match explicit_self.node { - ast::SelfStatic => None, - _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable)) - }; - let args = { - let args = arg_types.move_iter().map(|(name, ty)| { - cx.arg(trait_.span, name, ty) - }); - self_arg.move_iter().chain(args).collect() - }; - - let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); - - let method_ident = cx.ident_of(self.name); - let fn_decl = cx.fn_decl(args, ret_type); - let body_block = cx.block_expr(body); - - // Create the method. - @ast::Method { - ident: method_ident, - attrs: self.attributes.clone(), - generics: fn_generics, - explicit_self: explicit_self, - fn_style: ast::NormalFn, - decl: fn_decl, - body: body_block, - id: ast::DUMMY_NODE_ID, - span: trait_.span, - vis: ast::Inherited, - } - } - - /** - ~~~ - #[deriving(Eq)] - struct A { x: int, y: int } - - // equivalent to: - impl Eq for A { - fn eq(&self, __arg_1: &A) -> bool { - match *self { - A {x: ref __self_0_0, y: ref __self_0_1} => { - match *__arg_1 { - A {x: ref __self_1_0, y: ref __self_1_1} => { - __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1) - } - } - } - } - } - } - ~~~ - */ - fn expand_struct_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - struct_def: &StructDef, - type_ident: Ident, - self_args: &[@Expr], - nonself_args: &[@Expr]) - -> @Expr { - - let mut raw_fields = Vec::new(); // ~[[fields of self], - // [fields of next Self arg], [etc]] - let mut patterns = Vec::new(); - for i in range(0u, self_args.len()) { - let (pat, ident_expr) = trait_.create_struct_pattern(cx, type_ident, struct_def, - format!("__self_{}", i), - ast::MutImmutable); - patterns.push(pat); - raw_fields.push(ident_expr); - } - - // transpose raw_fields - let fields = if raw_fields.len() > 0 { - raw_fields.get(0) - .iter() - .enumerate() - .map(|(i, &(span, opt_id, field))| { - let other_fields = raw_fields.tail().iter().map(|l| { - match l.get(i) { - &(_, _, ex) => ex - } - }).collect(); - FieldInfo { - span: span, - name: opt_id, - self_: field, - other: other_fields - } - }).collect() - } else { - cx.span_bug(trait_.span, - "no self arguments to non-static method in generic \ - `deriving`") - }; - - // body of the inner most destructuring match - let mut body = self.call_substructure_method( - cx, - trait_, - type_ident, - self_args, - nonself_args, - &Struct(fields)); - - // make a series of nested matches, to destructure the - // structs. This is actually right-to-left, but it shoudn't - // matter. - for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) { - body = cx.expr_match(trait_.span, arg_expr, - vec!( cx.arm(trait_.span, vec!(pat), body) )) - } - body - } - - fn expand_static_struct_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - struct_def: &StructDef, - type_ident: Ident, - self_args: &[@Expr], - nonself_args: &[@Expr]) - -> @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)) - } - - /** - ~~~ - #[deriving(Eq)] - enum A { - A1 - A2(int) - } - - // is equivalent to (with const_nonmatching == false) - - impl Eq for A { - fn eq(&self, __arg_1: &A) { - match *self { - A1 => match *__arg_1 { - A1 => true - A2(ref __arg_1_1) => false - }, - A2(self_1) => match *__arg_1 { - A1 => false, - A2(ref __arg_1_1) => self_1.eq(__arg_1_1) - } - } - } - } - ~~~ - */ - fn expand_enum_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, - type_ident: Ident, - self_args: &[@Expr], - nonself_args: &[@Expr]) - -> @Expr { - let mut matches = Vec::new(); - self.build_enum_match(cx, trait_, enum_def, type_ident, - self_args, nonself_args, - None, &mut matches, 0) - } - - - /** - Creates the nested matches for an enum definition recursively, i.e. - - ~~~notrust - match self { - Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... }, - Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... }, - ... - } - ~~~ - - It acts in the most naive way, so every branch (and subbranch, - subsubbranch, etc) exists, not just the ones where all the variants in - the tree are the same. Hopefully the optimisers get rid of any - repetition, otherwise derived methods with many Self arguments will be - exponentially large. - - `matching` is Some(n) if all branches in the tree above the - current position are variant `n`, `None` otherwise (including on - the first call). - */ - fn build_enum_match(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, - type_ident: Ident, - self_args: &[@Expr], - nonself_args: &[@Expr], - matching: Option, - matches_so_far: &mut Vec<(uint, P, - Vec<(Span, Option, @Expr)> )> , - match_count: uint) -> @Expr { - if match_count == self_args.len() { - // we've matched against all arguments, so make the final - // expression at the bottom of the match tree - if matches_so_far.len() == 0 { - cx.span_bug(trait_.span, - "no self match on an enum in \ - generic `deriving`"); - } - - // `ref` inside let matches is buggy. Causes havoc wih rusc. - // let (variant_index, ref self_vec) = matches_so_far[0]; - let (variant, self_vec) = match matches_so_far.get(0) { - &(_, v, ref s) => (v, s) - }; - - // we currently have a vec of vecs, where each - // subvec is the fields of one of the arguments, - // but if the variants all match, we want this as - // vec of tuples, where each tuple represents a - // field. - - // most arms don't have matching variants, so do a - // quick check to see if they match (even though - // this means iterating twice) instead of being - // optimistic and doing a pile of allocations etc. - let substructure = match matching { - Some(variant_index) => { - let mut enum_matching_fields = Vec::from_elem(self_vec.len(), Vec::new()); - - for triple in matches_so_far.tail().iter() { - match triple { - &(_, _, ref other_fields) => { - for (i, &(_, _, e)) in other_fields.iter().enumerate() { - enum_matching_fields.get_mut(i).push(e); - } - } - } - } - let field_tuples = - self_vec.iter() - .zip(enum_matching_fields.iter()) - .map(|(&(span, id, self_f), other)| { - FieldInfo { - span: span, - name: id, - self_: self_f, - other: (*other).clone() - } - }).collect(); - EnumMatching(variant_index, variant, field_tuples) - } - None => { - EnumNonMatching(matches_so_far.as_slice()) - } - }; - self.call_substructure_method(cx, trait_, type_ident, - self_args, nonself_args, - &substructure) - - } else { // there are still matches to create - let current_match_str = if match_count == 0 { - "__self".to_owned() - } else { - format!("__arg_{}", match_count) - }; - - let mut arms = Vec::new(); - - // the code for nonmatching variants only matters when - // we've seen at least one other variant already - if self.const_nonmatching && match_count > 0 { - // make a matching-variant match, and a _ match. - let index = match matching { - Some(i) => i, - None => cx.span_bug(trait_.span, - "non-matching variants when required to \ - be matching in generic `deriving`") - }; - - // matching-variant match - let variant = *enum_def.variants.get(index); - let (pattern, idents) = trait_.create_enum_variant_pattern(cx, - variant, - current_match_str, - ast::MutImmutable); - - matches_so_far.push((index, variant, idents)); - let arm_expr = self.build_enum_match(cx, - trait_, - enum_def, - type_ident, - self_args, nonself_args, - matching, - matches_so_far, - match_count + 1); - matches_so_far.pop().unwrap(); - arms.push(cx.arm(trait_.span, vec!( pattern ), arm_expr)); - - if enum_def.variants.len() > 1 { - let e = &EnumNonMatching(&[]); - let wild_expr = self.call_substructure_method(cx, trait_, type_ident, - self_args, nonself_args, - e); - let wild_arm = cx.arm( - trait_.span, - vec!( cx.pat_wild(trait_.span) ), - wild_expr); - arms.push(wild_arm); - } - } else { - // create an arm matching on each variant - for (index, &variant) in enum_def.variants.iter().enumerate() { - let (pattern, idents) = trait_.create_enum_variant_pattern(cx, - variant, - current_match_str, - ast::MutImmutable); - - matches_so_far.push((index, variant, idents)); - let new_matching = - match matching { - _ if match_count == 0 => Some(index), - Some(i) if index == i => Some(i), - _ => None - }; - let arm_expr = self.build_enum_match(cx, - trait_, - enum_def, - type_ident, - self_args, nonself_args, - new_matching, - matches_so_far, - match_count + 1); - matches_so_far.pop().unwrap(); - - let arm = cx.arm(trait_.span, vec!( pattern ), arm_expr); - arms.push(arm); - } - } - - // match foo { arm, arm, arm, ... } - cx.expr_match(trait_.span, self_args[match_count], arms) - } - } - - fn expand_static_enum_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, - type_ident: Ident, - self_args: &[@Expr], - nonself_args: &[@Expr]) - -> @Expr { - let summary = enum_def.variants.iter().map(|v| { - let ident = v.node.name; - let summary = match v.node.kind { - ast::TupleVariantKind(ref args) => { - Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect()) - } - ast::StructVariantKind(struct_def) => { - trait_.summarise_struct(cx, struct_def) - } - }; - (ident, v.span, summary) - }).collect(); - self.call_substructure_method(cx, trait_, type_ident, - self_args, nonself_args, - &StaticEnum(enum_def, summary)) - } -} - -#[deriving(Eq)] // dogfooding! -enum StructType { - Unknown, Record, Tuple -} - -// general helper methods. -impl<'a> TraitDef<'a> { - fn set_expn_info(&self, - cx: &mut ExtCtxt, - mut to_set: Span) -> Span { - let trait_name = match self.path.path.last() { - None => cx.span_bug(self.span, "trait with empty path in generic `deriving`"), - Some(name) => *name - }; - to_set.expn_info = Some(@codemap::ExpnInfo { - call_site: to_set, - callee: codemap::NameAndSpan { - name: format!("deriving({})", trait_name).to_strbuf(), - format: codemap::MacroAttribute, - span: Some(self.span) - } - }); - to_set - } - - fn summarise_struct(&self, - cx: &mut ExtCtxt, - struct_def: &StructDef) -> StaticFields { - let mut named_idents = Vec::new(); - let mut just_spans = Vec::new(); - for field in struct_def.fields.iter(){ - let sp = self.set_expn_info(cx, field.span); - match field.node.kind { - ast::NamedField(ident, _) => named_idents.push((ident, sp)), - ast::UnnamedField(..) => just_spans.push(sp), - } - } - - match (just_spans.is_empty(), named_idents.is_empty()) { - (false, false) => cx.span_bug(self.span, - "a struct with named and unnamed \ - fields in generic `deriving`"), - // named fields - (_, false) => Named(named_idents), - // tuple structs (includes empty structs) - (_, _) => Unnamed(just_spans) - } - } - - fn create_subpatterns(&self, - cx: &mut ExtCtxt, - field_paths: Vec , - mutbl: ast::Mutability) - -> Vec<@ast::Pat> { - field_paths.iter().map(|path| { - cx.pat(path.span, - ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None)) - }).collect() - } - - fn create_struct_pattern(&self, - cx: &mut ExtCtxt, - struct_ident: Ident, - struct_def: &StructDef, - prefix: &str, - mutbl: ast::Mutability) - -> (@ast::Pat, Vec<(Span, Option, @Expr)> ) { - if struct_def.fields.is_empty() { - return ( - cx.pat_ident_binding_mode( - self.span, struct_ident, ast::BindByValue(ast::MutImmutable)), - Vec::new()); - } - - let matching_path = cx.path(self.span, vec!( struct_ident )); - - let mut paths = Vec::new(); - let mut ident_expr = Vec::new(); - let mut struct_type = Unknown; - - for (i, struct_field) in struct_def.fields.iter().enumerate() { - let sp = self.set_expn_info(cx, struct_field.span); - let opt_id = match struct_field.node.kind { - ast::NamedField(ident, _) if (struct_type == Unknown || - struct_type == Record) => { - struct_type = Record; - Some(ident) - } - ast::UnnamedField(..) if (struct_type == Unknown || - struct_type == Tuple) => { - struct_type = Tuple; - None - } - _ => { - cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`"); - } - }; - let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i))); - paths.push(path.clone()); - let val = cx.expr( - sp, ast::ExprParen( - cx.expr_deref(sp, cx.expr_path(path)))); - ident_expr.push((sp, opt_id, val)); - } - - let subpats = self.create_subpatterns(cx, paths, mutbl); - - // struct_type is definitely not Unknown, since struct_def.fields - // must be nonempty to reach here - let pattern = if struct_type == Record { - let field_pats = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _))| { - // id is guaranteed to be Some - ast::FieldPat { ident: id.unwrap(), pat: pat } - }).collect(); - cx.pat_struct(self.span, matching_path, field_pats) - } else { - cx.pat_enum(self.span, matching_path, subpats) - }; - - (pattern, ident_expr) - } - - fn create_enum_variant_pattern(&self, - cx: &mut ExtCtxt, - variant: &ast::Variant, - prefix: &str, - mutbl: ast::Mutability) - -> (@ast::Pat, Vec<(Span, Option, @Expr)> ) { - let variant_ident = variant.node.name; - match variant.node.kind { - ast::TupleVariantKind(ref variant_args) => { - if variant_args.is_empty() { - return (cx.pat_ident_binding_mode(variant.span, variant_ident, - ast::BindByValue(ast::MutImmutable)), - Vec::new()); - } - - let matching_path = cx.path_ident(variant.span, variant_ident); - - let mut paths = Vec::new(); - let mut ident_expr = Vec::new(); - for (i, va) in variant_args.iter().enumerate() { - let sp = self.set_expn_info(cx, va.ty.span); - let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i))); - - paths.push(path.clone()); - let val = cx.expr( - sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path)))); - ident_expr.push((sp, None, val)); - } - - let subpats = self.create_subpatterns(cx, paths, mutbl); - - (cx.pat_enum(variant.span, matching_path, subpats), - ident_expr) - } - ast::StructVariantKind(struct_def) => { - self.create_struct_pattern(cx, variant_ident, struct_def, - prefix, mutbl) - } - } - } -} - -/* helpful premade recipes */ - -/** -Fold the fields. `use_foldl` controls whether this is done -left-to-right (`true`) or right-to-left (`false`). -*/ -pub fn cs_fold(use_foldl: bool, - f: |&mut ExtCtxt, Span, @Expr, @Expr, &[@Expr]| -> @Expr, - base: @Expr, - enum_nonmatch_f: EnumNonMatchFunc, - cx: &mut ExtCtxt, - trait_span: Span, - substructure: &Substructure) - -> @Expr { - match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { - if use_foldl { - all_fields.iter().fold(base, |old, field| { - f(cx, - field.span, - old, - field.self_, - field.other.as_slice()) - }) - } else { - all_fields.iter().rev().fold(base, |old, field| { - f(cx, - field.span, - old, - field.self_, - field.other.as_slice()) - }) - } - }, - EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span, - *all_enums, - substructure.nonself_args), - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, "static function in `deriving`") - } - } -} - - -/** -Call the method that is being derived on all the fields, and then -process the collected results. i.e. - -~~~ -f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1), - self_2.method(__arg_1_2, __arg_2_2)]) -~~~ -*/ -#[inline] -pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<@Expr> | -> @Expr, - enum_nonmatch_f: EnumNonMatchFunc, - cx: &mut ExtCtxt, - trait_span: Span, - substructure: &Substructure) - -> @Expr { - match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { - // call self_n.method(other_1_n, other_2_n, ...) - let called = all_fields.iter().map(|field| { - cx.expr_method_call(field.span, - field.self_, - substructure.method_ident, - field.other.iter() - .map(|e| cx.expr_addr_of(field.span, *e)) - .collect()) - }).collect(); - - f(cx, trait_span, called) - }, - EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span, - *all_enums, - substructure.nonself_args), - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, "static function in `deriving`") - } - } -} - -/** -Fold together the results of calling the derived method on all the -fields. `use_foldl` controls whether this is done left-to-right -(`true`) or right-to-left (`false`). -*/ -#[inline] -pub fn cs_same_method_fold(use_foldl: bool, - f: |&mut ExtCtxt, Span, @Expr, @Expr| -> @Expr, - base: @Expr, - enum_nonmatch_f: EnumNonMatchFunc, - cx: &mut ExtCtxt, - trait_span: Span, - substructure: &Substructure) - -> @Expr { - cs_same_method( - |cx, span, vals| { - if use_foldl { - vals.iter().fold(base, |old, &new| { - f(cx, span, old, new) - }) - } else { - vals.iter().rev().fold(base, |old, &new| { - f(cx, span, old, new) - }) - } - }, - enum_nonmatch_f, - cx, trait_span, substructure) -} - -/** -Use a given binop to combine the result of calling the derived method -on all the fields. -*/ -#[inline] -pub fn cs_binop(binop: ast::BinOp, base: @Expr, - enum_nonmatch_f: EnumNonMatchFunc, - cx: &mut ExtCtxt, trait_span: Span, - substructure: &Substructure) -> @Expr { - cs_same_method_fold( - true, // foldl is good enough - |cx, span, old, new| { - cx.expr_binary(span, - binop, - old, new) - - }, - base, - enum_nonmatch_f, - cx, trait_span, substructure) -} - -/// cs_binop with binop == or -#[inline] -pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc, - cx: &mut ExtCtxt, span: Span, - substructure: &Substructure) -> @Expr { - cs_binop(ast::BiOr, cx.expr_bool(span, false), - enum_nonmatch_f, - cx, span, substructure) -} - -/// cs_binop with binop == and -#[inline] -pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc, - cx: &mut ExtCtxt, span: Span, - substructure: &Substructure) -> @Expr { - cs_binop(ast::BiAnd, cx.expr_bool(span, true), - enum_nonmatch_f, - cx, span, substructure) -} diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs new file mode 100644 index 00000000000..6df4da89402 --- /dev/null +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -0,0 +1,1304 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +Some code that abstracts away much of the boilerplate of writing +`deriving` 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`), 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, e.g. the `Ord` instance + requires an explicit `Eq` bound at the + moment. (`TraitDef.additional_bounds`) + +Unsupported: FIXME #6257: calling methods on reference fields, +e.g. deriving TotalEq/TotalOrd/Clone don't work on `struct A(&int)`, +because of how the auto-dereferencing happens. + +The most important thing for implementers is the `Substructure` and +`SubstructureFields` objects. The latter groups 5 possibilities of the +arguments: + +- `Struct`, when `Self` is a struct (including tuple structs, e.g + `struct T(int, 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)`) +- `EnumNonMatching` when `Self` is an enum and the arguments are not + the same variant (e.g. `None`, `Some(1)` and `None`). If + `const_nonmatching` is true, this will contain an empty list. +- `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. In the `EnumNonMatching` case +this isn't possible (different variants have different fields), so the +fields are grouped by which argument they come from. There are no +fields with values in the static cases, so these are treated entirely +differently. + +The non-static cases have `Option` 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 +struct A { x : int } + +struct B(int); + +enum C { + C0(int), + C1 { x: int } +} +``` + +The `int`s in `B` and `C0` don't have an identifier, so the +`Option`s would be `None` for them. + +In the static cases, the structure is summarised, either into the just +spans of the fields or a list of spans and the field idents (for tuple +structs and record structs, respectively), or a list of these, for +enums (one for each variant). For empty struct and empty enum +variants, it is represented as a count of 0. + +# Examples + +The following simplified `Eq` is used for in-code examples: + +```rust +trait Eq { + fn eq(&self, other: &Self); +} +impl Eq for int { + fn eq(&self, other: &int) -> bool { + *self == *other + } +} +``` + +Some examples of the values of `SubstructureFields` follow, using the +above `Eq`, `A`, `B` and `C`. + +## Structs + +When generating the `expr` for the `A` impl, the `SubstructureFields` is + +~~~notrust +Struct(~[FieldInfo { + span: + name: Some(), + self_: , + other: ~[, + name: None, + + ~[] + }]) +~~~ + +## Enums + +When generating the `expr` for a call with `self == C0(a)` and `other +== C0(b)`, the SubstructureFields is + +~~~notrust +EnumMatching(0, , + ~[FieldInfo { + span: + name: None, + self_: , + other: ~[] + }]) +~~~ + +For `C1 {x}` and `C1 {x}`, + +~~~notrust +EnumMatching(1, , + ~[FieldInfo { + span: + name: Some(), + self_: , + other: ~[] + }]) +~~~ + +For `C0(a)` and `C1 {x}` , + +~~~notrust +EnumNonMatching(~[(0, , + ~[(, None, )]), + (1, , + ~[(, Some(), + )])]) +~~~ + +(and vice versa, but with the order of the outermost list flipped.) + +## Static + +A static method on the above would result in, + +~~~~notrust +StaticStruct(, Named(~[(, )])) + +StaticStruct(, Unnamed(~[])) + +StaticEnum(, ~[(, , Unnamed(~[])), + (, , + Named(~[(, )]))]) +~~~ + +*/ + +use std::cell::RefCell; + +use ast; +use ast::{P, EnumDef, Expr, Ident, Generics, StructDef}; +use ast_util; +use attr::AttrMetaMethods; +use ext::base::ExtCtxt; +use ext::build::AstBuilder; +use codemap; +use codemap::Span; +use owned_slice::OwnedSlice; +use parse::token::InternedString; + +pub use self::ty::*; +mod ty; + +pub struct TraitDef<'a> { + /// The span for the current #[deriving(Foo)] header. + pub span: Span, + + pub attributes: Vec, + + /// 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>, + + /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder` + pub generics: LifetimeBounds<'a>, + + pub methods: Vec>, +} + + +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>>, + + /// Arguments other than the self argument + pub args: Vec>, + + /// Return type + pub ret_ty: Ty<'a>, + + pub attributes: Vec, + + /// if the value of the nonmatching enums is independent of the + /// actual enum variants, i.e. can use _ => .. match. + pub const_nonmatching: bool, + + pub combine_substructure: RefCell>, +} + +/// 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 [@Expr], + /// verbatim access to any other arguments + pub nonself_args: &'a [@Expr], + pub fields: &'a SubstructureFields<'a> +} + +/// Summary of the relevant parts of a struct/enum field. +pub struct FieldInfo { + pub span: Span, + /// None for tuple structs/normal enum variants, Some for normal + /// structs/struct enum variants. + pub name: Option, + /// The expression corresponding to this field of `self` + /// (specifically, a reference to it). + pub self_: @Expr, + /// The expressions corresponding to references to this field in + /// the other Self arguments. + pub other: Vec<@Expr>, +} + +/// Fields for a static method +pub enum StaticFields { + /// Tuple structs/enum variants like this + Unnamed(Vec ), + /// Normal structs/struct variants. + Named(Vec<(Ident, Span)> ) +} + +/// A summary of the possible sets of fields. See above for details +/// and examples +pub enum SubstructureFields<'a> { + Struct(Vec ), + /** + Matching variants of the enum: variant index, ast::Variant, + fields: the field name is only non-`None` in the case of a struct + variant. + */ + EnumMatching(uint, &'a ast::Variant, Vec ), + + /** + non-matching variants of the enum, [(variant index, ast::Variant, + [field span, field ident, fields])] (i.e. all fields for self are in the + first tuple, for other1 are in the second tuple, etc.) + */ + EnumNonMatching(&'a [(uint, P, Vec<(Span, Option, @Expr)> )]), + + /// A static method where Self is a struct. + StaticStruct(&'a ast::StructDef, 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, see above for details. +*/ +pub type CombineSubstructureFunc<'a> = + |&mut ExtCtxt, Span, &Substructure|: 'a -> @Expr; + +/** +Deal with non-matching enum variants, the arguments are a list +representing each variant: (variant index, ast::Variant instance, +[variant fields]), and a list of the nonself args of the type +*/ +pub type EnumNonMatchFunc<'a> = + |&mut ExtCtxt, + Span, + &[(uint, P, Vec<(Span, Option, @Expr)> )], + &[@Expr]|: 'a + -> @Expr; + +pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) + -> RefCell> { + RefCell::new(f) +} + + +impl<'a> TraitDef<'a> { + pub fn expand(&self, + cx: &mut ExtCtxt, + _mitem: @ast::MetaItem, + item: @ast::Item, + push: |@ast::Item|) { + let newitem = match item.node { + ast::ItemStruct(struct_def, ref generics) => { + self.expand_struct_def(cx, + struct_def, + item.ident, + generics) + } + ast::ItemEnum(ref enum_def, ref generics) => { + self.expand_enum_def(cx, + enum_def, + item.ident, + generics) + } + _ => return + }; + // Keep the lint attributes of the previous item to control how the + // generated implementations are linted + let mut attrs = newitem.attrs.clone(); + attrs.extend(item.attrs.iter().filter(|a| { + match a.name().get() { + "allow" | "warn" | "deny" | "forbid" => true, + _ => false, + } + }).map(|a| a.clone())); + push(@ast::Item { + attrs: attrs, + ..(*newitem).clone() + }) + } + + /** + * + * Given that we are deriving a trait `Tr` for a type `T<'a, ..., + * 'z, A, ..., Z>`, creates an impl like: + * + * ```ignore + * impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T { ... } + * ``` + * + * where B1, B2, ... are the bounds given by `bounds_paths`.' + * + */ + fn create_derived_impl(&self, + cx: &mut ExtCtxt, + type_ident: Ident, + generics: &Generics, + methods: Vec<@ast::Method> ) -> @ast::Item { + let trait_path = self.path.to_path(cx, self.span, type_ident, generics); + + let Generics { mut lifetimes, ty_params } = + self.generics.to_generics(cx, self.span, type_ident, generics); + let mut ty_params = ty_params.into_vec(); + + // Copy the lifetimes + lifetimes.extend(generics.lifetimes.iter().map(|l| *l)); + + // Create the type parameters. + ty_params.extend(generics.ty_params.iter().map(|ty_param| { + // I don't think this can be moved out of the loop, since + // a TyParamBound requires an ast id + let mut bounds: Vec<_> = + // extra restrictions on the generics parameters to the type being derived upon + self.additional_bounds.iter().map(|p| { + cx.typarambound(p.to_path(cx, self.span, + type_ident, generics)) + }).collect(); + // require the current trait + bounds.push(cx.typarambound(trait_path.clone())); + + cx.typaram(self.span, + ty_param.ident, + ty_param.sized, + OwnedSlice::from_vec(bounds), + None) + })); + let trait_generics = Generics { + lifetimes: lifetimes, + ty_params: OwnedSlice::from_vec(ty_params) + }; + + // Create the reference to the trait. + let trait_ref = cx.trait_ref(trait_path); + + // Create the type parameters on the `self` path. + let self_ty_params = generics.ty_params.map(|ty_param| { + cx.ty_ident(self.span, ty_param.ident) + }); + + let self_lifetimes = generics.lifetimes.clone(); + + // Create the type of `self`. + let self_type = cx.ty_path( + cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes, + self_ty_params.into_vec()), None); + + let attr = cx.attribute( + self.span, + cx.meta_word(self.span, + InternedString::new("automatically_derived"))); + let opt_trait_ref = Some(trait_ref); + let ident = ast_util::impl_pretty_name(&opt_trait_ref, self_type); + cx.item( + self.span, + ident, + (vec!(attr)).append(self.attributes.as_slice()), + ast::ItemImpl(trait_generics, opt_trait_ref, + self_type, methods)) + } + + fn expand_struct_def(&self, + cx: &mut ExtCtxt, + struct_def: &StructDef, + type_ident: Ident, + generics: &Generics) -> @ast::Item { + let methods = self.methods.iter().map(|method_def| { + let (explicit_self, self_args, nonself_args, tys) = + method_def.split_self_nonself_args( + cx, self, type_ident, generics); + + let body = if method_def.is_static() { + method_def.expand_static_struct_method_body( + cx, + self, + struct_def, + type_ident, + self_args.as_slice(), + nonself_args.as_slice()) + } else { + method_def.expand_struct_method_body(cx, + self, + struct_def, + type_ident, + self_args.as_slice(), + nonself_args.as_slice()) + }; + + method_def.create_method(cx, self, + type_ident, generics, + explicit_self, tys, + body) + }).collect(); + + self.create_derived_impl(cx, type_ident, generics, methods) + } + + fn expand_enum_def(&self, + cx: &mut ExtCtxt, + enum_def: &EnumDef, + type_ident: Ident, + generics: &Generics) -> @ast::Item { + let methods = self.methods.iter().map(|method_def| { + let (explicit_self, self_args, nonself_args, tys) = + method_def.split_self_nonself_args(cx, self, + type_ident, generics); + + let body = if method_def.is_static() { + method_def.expand_static_enum_method_body( + cx, + self, + enum_def, + type_ident, + self_args.as_slice(), + nonself_args.as_slice()) + } else { + method_def.expand_enum_method_body(cx, + self, + enum_def, + type_ident, + self_args.as_slice(), + nonself_args.as_slice()) + }; + + method_def.create_method(cx, self, + type_ident, generics, + explicit_self, tys, + body) + }).collect(); + + self.create_derived_impl(cx, type_ident, generics, methods) + } +} + +impl<'a> MethodDef<'a> { + fn call_substructure_method(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + type_ident: Ident, + self_args: &[@Expr], + nonself_args: &[@Expr], + fields: &SubstructureFields) + -> @Expr { + let substructure = Substructure { + type_ident: type_ident, + method_ident: cx.ident_of(self.name), + self_args: self_args, + nonself_args: nonself_args, + fields: fields + }; + let mut f = self.combine_substructure.borrow_mut(); + let f: &mut CombineSubstructureFunc = &mut *f; + (*f)(cx, trait_.span, &substructure) + } + + fn get_ret_ty(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + generics: &Generics, + type_ident: Ident) + -> P { + self.ret_ty.to_ty(cx, trait_.span, type_ident, generics) + } + + fn is_static(&self) -> bool { + self.explicit_self.is_none() + } + + fn split_self_nonself_args(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + type_ident: Ident, + generics: &Generics) + -> (ast::ExplicitSelf, Vec<@Expr> , Vec<@Expr> , Vec<(Ident, P)> ) { + + let mut self_args = Vec::new(); + let mut nonself_args = Vec::new(); + let mut arg_tys = Vec::new(); + let mut nonstatic = false; + + let ast_explicit_self = match self.explicit_self { + Some(ref self_ptr) => { + let (self_expr, explicit_self) = + ty::get_explicit_self(cx, trait_.span, self_ptr); + + self_args.push(self_expr); + nonstatic = true; + + explicit_self + } + None => codemap::respan(trait_.span, ast::SelfStatic), + }; + + for (i, ty) in self.args.iter().enumerate() { + let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics); + let ident = cx.ident_of(format!("__arg_{}", i)); + arg_tys.push((ident, ast_ty)); + + let arg_expr = cx.expr_ident(trait_.span, ident); + + match *ty { + // for static methods, just treat any Self + // arguments as a normal arg + Self if nonstatic => { + self_args.push(arg_expr); + } + Ptr(box Self, _) if 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: ast::ExplicitSelf, + arg_types: Vec<(Ident, P)> , + body: @Expr) -> @ast::Method { + // create the generics that aren't for Self + let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); + + let self_arg = match explicit_self.node { + ast::SelfStatic => None, + _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable)) + }; + let args = { + let args = arg_types.move_iter().map(|(name, ty)| { + cx.arg(trait_.span, name, ty) + }); + self_arg.move_iter().chain(args).collect() + }; + + let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); + + let method_ident = cx.ident_of(self.name); + let fn_decl = cx.fn_decl(args, ret_type); + let body_block = cx.block_expr(body); + + // Create the method. + @ast::Method { + ident: method_ident, + attrs: self.attributes.clone(), + generics: fn_generics, + explicit_self: explicit_self, + fn_style: ast::NormalFn, + decl: fn_decl, + body: body_block, + id: ast::DUMMY_NODE_ID, + span: trait_.span, + vis: ast::Inherited, + } + } + + /** + ~~~ + #[deriving(Eq)] + struct A { x: int, y: int } + + // equivalent to: + impl Eq for A { + fn eq(&self, __arg_1: &A) -> bool { + match *self { + A {x: ref __self_0_0, y: ref __self_0_1} => { + match *__arg_1 { + A {x: ref __self_1_0, y: ref __self_1_1} => { + __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1) + } + } + } + } + } + } + ~~~ + */ + fn expand_struct_method_body(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + struct_def: &StructDef, + type_ident: Ident, + self_args: &[@Expr], + nonself_args: &[@Expr]) + -> @Expr { + + let mut raw_fields = Vec::new(); // ~[[fields of self], + // [fields of next Self arg], [etc]] + let mut patterns = Vec::new(); + for i in range(0u, self_args.len()) { + let (pat, ident_expr) = trait_.create_struct_pattern(cx, type_ident, struct_def, + format!("__self_{}", i), + ast::MutImmutable); + patterns.push(pat); + raw_fields.push(ident_expr); + } + + // transpose raw_fields + let fields = if raw_fields.len() > 0 { + raw_fields.get(0) + .iter() + .enumerate() + .map(|(i, &(span, opt_id, field))| { + let other_fields = raw_fields.tail().iter().map(|l| { + match l.get(i) { + &(_, _, ex) => ex + } + }).collect(); + FieldInfo { + span: span, + name: opt_id, + self_: field, + other: other_fields + } + }).collect() + } else { + cx.span_bug(trait_.span, + "no self arguments to non-static method in generic \ + `deriving`") + }; + + // body of the inner most destructuring match + let mut body = self.call_substructure_method( + cx, + trait_, + type_ident, + self_args, + nonself_args, + &Struct(fields)); + + // make a series of nested matches, to destructure the + // structs. This is actually right-to-left, but it shoudn't + // matter. + for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) { + body = cx.expr_match(trait_.span, arg_expr, + vec!( cx.arm(trait_.span, vec!(pat), body) )) + } + body + } + + fn expand_static_struct_method_body(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + struct_def: &StructDef, + type_ident: Ident, + self_args: &[@Expr], + nonself_args: &[@Expr]) + -> @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)) + } + + /** + ~~~ + #[deriving(Eq)] + enum A { + A1 + A2(int) + } + + // is equivalent to (with const_nonmatching == false) + + impl Eq for A { + fn eq(&self, __arg_1: &A) { + match *self { + A1 => match *__arg_1 { + A1 => true + A2(ref __arg_1_1) => false + }, + A2(self_1) => match *__arg_1 { + A1 => false, + A2(ref __arg_1_1) => self_1.eq(__arg_1_1) + } + } + } + } + ~~~ + */ + fn expand_enum_method_body(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + enum_def: &EnumDef, + type_ident: Ident, + self_args: &[@Expr], + nonself_args: &[@Expr]) + -> @Expr { + let mut matches = Vec::new(); + self.build_enum_match(cx, trait_, enum_def, type_ident, + self_args, nonself_args, + None, &mut matches, 0) + } + + + /** + Creates the nested matches for an enum definition recursively, i.e. + + ~~~notrust + match self { + Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... }, + Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... }, + ... + } + ~~~ + + It acts in the most naive way, so every branch (and subbranch, + subsubbranch, etc) exists, not just the ones where all the variants in + the tree are the same. Hopefully the optimisers get rid of any + repetition, otherwise derived methods with many Self arguments will be + exponentially large. + + `matching` is Some(n) if all branches in the tree above the + current position are variant `n`, `None` otherwise (including on + the first call). + */ + fn build_enum_match(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + enum_def: &EnumDef, + type_ident: Ident, + self_args: &[@Expr], + nonself_args: &[@Expr], + matching: Option, + matches_so_far: &mut Vec<(uint, P, + Vec<(Span, Option, @Expr)> )> , + match_count: uint) -> @Expr { + if match_count == self_args.len() { + // we've matched against all arguments, so make the final + // expression at the bottom of the match tree + if matches_so_far.len() == 0 { + cx.span_bug(trait_.span, + "no self match on an enum in \ + generic `deriving`"); + } + + // `ref` inside let matches is buggy. Causes havoc wih rusc. + // let (variant_index, ref self_vec) = matches_so_far[0]; + let (variant, self_vec) = match matches_so_far.get(0) { + &(_, v, ref s) => (v, s) + }; + + // we currently have a vec of vecs, where each + // subvec is the fields of one of the arguments, + // but if the variants all match, we want this as + // vec of tuples, where each tuple represents a + // field. + + // most arms don't have matching variants, so do a + // quick check to see if they match (even though + // this means iterating twice) instead of being + // optimistic and doing a pile of allocations etc. + let substructure = match matching { + Some(variant_index) => { + let mut enum_matching_fields = Vec::from_elem(self_vec.len(), Vec::new()); + + for triple in matches_so_far.tail().iter() { + match triple { + &(_, _, ref other_fields) => { + for (i, &(_, _, e)) in other_fields.iter().enumerate() { + enum_matching_fields.get_mut(i).push(e); + } + } + } + } + let field_tuples = + self_vec.iter() + .zip(enum_matching_fields.iter()) + .map(|(&(span, id, self_f), other)| { + FieldInfo { + span: span, + name: id, + self_: self_f, + other: (*other).clone() + } + }).collect(); + EnumMatching(variant_index, variant, field_tuples) + } + None => { + EnumNonMatching(matches_so_far.as_slice()) + } + }; + self.call_substructure_method(cx, trait_, type_ident, + self_args, nonself_args, + &substructure) + + } else { // there are still matches to create + let current_match_str = if match_count == 0 { + "__self".to_owned() + } else { + format!("__arg_{}", match_count) + }; + + let mut arms = Vec::new(); + + // the code for nonmatching variants only matters when + // we've seen at least one other variant already + if self.const_nonmatching && match_count > 0 { + // make a matching-variant match, and a _ match. + let index = match matching { + Some(i) => i, + None => cx.span_bug(trait_.span, + "non-matching variants when required to \ + be matching in generic `deriving`") + }; + + // matching-variant match + let variant = *enum_def.variants.get(index); + let (pattern, idents) = trait_.create_enum_variant_pattern(cx, + variant, + current_match_str, + ast::MutImmutable); + + matches_so_far.push((index, variant, idents)); + let arm_expr = self.build_enum_match(cx, + trait_, + enum_def, + type_ident, + self_args, nonself_args, + matching, + matches_so_far, + match_count + 1); + matches_so_far.pop().unwrap(); + arms.push(cx.arm(trait_.span, vec!( pattern ), arm_expr)); + + if enum_def.variants.len() > 1 { + let e = &EnumNonMatching(&[]); + let wild_expr = self.call_substructure_method(cx, trait_, type_ident, + self_args, nonself_args, + e); + let wild_arm = cx.arm( + trait_.span, + vec!( cx.pat_wild(trait_.span) ), + wild_expr); + arms.push(wild_arm); + } + } else { + // create an arm matching on each variant + for (index, &variant) in enum_def.variants.iter().enumerate() { + let (pattern, idents) = trait_.create_enum_variant_pattern(cx, + variant, + current_match_str, + ast::MutImmutable); + + matches_so_far.push((index, variant, idents)); + let new_matching = + match matching { + _ if match_count == 0 => Some(index), + Some(i) if index == i => Some(i), + _ => None + }; + let arm_expr = self.build_enum_match(cx, + trait_, + enum_def, + type_ident, + self_args, nonself_args, + new_matching, + matches_so_far, + match_count + 1); + matches_so_far.pop().unwrap(); + + let arm = cx.arm(trait_.span, vec!( pattern ), arm_expr); + arms.push(arm); + } + } + + // match foo { arm, arm, arm, ... } + cx.expr_match(trait_.span, self_args[match_count], arms) + } + } + + fn expand_static_enum_method_body(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + enum_def: &EnumDef, + type_ident: Ident, + self_args: &[@Expr], + nonself_args: &[@Expr]) + -> @Expr { + let summary = enum_def.variants.iter().map(|v| { + let ident = v.node.name; + let summary = match v.node.kind { + ast::TupleVariantKind(ref args) => { + Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect()) + } + ast::StructVariantKind(struct_def) => { + trait_.summarise_struct(cx, struct_def) + } + }; + (ident, v.span, summary) + }).collect(); + self.call_substructure_method(cx, trait_, type_ident, + self_args, nonself_args, + &StaticEnum(enum_def, summary)) + } +} + +#[deriving(Eq)] // dogfooding! +enum StructType { + Unknown, Record, Tuple +} + +// general helper methods. +impl<'a> TraitDef<'a> { + fn set_expn_info(&self, + cx: &mut ExtCtxt, + mut to_set: Span) -> Span { + let trait_name = match self.path.path.last() { + None => cx.span_bug(self.span, "trait with empty path in generic `deriving`"), + Some(name) => *name + }; + to_set.expn_info = Some(@codemap::ExpnInfo { + call_site: to_set, + callee: codemap::NameAndSpan { + name: format!("deriving({})", trait_name).to_strbuf(), + format: codemap::MacroAttribute, + span: Some(self.span) + } + }); + to_set + } + + fn summarise_struct(&self, + cx: &mut ExtCtxt, + struct_def: &StructDef) -> StaticFields { + let mut named_idents = Vec::new(); + let mut just_spans = Vec::new(); + for field in struct_def.fields.iter(){ + let sp = self.set_expn_info(cx, field.span); + match field.node.kind { + ast::NamedField(ident, _) => named_idents.push((ident, sp)), + ast::UnnamedField(..) => just_spans.push(sp), + } + } + + match (just_spans.is_empty(), named_idents.is_empty()) { + (false, false) => cx.span_bug(self.span, + "a struct with named and unnamed \ + fields in generic `deriving`"), + // named fields + (_, false) => Named(named_idents), + // tuple structs (includes empty structs) + (_, _) => Unnamed(just_spans) + } + } + + fn create_subpatterns(&self, + cx: &mut ExtCtxt, + field_paths: Vec , + mutbl: ast::Mutability) + -> Vec<@ast::Pat> { + field_paths.iter().map(|path| { + cx.pat(path.span, + ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None)) + }).collect() + } + + fn create_struct_pattern(&self, + cx: &mut ExtCtxt, + struct_ident: Ident, + struct_def: &StructDef, + prefix: &str, + mutbl: ast::Mutability) + -> (@ast::Pat, Vec<(Span, Option, @Expr)> ) { + if struct_def.fields.is_empty() { + return ( + cx.pat_ident_binding_mode( + self.span, struct_ident, ast::BindByValue(ast::MutImmutable)), + Vec::new()); + } + + let matching_path = cx.path(self.span, vec!( struct_ident )); + + let mut paths = Vec::new(); + let mut ident_expr = Vec::new(); + let mut struct_type = Unknown; + + for (i, struct_field) in struct_def.fields.iter().enumerate() { + let sp = self.set_expn_info(cx, struct_field.span); + let opt_id = match struct_field.node.kind { + ast::NamedField(ident, _) if (struct_type == Unknown || + struct_type == Record) => { + struct_type = Record; + Some(ident) + } + ast::UnnamedField(..) if (struct_type == Unknown || + struct_type == Tuple) => { + struct_type = Tuple; + None + } + _ => { + cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`"); + } + }; + let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i))); + paths.push(path.clone()); + let val = cx.expr( + sp, ast::ExprParen( + cx.expr_deref(sp, cx.expr_path(path)))); + ident_expr.push((sp, opt_id, val)); + } + + let subpats = self.create_subpatterns(cx, paths, mutbl); + + // struct_type is definitely not Unknown, since struct_def.fields + // must be nonempty to reach here + let pattern = if struct_type == Record { + let field_pats = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _))| { + // id is guaranteed to be Some + ast::FieldPat { ident: id.unwrap(), pat: pat } + }).collect(); + cx.pat_struct(self.span, matching_path, field_pats) + } else { + cx.pat_enum(self.span, matching_path, subpats) + }; + + (pattern, ident_expr) + } + + fn create_enum_variant_pattern(&self, + cx: &mut ExtCtxt, + variant: &ast::Variant, + prefix: &str, + mutbl: ast::Mutability) + -> (@ast::Pat, Vec<(Span, Option, @Expr)> ) { + let variant_ident = variant.node.name; + match variant.node.kind { + ast::TupleVariantKind(ref variant_args) => { + if variant_args.is_empty() { + return (cx.pat_ident_binding_mode(variant.span, variant_ident, + ast::BindByValue(ast::MutImmutable)), + Vec::new()); + } + + let matching_path = cx.path_ident(variant.span, variant_ident); + + let mut paths = Vec::new(); + let mut ident_expr = Vec::new(); + for (i, va) in variant_args.iter().enumerate() { + let sp = self.set_expn_info(cx, va.ty.span); + let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i))); + + paths.push(path.clone()); + let val = cx.expr( + sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path)))); + ident_expr.push((sp, None, val)); + } + + let subpats = self.create_subpatterns(cx, paths, mutbl); + + (cx.pat_enum(variant.span, matching_path, subpats), + ident_expr) + } + ast::StructVariantKind(struct_def) => { + self.create_struct_pattern(cx, variant_ident, struct_def, + prefix, mutbl) + } + } + } +} + +/* helpful premade recipes */ + +/** +Fold the fields. `use_foldl` controls whether this is done +left-to-right (`true`) or right-to-left (`false`). +*/ +pub fn cs_fold(use_foldl: bool, + f: |&mut ExtCtxt, Span, @Expr, @Expr, &[@Expr]| -> @Expr, + base: @Expr, + enum_nonmatch_f: EnumNonMatchFunc, + cx: &mut ExtCtxt, + trait_span: Span, + substructure: &Substructure) + -> @Expr { + match *substructure.fields { + EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { + if use_foldl { + all_fields.iter().fold(base, |old, field| { + f(cx, + field.span, + old, + field.self_, + field.other.as_slice()) + }) + } else { + all_fields.iter().rev().fold(base, |old, field| { + f(cx, + field.span, + old, + field.self_, + field.other.as_slice()) + }) + } + }, + EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span, + *all_enums, + substructure.nonself_args), + StaticEnum(..) | StaticStruct(..) => { + cx.span_bug(trait_span, "static function in `deriving`") + } + } +} + + +/** +Call the method that is being derived on all the fields, and then +process the collected results. i.e. + +~~~ +f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1), + self_2.method(__arg_1_2, __arg_2_2)]) +~~~ +*/ +#[inline] +pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<@Expr> | -> @Expr, + enum_nonmatch_f: EnumNonMatchFunc, + cx: &mut ExtCtxt, + trait_span: Span, + substructure: &Substructure) + -> @Expr { + match *substructure.fields { + EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { + // call self_n.method(other_1_n, other_2_n, ...) + let called = all_fields.iter().map(|field| { + cx.expr_method_call(field.span, + field.self_, + substructure.method_ident, + field.other.iter() + .map(|e| cx.expr_addr_of(field.span, *e)) + .collect()) + }).collect(); + + f(cx, trait_span, called) + }, + EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span, + *all_enums, + substructure.nonself_args), + StaticEnum(..) | StaticStruct(..) => { + cx.span_bug(trait_span, "static function in `deriving`") + } + } +} + +/** +Fold together the results of calling the derived method on all the +fields. `use_foldl` controls whether this is done left-to-right +(`true`) or right-to-left (`false`). +*/ +#[inline] +pub fn cs_same_method_fold(use_foldl: bool, + f: |&mut ExtCtxt, Span, @Expr, @Expr| -> @Expr, + base: @Expr, + enum_nonmatch_f: EnumNonMatchFunc, + cx: &mut ExtCtxt, + trait_span: Span, + substructure: &Substructure) + -> @Expr { + cs_same_method( + |cx, span, vals| { + if use_foldl { + vals.iter().fold(base, |old, &new| { + f(cx, span, old, new) + }) + } else { + vals.iter().rev().fold(base, |old, &new| { + f(cx, span, old, new) + }) + } + }, + enum_nonmatch_f, + cx, trait_span, substructure) +} + +/** +Use a given binop to combine the result of calling the derived method +on all the fields. +*/ +#[inline] +pub fn cs_binop(binop: ast::BinOp, base: @Expr, + enum_nonmatch_f: EnumNonMatchFunc, + cx: &mut ExtCtxt, trait_span: Span, + substructure: &Substructure) -> @Expr { + cs_same_method_fold( + true, // foldl is good enough + |cx, span, old, new| { + cx.expr_binary(span, + binop, + old, new) + + }, + base, + enum_nonmatch_f, + cx, trait_span, substructure) +} + +/// cs_binop with binop == or +#[inline] +pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc, + cx: &mut ExtCtxt, span: Span, + substructure: &Substructure) -> @Expr { + cs_binop(ast::BiOr, cx.expr_bool(span, false), + enum_nonmatch_f, + cx, span, substructure) +} + +/// cs_binop with binop == and +#[inline] +pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc, + cx: &mut ExtCtxt, span: Span, + substructure: &Substructure) -> @Expr { + cs_binop(ast::BiAnd, cx.expr_bool(span, true), + enum_nonmatch_f, + cx, span, substructure) +} diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs new file mode 100644 index 00000000000..602245b4c47 --- /dev/null +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -0,0 +1,267 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +A mini version of ast::Ty, which is easier to use, and features an +explicit `Self` type to use when specifying impls to be derived. +*/ + +use ast; +use ast::{P,Expr,Generics,Ident}; +use ext::base::ExtCtxt; +use ext::build::AstBuilder; +use codemap::{Span,respan}; +use owned_slice::OwnedSlice; + + +/// The types of pointers +pub enum PtrTy<'a> { + Send, // ~ + Borrowed(Option<&'a str>, ast::Mutability), // &['lifetime] [mut] +} + +/// A path, e.g. `::std::option::Option::` (global). Has support +/// for type parameters and a lifetime. +pub struct Path<'a> { + pub path: Vec<&'a str> , + pub lifetime: Option<&'a str>, + pub params: Vec>>, + pub global: bool, +} + +impl<'a> Path<'a> { + pub fn new<'r>(path: Vec<&'r str> ) -> Path<'r> { + Path::new_(path, None, Vec::new(), true) + } + pub fn new_local<'r>(path: &'r str) -> Path<'r> { + Path::new_(vec!( path ), None, Vec::new(), false) + } + pub fn new_<'r>(path: Vec<&'r str> , + lifetime: Option<&'r str>, + params: Vec>>, + global: bool) + -> Path<'r> { + Path { + path: path, + lifetime: lifetime, + params: params, + global: global + } + } + + pub fn to_ty(&self, + cx: &ExtCtxt, + span: Span, + self_ty: Ident, + self_generics: &Generics) + -> P { + cx.ty_path(self.to_path(cx, span, self_ty, self_generics), None) + } + pub fn to_path(&self, + cx: &ExtCtxt, + span: Span, + self_ty: Ident, + self_generics: &Generics) + -> ast::Path { + let idents = self.path.iter().map(|s| cx.ident_of(*s)).collect(); + let lt = mk_lifetimes(cx, span, &self.lifetime); + let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); + + cx.path_all(span, self.global, idents, lt, tys) + } +} + +/// A type. Supports pointers (except for *), Self, and literals +pub enum Ty<'a> { + Self, + // &/Box/@ Ty + Ptr(Box>, PtrTy<'a>), + // mod::mod::Type<[lifetime], [Params...]>, including a plain type + // parameter, and things like `int` + Literal(Path<'a>), + // includes nil + Tuple(Vec> ) +} + +pub fn borrowed_ptrty<'r>() -> PtrTy<'r> { + Borrowed(None, ast::MutImmutable) +} +pub fn borrowed<'r>(ty: Box>) -> Ty<'r> { + Ptr(ty, borrowed_ptrty()) +} + +pub fn borrowed_explicit_self<'r>() -> Option>> { + Some(Some(borrowed_ptrty())) +} + +pub fn borrowed_self<'r>() -> Ty<'r> { + borrowed(box Self) +} + +pub fn nil_ty() -> Ty<'static> { + Tuple(Vec::new()) +} + +fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option { + match *lt { + Some(ref s) => Some(cx.lifetime(span, cx.ident_of(*s).name)), + None => None + } +} + +fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec { + match *lt { + Some(ref s) => vec!(cx.lifetime(span, cx.ident_of(*s).name)), + None => vec!() + } +} + +impl<'a> Ty<'a> { + pub fn to_ty(&self, + cx: &ExtCtxt, + span: Span, + self_ty: Ident, + self_generics: &Generics) + -> P { + match *self { + Ptr(ref ty, ref ptr) => { + let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); + match *ptr { + Send => { + cx.ty_uniq(span, raw_ty) + } + Borrowed(ref lt, mutbl) => { + let lt = mk_lifetime(cx, span, lt); + cx.ty_rptr(span, raw_ty, lt, 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), None) + } + Tuple(ref fields) => { + let ty = if fields.is_empty() { + ast::TyNil + } else { + ast::TyTup(fields.iter() + .map(|f| f.to_ty(cx, span, self_ty, self_generics)) + .collect()) + }; + + cx.ty(span, ty) + } + } + } + + pub fn to_path(&self, + cx: &ExtCtxt, + span: Span, + self_ty: Ident, + self_generics: &Generics) + -> ast::Path { + match *self { + Self => { + let self_params = self_generics.ty_params.map(|ty_param| { + cx.ty_ident(span, ty_param.ident) + }); + let lifetimes = self_generics.lifetimes.clone(); + + cx.path_all(span, false, vec!(self_ty), lifetimes, + self_params.into_vec()) + } + Literal(ref p) => { + p.to_path(cx, span, self_ty, self_generics) + } + Ptr(..) => { cx.span_bug(span, "pointer in a path in generic `deriving`") } + Tuple(..) => { cx.span_bug(span, "tuple in a path in generic `deriving`") } + } + } +} + + +fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, sized: ast::Sized, bounds: &[Path], + self_ident: Ident, self_generics: &Generics) -> ast::TyParam { + let bounds = + bounds.iter().map(|b| { + let path = b.to_path(cx, span, self_ident, self_generics); + cx.typarambound(path) + }).collect(); + cx.typaram(span, cx.ident_of(name), sized, bounds, None) +} + +fn mk_generics(lifetimes: Vec , ty_params: Vec ) -> Generics { + Generics { + lifetimes: lifetimes, + ty_params: OwnedSlice::from_vec(ty_params) + } +} + +/// Lifetimes and bounds on type parameters +pub struct LifetimeBounds<'a> { + pub lifetimes: Vec<&'a str>, + pub bounds: Vec<(&'a str, ast::Sized, Vec>)>, +} + +impl<'a> LifetimeBounds<'a> { + pub fn empty() -> LifetimeBounds<'static> { + LifetimeBounds { + lifetimes: Vec::new(), bounds: Vec::new() + } + } + pub fn to_generics(&self, + cx: &ExtCtxt, + span: Span, + self_ty: Ident, + self_generics: &Generics) + -> Generics { + let lifetimes = self.lifetimes.iter().map(|lt| { + cx.lifetime(span, cx.ident_of(*lt).name) + }).collect(); + let ty_params = self.bounds.iter().map(|t| { + match t { + &(ref name, sized, ref bounds) => { + mk_ty_param(cx, + span, + *name, + sized, + bounds.as_slice(), + self_ty, + self_generics) + } + } + }).collect(); + mk_generics(lifetimes, ty_params) + } +} + + +pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option) + -> (@Expr, ast::ExplicitSelf) { + let self_path = cx.expr_self(span); + match *self_ptr { + None => { + (self_path, respan(span, ast::SelfValue)) + } + Some(ref ptr) => { + let self_ty = respan( + span, + match *ptr { + Send => ast::SelfUniq, + Borrowed(ref lt, mutbl) => { + let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name)); + ast::SelfRegion(lt, mutbl) + } + }); + let self_expr = cx.expr_deref(span, self_path); + (self_expr, self_ty) + } + } +} diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs deleted file mode 100644 index 602245b4c47..00000000000 --- a/src/libsyntax/ext/deriving/ty.rs +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -A mini version of ast::Ty, which is easier to use, and features an -explicit `Self` type to use when specifying impls to be derived. -*/ - -use ast; -use ast::{P,Expr,Generics,Ident}; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use codemap::{Span,respan}; -use owned_slice::OwnedSlice; - - -/// The types of pointers -pub enum PtrTy<'a> { - Send, // ~ - Borrowed(Option<&'a str>, ast::Mutability), // &['lifetime] [mut] -} - -/// A path, e.g. `::std::option::Option::` (global). Has support -/// for type parameters and a lifetime. -pub struct Path<'a> { - pub path: Vec<&'a str> , - pub lifetime: Option<&'a str>, - pub params: Vec>>, - pub global: bool, -} - -impl<'a> Path<'a> { - pub fn new<'r>(path: Vec<&'r str> ) -> Path<'r> { - Path::new_(path, None, Vec::new(), true) - } - pub fn new_local<'r>(path: &'r str) -> Path<'r> { - Path::new_(vec!( path ), None, Vec::new(), false) - } - pub fn new_<'r>(path: Vec<&'r str> , - lifetime: Option<&'r str>, - params: Vec>>, - global: bool) - -> Path<'r> { - Path { - path: path, - lifetime: lifetime, - params: params, - global: global - } - } - - pub fn to_ty(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> P { - cx.ty_path(self.to_path(cx, span, self_ty, self_generics), None) - } - pub fn to_path(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> ast::Path { - let idents = self.path.iter().map(|s| cx.ident_of(*s)).collect(); - let lt = mk_lifetimes(cx, span, &self.lifetime); - let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); - - cx.path_all(span, self.global, idents, lt, tys) - } -} - -/// A type. Supports pointers (except for *), Self, and literals -pub enum Ty<'a> { - Self, - // &/Box/@ Ty - Ptr(Box>, PtrTy<'a>), - // mod::mod::Type<[lifetime], [Params...]>, including a plain type - // parameter, and things like `int` - Literal(Path<'a>), - // includes nil - Tuple(Vec> ) -} - -pub fn borrowed_ptrty<'r>() -> PtrTy<'r> { - Borrowed(None, ast::MutImmutable) -} -pub fn borrowed<'r>(ty: Box>) -> Ty<'r> { - Ptr(ty, borrowed_ptrty()) -} - -pub fn borrowed_explicit_self<'r>() -> Option>> { - Some(Some(borrowed_ptrty())) -} - -pub fn borrowed_self<'r>() -> Ty<'r> { - borrowed(box Self) -} - -pub fn nil_ty() -> Ty<'static> { - Tuple(Vec::new()) -} - -fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option { - match *lt { - Some(ref s) => Some(cx.lifetime(span, cx.ident_of(*s).name)), - None => None - } -} - -fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec { - match *lt { - Some(ref s) => vec!(cx.lifetime(span, cx.ident_of(*s).name)), - None => vec!() - } -} - -impl<'a> Ty<'a> { - pub fn to_ty(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> P { - match *self { - Ptr(ref ty, ref ptr) => { - let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); - match *ptr { - Send => { - cx.ty_uniq(span, raw_ty) - } - Borrowed(ref lt, mutbl) => { - let lt = mk_lifetime(cx, span, lt); - cx.ty_rptr(span, raw_ty, lt, 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), None) - } - Tuple(ref fields) => { - let ty = if fields.is_empty() { - ast::TyNil - } else { - ast::TyTup(fields.iter() - .map(|f| f.to_ty(cx, span, self_ty, self_generics)) - .collect()) - }; - - cx.ty(span, ty) - } - } - } - - pub fn to_path(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> ast::Path { - match *self { - Self => { - let self_params = self_generics.ty_params.map(|ty_param| { - cx.ty_ident(span, ty_param.ident) - }); - let lifetimes = self_generics.lifetimes.clone(); - - cx.path_all(span, false, vec!(self_ty), lifetimes, - self_params.into_vec()) - } - Literal(ref p) => { - p.to_path(cx, span, self_ty, self_generics) - } - Ptr(..) => { cx.span_bug(span, "pointer in a path in generic `deriving`") } - Tuple(..) => { cx.span_bug(span, "tuple in a path in generic `deriving`") } - } - } -} - - -fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, sized: ast::Sized, bounds: &[Path], - self_ident: Ident, self_generics: &Generics) -> ast::TyParam { - let bounds = - bounds.iter().map(|b| { - let path = b.to_path(cx, span, self_ident, self_generics); - cx.typarambound(path) - }).collect(); - cx.typaram(span, cx.ident_of(name), sized, bounds, None) -} - -fn mk_generics(lifetimes: Vec , ty_params: Vec ) -> Generics { - Generics { - lifetimes: lifetimes, - ty_params: OwnedSlice::from_vec(ty_params) - } -} - -/// Lifetimes and bounds on type parameters -pub struct LifetimeBounds<'a> { - pub lifetimes: Vec<&'a str>, - pub bounds: Vec<(&'a str, ast::Sized, Vec>)>, -} - -impl<'a> LifetimeBounds<'a> { - pub fn empty() -> LifetimeBounds<'static> { - LifetimeBounds { - lifetimes: Vec::new(), bounds: Vec::new() - } - } - pub fn to_generics(&self, - cx: &ExtCtxt, - span: Span, - self_ty: Ident, - self_generics: &Generics) - -> Generics { - let lifetimes = self.lifetimes.iter().map(|lt| { - cx.lifetime(span, cx.ident_of(*lt).name) - }).collect(); - let ty_params = self.bounds.iter().map(|t| { - match t { - &(ref name, sized, ref bounds) => { - mk_ty_param(cx, - span, - *name, - sized, - bounds.as_slice(), - self_ty, - self_generics) - } - } - }).collect(); - mk_generics(lifetimes, ty_params) - } -} - - -pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option) - -> (@Expr, ast::ExplicitSelf) { - let self_path = cx.expr_self(span); - match *self_ptr { - None => { - (self_path, respan(span, ast::SelfValue)) - } - Some(ref ptr) => { - let self_ty = respan( - span, - match *ptr { - Send => ast::SelfUniq, - Borrowed(ref lt, mutbl) => { - let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name)); - ast::SelfRegion(lt, mutbl) - } - }); - let self_expr = cx.expr_deref(span, self_path); - (self_expr, self_ty) - } - } -} diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 6e7e72bd2e8..6bc08741c07 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -95,6 +95,8 @@ pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) &res_rel_file(cx, sp, &Path::new(file)), + true, + None, sp); base::MacExpr::new(p.parse_expr()) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index d8a9f69e293..8e139b049c5 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -184,8 +184,13 @@ pub fn new_parser_from_file<'a>(sess: &'a ParseSess, pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, cfg: ast::CrateConfig, path: &Path, + owns_directory: bool, + module_name: Option, sp: Span) -> Parser<'a> { - filemap_to_parser(sess, file_to_filemap(sess, path, Some(sp)), cfg) + let mut p = filemap_to_parser(sess, file_to_filemap(sess, path, Some(sp)), cfg); + p.owns_directory = owns_directory; + p.root_module_name = module_name; + p } /// Given a filemap and config, return a parser diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 92e5f8da6aa..c42febcd607 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -313,6 +313,8 @@ pub fn Parser<'a>( obsolete_set: HashSet::new(), mod_path_stack: Vec::new(), open_braces: Vec::new(), + owns_directory: true, + root_module_name: None, } } @@ -342,6 +344,13 @@ pub struct Parser<'a> { pub mod_path_stack: Vec, /// Stack of spans of open delimiters. Used for error message. pub open_braces: Vec, + /// Flag if this parser "owns" the directory that it is currently parsing + /// in. This will affect how nested files are looked up. + pub owns_directory: bool, + /// Name of the root module this parser originated from. If `None`, then the + /// name is not known. This does not change while the parser is descending + /// into modules, and sub-parsers have new values for this name. + pub root_module_name: Option, } fn is_plain_ident_or_underscore(t: &token::Token) -> bool { @@ -4179,9 +4188,12 @@ impl<'a> Parser<'a> { self.push_mod_path(id, outer_attrs); self.expect(&token::LBRACE); let mod_inner_lo = self.span.lo; + let old_owns_directory = self.owns_directory; + self.owns_directory = true; let (inner, next) = self.parse_inner_attrs_and_next(); let m = self.parse_mod_items(token::RBRACE, next, mod_inner_lo); self.expect(&token::RBRACE); + self.owns_directory = old_owns_directory; self.pop_mod_path(); (id, ItemMod(m), Some(inner)) } @@ -4211,11 +4223,11 @@ impl<'a> Parser<'a> { prefix.pop(); let mod_path = Path::new(".").join_many(self.mod_path_stack.as_slice()); let dir_path = prefix.join(&mod_path); - let file_path = match ::attr::first_attr_value_str_by_name( + let mod_string = token::get_ident(id); + let (file_path, owns_directory) = match ::attr::first_attr_value_str_by_name( outer_attrs, "path") { - Some(d) => dir_path.join(d), + Some(d) => (dir_path.join(d), true), None => { - let mod_string = token::get_ident(id); let mod_name = mod_string.get().to_owned(); let default_path_str = mod_name + ".rs"; let secondary_path_str = mod_name + "/mod.rs"; @@ -4223,9 +4235,30 @@ impl<'a> Parser<'a> { let secondary_path = dir_path.join(secondary_path_str.as_slice()); let default_exists = default_path.exists(); let secondary_exists = secondary_path.exists(); + + if !self.owns_directory { + self.span_err(id_sp, + "cannot declare a new module at this location"); + let this_module = match self.mod_path_stack.last() { + Some(name) => name.get().to_strbuf(), + None => self.root_module_name.get_ref().clone(), + }; + self.span_note(id_sp, + format!("maybe move this module `{0}` \ + to its own directory via \ + `{0}/mod.rs`", this_module)); + if default_exists || secondary_exists { + self.span_note(id_sp, + format!("... or maybe `use` the module \ + `{}` instead of possibly \ + redeclaring it", mod_name)); + } + self.abort_if_errors(); + } + match (default_exists, secondary_exists) { - (true, false) => default_path, - (false, true) => secondary_path, + (true, false) => (default_path, false), + (false, true) => (secondary_path, true), (false, false) => { self.span_fatal(id_sp, format!("file not found for module `{}`", mod_name)); } @@ -4238,11 +4271,14 @@ impl<'a> Parser<'a> { } }; - self.eval_src_mod_from_path(file_path, id_sp) + self.eval_src_mod_from_path(file_path, owns_directory, + mod_string.get().to_strbuf(), id_sp) } fn eval_src_mod_from_path(&mut self, path: Path, + owns_directory: bool, + name: StrBuf, id_sp: Span) -> (ast::Item_, Vec ) { let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut(); match included_mod_stack.iter().position(|p| *p == path) { @@ -4265,6 +4301,8 @@ impl<'a> Parser<'a> { new_sub_parser_from_file(self.sess, self.cfg.clone(), &path, + owns_directory, + Some(name), id_sp); let mod_inner_lo = p0.span.lo; let (mod_attrs, next) = p0.parse_inner_attrs_and_next(); -- cgit 1.4.1-3-g733a5