Skip to content

Commit 0fb03c5

Browse files
committed
Implement clone_from via #[derive(Clone)], fixes rust-lang#13281
1 parent 8f1b0aa commit 0fb03c5

File tree

3 files changed

+102
-41
lines changed

3 files changed

+102
-41
lines changed

src/libsyntax/ext/deriving/clone.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use ast;
1112
use ast::{MetaItem, Expr};
1213
use codemap::Span;
1314
use ext::base::{ExtCtxt, Annotatable};
@@ -38,11 +39,23 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
3839
explicit_self: borrowed_explicit_self(),
3940
args: Vec::new(),
4041
ret_ty: Self_,
41-
attributes: attrs,
42+
attributes: attrs.clone(),
4243
is_unsafe: false,
4344
combine_substructure: combine_substructure(Box::new(|c, s, sub| {
4445
cs_clone("Clone", c, s, sub)
4546
})),
47+
},
48+
MethodDef {
49+
name: "clone_from",
50+
generics: LifetimeBounds::empty(),
51+
explicit_self: borrowed_mut_explicit_self(),
52+
args: vec![borrowed_self()],
53+
ret_ty: nil_ty(),
54+
attributes: attrs,
55+
is_unsafe: false,
56+
combine_substructure: combine_substructure(Box::new(|c, s, sub| {
57+
cs_clone_from("Clone", c, s, sub)
58+
})),
4659
}
4760
),
4861
associated_types: Vec::new(),
@@ -111,3 +124,29 @@ fn cs_clone(
111124
}
112125
}
113126
}
127+
128+
fn cs_clone_from(
129+
name: &str,
130+
cx: &mut ExtCtxt, span: Span,
131+
substr: &Substructure) -> P<Expr> {
132+
133+
cs_same_method(
134+
|cx, span, exprs| {
135+
cx.expr_block(cx.block(span, exprs.into_iter().map(|expr| {
136+
cx.stmt_expr(expr)
137+
}).collect(), None))
138+
},
139+
Box::new(|cx, span, (self_args, _), _non_self_args| {
140+
if self_args.len() != 2 {
141+
cx.span_bug(span, &format!("not exactly 2 arguments in `derive({})`", name))
142+
} else {
143+
let clone_path = cx.std_path(&["clone", "Clone", "clone"]);
144+
let args = vec![cx.expr_addr_of(span, self_args[1].clone())];
145+
146+
let rhs = cx.expr_call_global(span, clone_path, args);
147+
let lhs = self_args[0].clone();
148+
cx.expr(span, ast::ExprAssign(lhs, rhs))
149+
}
150+
}),
151+
cx, span, substr)
152+
}

src/libsyntax/ext/deriving/generic/mod.rs

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@
155155
//!
156156
//! ```{.text}
157157
//! EnumNonMatchingCollapsed(
158-
//! vec![<ident of self>, <ident of __arg_1>],
158+
//! vec![<ast::Expr for self>, <ast::Expr for __arg_1>],
159159
//! &[<ast::Variant for C0>, <ast::Variant for C1>],
160160
//! &[<ident for self index value>, <ident of __arg_1 index value>])
161161
//! ```
@@ -203,7 +203,6 @@ use ext::build::AstBuilder;
203203
use codemap::{self, DUMMY_SP};
204204
use codemap::Span;
205205
use diagnostic::SpanHandler;
206-
use fold::MoveMap;
207206
use owned_slice::OwnedSlice;
208207
use parse::token::InternedString;
209208
use parse::token::special_idents;
@@ -267,7 +266,7 @@ pub struct Substructure<'a> {
267266
/// ident of the method
268267
pub method_ident: Ident,
269268
/// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments
270-
pub self_args: &'a [P<Expr>],
269+
pub self_args: &'a [(P<Expr>, ast::Mutability)],
271270
/// verbatim access to any other arguments
272271
pub nonself_args: &'a [P<Expr>],
273272
pub fields: &'a SubstructureFields<'a>
@@ -311,7 +310,7 @@ pub enum SubstructureFields<'a> {
311310
/// variants for the enum itself, and the third component is a list of
312311
/// `Ident`s bound to the variant index values for each of the actual
313312
/// input `Self` arguments.
314-
EnumNonMatchingCollapsed(Vec<Ident>, &'a [P<ast::Variant>], &'a [Ident]),
313+
EnumNonMatchingCollapsed(Vec<P<ast::Expr>>, &'a [P<ast::Variant>], &'a [Ident]),
315314

316315
/// A static method where `Self` is a struct.
317316
StaticStruct(&'a ast::StructDef, StaticFields),
@@ -332,7 +331,7 @@ pub type CombineSubstructureFunc<'a> =
332331
/// holding the variant index value for each of the `Self` arguments. The
333332
/// last argument is all the non-`Self` args of the method being derived.
334333
pub type EnumNonMatchCollapsedFunc<'a> =
335-
Box<FnMut(&mut ExtCtxt, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
334+
Box<FnMut(&mut ExtCtxt, Span, (&[P<Expr>], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
336335

337336
pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
338337
-> RefCell<CombineSubstructureFunc<'a>> {
@@ -764,7 +763,7 @@ impl<'a> MethodDef<'a> {
764763
cx: &mut ExtCtxt,
765764
trait_: &TraitDef,
766765
type_ident: Ident,
767-
self_args: &[P<Expr>],
766+
self_args: &[(P<Expr>, ast::Mutability)],
768767
nonself_args: &[P<Expr>],
769768
fields: &SubstructureFields)
770769
-> P<Expr> {
@@ -798,7 +797,7 @@ impl<'a> MethodDef<'a> {
798797
trait_: &TraitDef,
799798
type_ident: Ident,
800799
generics: &Generics)
801-
-> (ast::ExplicitSelf, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
800+
-> (ast::ExplicitSelf, Vec<(P<Expr>, ast::Mutability)>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
802801

803802
let mut self_args = Vec::new();
804803
let mut nonself_args = Vec::new();
@@ -807,10 +806,10 @@ impl<'a> MethodDef<'a> {
807806

808807
let ast_explicit_self = match self.explicit_self {
809808
Some(ref self_ptr) => {
810-
let (self_expr, explicit_self) =
809+
let (self_expr, mutability, explicit_self) =
811810
ty::get_explicit_self(cx, trait_.span, self_ptr);
812811

813-
self_args.push(self_expr);
812+
self_args.push((self_expr, mutability));
814813
nonstatic = true;
815814

816815
explicit_self
@@ -829,10 +828,13 @@ impl<'a> MethodDef<'a> {
829828
// for static methods, just treat any Self
830829
// arguments as a normal arg
831830
Self_ if nonstatic => {
832-
self_args.push(arg_expr);
831+
self_args.push((arg_expr, ast::MutImmutable));
833832
}
834-
Ptr(ref ty, _) if **ty == Self_ && nonstatic => {
835-
self_args.push(cx.expr_deref(trait_.span, arg_expr))
833+
Ptr(ref ty, ref ty_ptr) if **ty == Self_ && nonstatic => {
834+
let mutability = match ty_ptr {
835+
&ty::Borrowed(_, m) | &ty::Raw(m) => m
836+
};
837+
self_args.push((cx.expr_deref(trait_.span, arg_expr), mutability))
836838
}
837839
_ => {
838840
nonself_args.push(arg_expr);
@@ -921,7 +923,7 @@ impl<'a> MethodDef<'a> {
921923
trait_: &TraitDef<'b>,
922924
struct_def: &'b StructDef,
923925
type_ident: Ident,
924-
self_args: &[P<Expr>],
926+
self_args: &[(P<Expr>, ast::Mutability)],
925927
nonself_args: &[P<Expr>])
926928
-> P<Expr> {
927929

@@ -936,7 +938,7 @@ impl<'a> MethodDef<'a> {
936938
struct_def,
937939
&format!("__self_{}",
938940
i),
939-
ast::MutImmutable);
941+
self_args[i].1);
940942
patterns.push(pat);
941943
raw_fields.push(ident_expr);
942944
}
@@ -978,7 +980,7 @@ impl<'a> MethodDef<'a> {
978980
// make a series of nested matches, to destructure the
979981
// structs. This is actually right-to-left, but it shouldn't
980982
// matter.
981-
for (arg_expr, pat) in self_args.iter().zip(patterns) {
983+
for (&(ref arg_expr, _), ref pat) in self_args.iter().zip(patterns) {
982984
body = cx.expr_match(trait_.span, arg_expr.clone(),
983985
vec!( cx.arm(trait_.span, vec!(pat.clone()), body) ))
984986
}
@@ -990,7 +992,7 @@ impl<'a> MethodDef<'a> {
990992
trait_: &TraitDef,
991993
struct_def: &StructDef,
992994
type_ident: Ident,
993-
self_args: &[P<Expr>],
995+
self_args: &[(P<Expr>, ast::Mutability)],
994996
nonself_args: &[P<Expr>])
995997
-> P<Expr> {
996998
let summary = trait_.summarise_struct(cx, struct_def);
@@ -1037,7 +1039,7 @@ impl<'a> MethodDef<'a> {
10371039
enum_def: &'b EnumDef,
10381040
type_attrs: &[ast::Attribute],
10391041
type_ident: Ident,
1040-
self_args: Vec<P<Expr>>,
1042+
self_args: Vec<(P<Expr>, ast::Mutability)>,
10411043
nonself_args: &[P<Expr>])
10421044
-> P<Expr> {
10431045
self.build_enum_match_tuple(
@@ -1087,39 +1089,35 @@ impl<'a> MethodDef<'a> {
10871089
enum_def: &'b EnumDef,
10881090
type_attrs: &[ast::Attribute],
10891091
type_ident: Ident,
1090-
self_args: Vec<P<Expr>>,
1092+
self_args: Vec<(P<Expr>, ast::Mutability)>,
10911093
nonself_args: &[P<Expr>]) -> P<Expr> {
10921094

10931095
let sp = trait_.span;
10941096
let variants = &enum_def.variants;
10951097

10961098
let self_arg_names = self_args.iter().enumerate()
1097-
.map(|(arg_count, _self_arg)| {
1099+
.map(|(arg_count, &(_, mutability))| {
10981100
if arg_count == 0 {
1099-
"__self".to_string()
1101+
("__self".to_string(), mutability)
11001102
} else {
1101-
format!("__arg_{}", arg_count)
1103+
(format!("__arg_{}", arg_count-1), mutability)
11021104
}
11031105
})
1104-
.collect::<Vec<String>>();
1105-
1106-
let self_arg_idents = self_arg_names.iter()
1107-
.map(|name|cx.ident_of(&name[..]))
1108-
.collect::<Vec<ast::Ident>>();
1106+
.collect::<Vec<(String, ast::Mutability)>>();
11091107

11101108
// The `vi_idents` will be bound, solely in the catch-all, to
11111109
// a series of let statements mapping each self_arg to an int
11121110
// value corresponding to its discriminant.
11131111
let vi_idents: Vec<ast::Ident> = self_arg_names.iter()
1114-
.map(|name| { let vi_suffix = format!("{}_vi", &name[..]);
1112+
.map(|&(ref name, _)| { let vi_suffix = format!("{}_vi", &name[..]);
11151113
cx.ident_of(&vi_suffix[..]) })
11161114
.collect::<Vec<ast::Ident>>();
11171115

11181116
// Builds, via callback to call_substructure_method, the
11191117
// delegated expression that handles the catch-all case,
11201118
// using `__variants_tuple` to drive logic if necessary.
11211119
let catch_all_substructure = EnumNonMatchingCollapsed(
1122-
self_arg_idents, &variants[..], &vi_idents[..]);
1120+
self_args.iter().map(|&(ref expr, _)| expr.clone()).collect(), &variants[..], &vi_idents[..]);
11231121

11241122
// These arms are of the form:
11251123
// (Variant1, Variant1, ...) => Body1
@@ -1128,12 +1126,12 @@ impl<'a> MethodDef<'a> {
11281126
// where each tuple has length = self_args.len()
11291127
let mut match_arms: Vec<ast::Arm> = variants.iter().enumerate()
11301128
.map(|(index, variant)| {
1131-
let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &str| {
1129+
let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &(String, ast::Mutability)| {
11321130
let (p, idents) = trait_.create_enum_variant_pattern(cx, type_ident,
11331131
&**variant,
1134-
self_arg_name,
1135-
ast::MutImmutable);
1136-
(cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents)
1132+
&self_arg_name.0[..],
1133+
self_arg_name.1);
1134+
(cx.pat(sp, ast::PatRegion(p, self_arg_name.1)), idents)
11371135
};
11381136

11391137
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
@@ -1146,7 +1144,7 @@ impl<'a> MethodDef<'a> {
11461144
idents
11471145
};
11481146
for self_arg_name in &self_arg_names[1..] {
1149-
let (p, idents) = mk_self_pat(cx, &self_arg_name[..]);
1147+
let (p, idents) = mk_self_pat(cx, self_arg_name);
11501148
subpats.push(p);
11511149
self_pats_idents.push(idents);
11521150
}
@@ -1251,7 +1249,7 @@ impl<'a> MethodDef<'a> {
12511249
find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs);
12521250

12531251
let mut first_ident = None;
1254-
for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
1252+
for (&ident, &(ref self_arg, _)) in vi_idents.iter().zip(&self_args) {
12551253
let path = cx.std_path(&["intrinsics", "discriminant_value"]);
12561254
let call = cx.expr_call_global(
12571255
sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]);
@@ -1303,7 +1301,12 @@ impl<'a> MethodDef<'a> {
13031301
// them when they are fed as r-values into a tuple
13041302
// expression; here add a layer of borrowing, turning
13051303
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1306-
let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
1304+
let borrowed_self_args = self_args.into_iter().map(|(self_arg, mutability)| {
1305+
match mutability {
1306+
ast::MutImmutable => cx.expr_addr_of(sp, self_arg),
1307+
ast::MutMutable => cx.expr_mut_addr_of(sp, self_arg),
1308+
}
1309+
}).collect();
13071310
let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
13081311

13091312
//Lastly we create an expression which branches on all discriminants being equal
@@ -1381,7 +1384,12 @@ impl<'a> MethodDef<'a> {
13811384
// them when they are fed as r-values into a tuple
13821385
// expression; here add a layer of borrowing, turning
13831386
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1384-
let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
1387+
let borrowed_self_args = self_args.into_iter().map(|(self_arg, mutability)| {
1388+
match mutability {
1389+
ast::MutImmutable => cx.expr_addr_of(sp, self_arg),
1390+
ast::MutMutable => cx.expr_mut_addr_of(sp, self_arg),
1391+
}
1392+
}).collect();
13851393
let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
13861394
cx.expr_match(sp, match_arg, match_arms)
13871395
}
@@ -1392,7 +1400,7 @@ impl<'a> MethodDef<'a> {
13921400
trait_: &TraitDef,
13931401
enum_def: &EnumDef,
13941402
type_ident: Ident,
1395-
self_args: &[P<Expr>],
1403+
self_args: &[(P<Expr>, ast::Mutability)],
13961404
nonself_args: &[P<Expr>])
13971405
-> P<Expr> {
13981406
let summary = enum_def.variants.iter().map(|v| {

src/libsyntax/ext/deriving/generic/ty.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,29 @@ pub enum Ty<'a> {
100100
pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
101101
Borrowed(None, ast::MutImmutable)
102102
}
103+
pub fn borrowed_mut_ptrty<'r>() -> PtrTy<'r> {
104+
Borrowed(None, ast::MutMutable)
105+
}
103106
pub fn borrowed<'r>(ty: Box<Ty<'r>>) -> Ty<'r> {
104107
Ptr(ty, borrowed_ptrty())
105108
}
109+
pub fn borrowed_mut<'r>(ty: Box<Ty<'r>>) -> Ty<'r> {
110+
Ptr(ty, borrowed_mut_ptrty())
111+
}
106112

107113
pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
108114
Some(Some(borrowed_ptrty()))
109115
}
116+
pub fn borrowed_mut_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
117+
Some(Some(borrowed_mut_ptrty()))
118+
}
110119

111120
pub fn borrowed_self<'r>() -> Ty<'r> {
112121
borrowed(Box::new(Self_))
113122
}
123+
pub fn borrowed_mut_self<'r>() -> Ty<'r> {
124+
borrowed_mut(Box::new(Self_))
125+
}
114126

115127
pub fn nil_ty<'r>() -> Ty<'r> {
116128
Tuple(Vec::new())
@@ -258,26 +270,28 @@ impl<'a> LifetimeBounds<'a> {
258270
}
259271

260272
pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option<PtrTy>)
261-
-> (P<Expr>, ast::ExplicitSelf) {
273+
-> (P<Expr>, ast::Mutability, ast::ExplicitSelf) {
262274
// this constructs a fresh `self` path, which will match the fresh `self` binding
263275
// created below.
264276
let self_path = cx.expr_self(span);
265277
match *self_ptr {
266278
None => {
267-
(self_path, respan(span, ast::SelfValue(special_idents::self_)))
279+
(self_path, ast::MutImmutable, respan(span, ast::SelfValue(special_idents::self_)))
268280
}
269281
Some(ref ptr) => {
282+
let mutability;
270283
let self_ty = respan(
271284
span,
272285
match *ptr {
273286
Borrowed(ref lt, mutbl) => {
287+
mutability = mutbl;
274288
let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name));
275289
ast::SelfRegion(lt, mutbl, special_idents::self_)
276290
}
277291
Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition")
278292
});
279293
let self_expr = cx.expr_deref(span, self_path);
280-
(self_expr, self_ty)
294+
(self_expr, mutability, self_ty)
281295
}
282296
}
283297
}

0 commit comments

Comments
 (0)