@@ -12,7 +12,13 @@ type deref = @{mutbl: bool, kind: deref_t, outer_t: ty::t};
12
12
// vec of dereferences that were used on this root. Note that, in this vec,
13
13
// the inner derefs come in front, so foo.bar[1] becomes rec(ex=foo,
14
14
// ds=[index,field])
15
- fn expr_root ( tcx : ty:: ctxt , ex: @expr, autoderef : bool ) ->
15
+ fn expr_root ( cx : @ctx , ex: @expr, autoderef : bool )
16
+ -> { ex : @expr, ds : @[ deref ] } {
17
+ expr_root_ ( cx. tcx , cx. in_ctor , ex, autoderef)
18
+ }
19
+
20
+ fn expr_root_ ( tcx : ty:: ctxt , ctor_self : option < node_id > ,
21
+ ex: @expr, autoderef : bool ) ->
16
22
{ ex : @expr, ds : @[ deref ] } {
17
23
fn maybe_auto_unbox ( tcx : ty:: ctxt , t : ty:: t ) -> { t : ty:: t , ds : [ deref ] } {
18
24
let mut ds = [ ] , t = t;
@@ -58,13 +64,23 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) ->
58
64
}
59
65
}
60
66
ty:: ty_class ( did, _) {
61
- util:: common:: log_expr ( * ex) ;
67
+ util:: common:: log_expr ( * base) ;
68
+ let in_self = alt ctor_self {
69
+ some( selfid) {
70
+ alt tcx. def_map . find ( base. id ) {
71
+ some ( def_self ( slfid) ) { slfid == selfid }
72
+ _ { false }
73
+ }
74
+ }
75
+ none { false }
76
+ } ;
62
77
for fld: ty:: field_ty in ty:: lookup_class_fields ( tcx, did) {
63
- #debug ( "%s %?" , fld. ident , fld. mutability ) ;
64
78
if str:: eq ( ident, fld. ident ) {
65
- is_mutbl = fld. mutability == class_mutable;
79
+ is_mutbl = fld. mutability == class_mutable
80
+ || in_self; // all fields can be mutated
81
+ // in the ctor
82
+ break ;
66
83
}
67
- break ;
68
84
}
69
85
}
70
86
_ { }
@@ -126,10 +142,11 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) ->
126
142
type mutbl_map = std:: map:: hashmap < node_id , ( ) > ;
127
143
// Keep track of whether we're inside a ctor, so as to
128
144
// allow mutating immutable fields in the same class
129
- type ctx = { tcx : ty:: ctxt , mutbl_map : mutbl_map , in_ctor : bool } ;
145
+ // if we are in a ctor, we track the self id
146
+ type ctx = { tcx : ty:: ctxt , mutbl_map : mutbl_map , in_ctor : option < node_id > } ;
130
147
131
148
fn check_crate ( tcx : ty:: ctxt , crate : @crate ) -> mutbl_map {
132
- let cx = @{ tcx: tcx, mutbl_map: std:: map:: int_hash ( ) , in_ctor: false } ;
149
+ let cx = @{ tcx: tcx, mutbl_map: std:: map:: int_hash ( ) , in_ctor: none } ;
133
150
let v = @{ visit_expr: visit_expr,
134
151
visit_decl: visit_decl,
135
152
visit_item: visit_item
@@ -204,7 +221,7 @@ fn visit_item(item: @item, &&cx: @ctx, v: visit::vt<@ctx>) {
204
221
i. node . privacy , i. node . decl , cx, v) ; } ) ;
205
222
v. visit_fn ( visit:: fk_ctor ( item. ident , tps) , ctor. node . dec ,
206
223
ctor. node . body , ctor. span , ctor. node . id ,
207
- @{ in_ctor: true with * cx} , v) ;
224
+ @{ in_ctor : some ( ctor . node . self_id ) with * cx} , v) ;
208
225
}
209
226
_ { visit : : visit_item ( item, cx, v) ; }
210
227
}
@@ -221,7 +238,7 @@ fn check_lval(cx: @ctx, dest: @expr, msg: msg) {
221
238
cx. mutbl_map . insert ( ast_util:: def_id_of_def ( def) . node , ( ) ) ;
222
239
}
223
240
_ {
224
- let root = expr_root ( cx. tcx , dest, false ) ;
241
+ let root = expr_root ( cx, dest, false ) ;
225
242
if vec:: len ( * root. ds ) == 0 u {
226
243
if msg != msg_move_out {
227
244
mk_err ( cx, dest. span , msg, "non-lvalue" ) ;
@@ -251,7 +268,7 @@ fn check_move_rhs(cx: @ctx, src: @expr) {
251
268
check_lval( cx, src, msg_move_out) ;
252
269
}
253
270
_ {
254
- let root = expr_root( cx. tcx , src, false ) ;
271
+ let root = expr_root( cx, src, false ) ;
255
272
256
273
// Not a path and no-derefs means this is a temporary.
257
274
if vec:: len ( * root. ds ) != 0 u &&
@@ -339,7 +356,7 @@ fn is_illegal_to_modify_def(cx: @ctx, def: def, msg: msg) -> option<str> {
339
356
340
357
def_binding ( _) { some ( "binding" ) }
341
358
def_class_field ( parent, fld) {
342
- if ! cx. in_ctor {
359
+ if option :: is_none ( cx. in_ctor ) {
343
360
/* Enforce mutability *unless* we're inside a ctor */
344
361
alt ty:: lookup_class_field ( cx. tcx , parent, fld) . mutability {
345
362
class_mutable { none }
0 commit comments