Skip to content

Commit 744fea1

Browse files
committed
Track the type of self properly. Closes #3247.
1 parent 7284969 commit 744fea1

File tree

7 files changed

+107
-96
lines changed

7 files changed

+107
-96
lines changed

src/rustc/middle/trans/impl.rs

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -54,32 +54,28 @@ fn trans_method(ccx: @crate_ctxt,
5454
method: &ast::method,
5555
param_substs: option<param_substs>,
5656
llfn: ValueRef) {
57-
// determine the (monomorphized) type that `self` maps to for this method
58-
let self_ty = ty::node_id_to_type(ccx.tcx, method.self_id);
59-
let self_ty = match param_substs {
60-
none => self_ty,
61-
some({tys: ref tys, _}) => ty::subst_tps(ccx.tcx, *tys, self_ty)
62-
};
6357

64-
// apply any transformations from the explicit self declaration
58+
// figure out how self is being passed
6559
let self_arg = match method.self_ty.node {
6660
ast::sty_static => {
6761
no_self
6862
}
69-
ast::sty_box(_) => {
70-
impl_self(ty::mk_imm_box(ccx.tcx, self_ty))
71-
}
72-
ast::sty_uniq(_) => {
73-
impl_self(ty::mk_imm_uniq(ccx.tcx, self_ty))
74-
}
75-
ast::sty_region(*) => {
76-
impl_self(ty::mk_imm_ptr(ccx.tcx, self_ty))
77-
}
78-
ast::sty_value => {
79-
impl_owned_self(self_ty)
80-
}
81-
ast::sty_by_ref => {
82-
impl_self(self_ty)
63+
_ => {
64+
// determine the (monomorphized) type that `self` maps to for
65+
// this method
66+
let self_ty = ty::node_id_to_type(ccx.tcx, method.self_id);
67+
let self_ty = match param_substs {
68+
none => self_ty,
69+
some({tys: ref tys, _}) => ty::subst_tps(ccx.tcx, *tys, self_ty)
70+
};
71+
match method.self_ty.node {
72+
ast::sty_value => {
73+
impl_owned_self(self_ty)
74+
}
75+
_ => {
76+
impl_self(self_ty)
77+
}
78+
}
8379
}
8480
};
8581

src/rustc/middle/typeck/check.rs

Lines changed: 57 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,16 @@ import std::map::str_hash;
7979

8080
type self_info = {
8181
self_ty: ty::t,
82+
self_id: ast::node_id,
8283
def_id: ast::def_id,
83-
explicit_self: ast::self_ty_
84+
explicit_self: ast::self_ty
8485
};
8586

8687
type fn_ctxt_ =
8788
// var_bindings, locals and next_var_id are shared
8889
// with any nested functions that capture the environment
8990
// (and with any functions whose environment is being captured).
90-
{self_info: option<self_info>,
91+
{self_impl_def_id: option<ast::def_id>,
9192
ret_ty: ty::t,
9293
// Used by loop bodies that return from the outer function
9394
indirect_ret_ty: option<ty::t>,
@@ -126,7 +127,7 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
126127
region_bnd: ast::node_id) -> @fn_ctxt {
127128
// It's kind of a kludge to manufacture a fake function context
128129
// and statement context, but we might as well do write the code only once
129-
@fn_ctxt_({self_info: none,
130+
@fn_ctxt_({self_impl_def_id: none,
130131
ret_ty: rty,
131132
indirect_ret_ty: none,
132133
purity: ast::pure_fn,
@@ -244,7 +245,7 @@ fn check_fn(ccx: @crate_ctxt,
244245
}
245246
} else { none };
246247

247-
@fn_ctxt_({self_info: self_info,
248+
@fn_ctxt_({self_impl_def_id: self_info.map(|info| info.def_id),
248249
ret_ty: ret_ty,
249250
indirect_ret_ty: indirect_ret_ty,
250251
purity: purity,
@@ -257,7 +258,22 @@ fn check_fn(ccx: @crate_ctxt,
257258
ccx: ccx})
258259
};
259260

260-
gather_locals(fcx, decl, body, arg_tys);
261+
// Update the self_info to contain an accurate self type (taking
262+
// into account explicit self).
263+
let self_info = do self_info.chain |info| {
264+
// If the self type is sty_static, we don't have a self ty.
265+
if info.explicit_self.node == ast::sty_static {
266+
none
267+
} else {
268+
let self_region = fcx.in_scope_regions.find(ty::br_self);
269+
let ty = method::transform_self_type_for_method(
270+
fcx.tcx(), self_region,
271+
info.self_ty, info.explicit_self.node);
272+
some({self_ty: ty with info})
273+
}
274+
};
275+
276+
gather_locals(fcx, decl, body, arg_tys, self_info);
261277
check_block(fcx, body);
262278

263279
// We unify the tail expr's type with the
@@ -270,10 +286,11 @@ fn check_fn(ccx: @crate_ctxt,
270286
none => ()
271287
}
272288

273-
let mut i = 0u;
274-
do vec::iter(arg_tys) |arg| {
275-
fcx.write_ty(decl.inputs[i].id, arg);
276-
i += 1u;
289+
for self_info.each |info| {
290+
fcx.write_ty(info.self_id, info.self_ty);
291+
}
292+
do vec::iter2(decl.inputs, arg_tys) |input, arg| {
293+
fcx.write_ty(input.id, arg);
277294
}
278295

279296
// If we don't have any enclosing function scope, it is time to
@@ -283,13 +300,14 @@ fn check_fn(ccx: @crate_ctxt,
283300
if option::is_none(old_fcx) {
284301
vtable::resolve_in_block(fcx, body);
285302
regionck::regionck_fn(fcx, decl, body);
286-
writeback::resolve_type_vars_in_fn(fcx, decl, body);
303+
writeback::resolve_type_vars_in_fn(fcx, decl, body, self_info);
287304
}
288305

289306
fn gather_locals(fcx: @fn_ctxt,
290307
decl: ast::fn_decl,
291308
body: ast::blk,
292-
arg_tys: ~[ty::t]) {
309+
arg_tys: ~[ty::t],
310+
self_info: option<self_info>) {
293311
let tcx = fcx.ccx.tcx;
294312

295313
let assign = fn@(span: span, nid: ast::node_id,
@@ -305,6 +323,14 @@ fn check_fn(ccx: @crate_ctxt,
305323
}
306324
};
307325

326+
// Add the self parameter
327+
for self_info.each |info| {
328+
assign(info.explicit_self.span,
329+
info.self_id, some(info.self_ty));
330+
debug!{"self is assigned to %s",
331+
fcx.locals.get(info.self_id).to_str()};
332+
}
333+
308334
// Add formal parameters.
309335
do vec::iter2(arg_tys, decl.inputs) |arg_ty, input| {
310336
assign(input.ty.span, input.id, some(arg_ty));
@@ -369,8 +395,11 @@ fn check_fn(ccx: @crate_ctxt,
369395
}
370396

371397
fn check_method(ccx: @crate_ctxt, method: @ast::method,
372-
self_info: self_info) {
373-
398+
self_ty: ty::t, self_impl_def_id: ast::def_id) {
399+
let self_info = {self_ty: self_ty,
400+
self_id: method.self_id,
401+
def_id: self_impl_def_id,
402+
explicit_self: method.self_ty };
374403
check_bare_fn(ccx, method.decl, method.body, method.id, some(self_info));
375404
}
376405

@@ -404,33 +433,31 @@ fn check_struct(ccx: @crate_ctxt, struct_def: @ast::struct_def,
404433

405434
do option::iter(struct_def.ctor) |ctor| {
406435
let class_t = {self_ty: self_ty,
436+
self_id: ctor.node.self_id,
407437
def_id: local_def(id),
408-
explicit_self: ast::sty_by_ref};
438+
explicit_self: {node: ast::sty_by_ref,
439+
span: ast_util::dummy_sp()}};
409440
// typecheck the ctor
410441
check_bare_fn(ccx, ctor.node.dec,
411442
ctor.node.body, ctor.node.id,
412443
some(class_t));
413-
// Write the ctor's self's type
414-
write_ty_to_tcx(tcx, ctor.node.self_id, class_t.self_ty);
415444
}
416445

417446
do option::iter(struct_def.dtor) |dtor| {
418447
let class_t = {self_ty: self_ty,
448+
self_id: dtor.node.self_id,
419449
def_id: local_def(id),
420-
explicit_self: ast::sty_by_ref};
450+
explicit_self: {node: ast::sty_by_ref,
451+
span: ast_util::dummy_sp()}};
421452
// typecheck the dtor
422453
check_bare_fn(ccx, ast_util::dtor_dec(),
423454
dtor.node.body, dtor.node.id,
424455
some(class_t));
425-
// Write the dtor's self's type
426-
write_ty_to_tcx(tcx, dtor.node.self_id, class_t.self_ty);
427456
};
428457

429458
// typecheck the methods
430459
for struct_def.methods.each |m| {
431-
check_method(ccx, m, {self_ty: self_ty,
432-
def_id: local_def(id),
433-
explicit_self: m.self_ty.node});
460+
check_method(ccx, m, self_ty, local_def(id));
434461
}
435462
// Check that there's at least one field
436463
if struct_def.fields.len() < 1u {
@@ -455,10 +482,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
455482
*it.ident, it.id, rp};
456483
let self_ty = ccx.to_ty(rscope::type_rscope(rp), ty);
457484
for ms.each |m| {
458-
let self_info = {self_ty: self_ty,
459-
def_id: local_def(it.id),
460-
explicit_self: m.self_ty.node };
461-
check_method(ccx, m, self_info)
485+
check_method(ccx, m, self_ty, local_def(it.id));
462486
}
463487
}
464488
ast::item_trait(_, _, trait_methods) => {
@@ -469,10 +493,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
469493
// bodies to check.
470494
}
471495
provided(m) => {
472-
let self_info = {self_ty: ty::mk_self(ccx.tcx),
473-
def_id: local_def(it.id),
474-
explicit_self: m.self_ty.node};
475-
check_method(ccx, m, self_info);
496+
check_method(ccx, m, ty::mk_self(ccx.tcx), local_def(it.id));
476497
}
477498
}
478499
}
@@ -1204,7 +1225,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
12041225

12051226
fcx.write_ty(expr.id, fty);
12061227

1207-
check_fn(fcx.ccx, fcx.self_info, &fn_ty, decl, body,
1228+
check_fn(fcx.ccx, none, &fn_ty, decl, body,
12081229
is_loop_body, some(fcx));
12091230
}
12101231

@@ -2247,29 +2268,12 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
22472268
ty_param_bounds_and_ty {
22482269
22492270
match defn {
2250-
ast::def_arg(nid, _) => {
2271+
ast::def_arg(nid, _) | ast::def_local(nid, _) |
2272+
ast::def_self(nid) | ast::def_binding(nid, _) => {
22512273
assert (fcx.locals.contains_key(nid));
22522274
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
22532275
return no_params(typ);
22542276
}
2255-
ast::def_local(nid, _) => {
2256-
assert (fcx.locals.contains_key(nid));
2257-
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
2258-
return no_params(typ);
2259-
}
2260-
ast::def_self(_) => {
2261-
match fcx.self_info {
2262-
some(self_info) => {
2263-
let self_region = fcx.in_scope_regions.find(ty::br_self);
2264-
return no_params(method::transform_self_type_for_method(
2265-
fcx.tcx(), self_region,
2266-
self_info.self_ty, self_info.explicit_self));
2267-
}
2268-
none => {
2269-
fcx.ccx.tcx.sess.span_bug(sp, ~"def_self with no self_info");
2270-
}
2271-
}
2272-
}
22732277
ast::def_fn(id, ast::extern_fn) => {
22742278
// extern functions are just u8 pointers
22752279
return {
@@ -2296,20 +2300,15 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
22962300
ast::def_class(id, _) => {
22972301
return ty::lookup_item_type(fcx.ccx.tcx, id);
22982302
}
2299-
ast::def_binding(nid, _) => {
2300-
assert (fcx.locals.contains_key(nid));
2301-
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
2302-
return no_params(typ);
2303-
}
2304-
ast::def_ty(_) | ast::def_prim_ty(_) => {
2305-
fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found type");
2306-
}
23072303
ast::def_upvar(_, inner, _, _) => {
23082304
return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
23092305
}
23102306
ast::def_ty_param(did, n) => {
23112307
return no_params(ty::mk_param(fcx.ccx.tcx, n, did));
23122308
}
2309+
ast::def_ty(_) | ast::def_prim_ty(_) => {
2310+
fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found type");
2311+
}
23132312
ast::def_mod(*) | ast::def_foreign_mod(*) => {
23142313
fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found module");
23152314
}

src/rustc/middle/typeck/check/method.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,8 @@ struct lookup {
150150
ty::ty_self => {
151151
// Call is of the form "self.foo()" and appears in one
152152
// of a trait's provided methods.
153-
let self_def_id = match self.fcx.self_info {
154-
some(self_info) => self_info.def_id,
155-
none => {
156-
// Shouldn't happen; there should always be a
157-
// self_info in this case.
158-
self.tcx().sess.bug(~"unexpected `none` for self_info")
159-
}
160-
};
153+
let self_def_id = self.fcx.self_impl_def_id.expect(
154+
~"unexpected `none` for self_impl_def_id");
161155

162156
let substs = {
163157
self_r: none,

src/rustc/middle/typeck/check/regionmanip.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn replace_bound_regions_in_fn_ty(
2323
let mut all_tys = ty::tys_in_fn_ty(fn_ty);
2424

2525
match self_info {
26-
some({explicit_self: ast::sty_region(m), _}) => {
26+
some({explicit_self: {node: ast::sty_region(m), _}, _}) => {
2727
let region = ty::re_bound(ty::br_self);
2828
let ty = ty::mk_rptr(tcx, region,
2929
{ ty: ty::mk_self(tcx), mutbl: m });

src/rustc/middle/typeck/check/writeback.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,16 @@ fn resolve_type_vars_in_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool {
171171

172172
fn resolve_type_vars_in_fn(fcx: @fn_ctxt,
173173
decl: ast::fn_decl,
174-
blk: ast::blk) -> bool {
174+
blk: ast::blk,
175+
self_info: option<self_info>) -> bool {
175176
let wbcx = {fcx: fcx, mut success: true};
176177
let visit = mk_visitor();
177178
visit.visit_block(blk, wbcx, visit);
179+
for self_info.each |self_info| {
180+
if self_info.explicit_self.node == ast::sty_static { break; }
181+
resolve_type_vars_for_node(wbcx, self_info.explicit_self.span,
182+
self_info.self_id);
183+
}
178184
for decl.inputs.each |arg| {
179185
resolve_type_vars_for_node(wbcx, arg.ty.span, arg.id);
180186
}

src/rustc/middle/typeck/collect.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -381,12 +381,10 @@ type converted_method = {mty: ty::method, id: ast::node_id, span: span};
381381
fn convert_methods(ccx: @crate_ctxt,
382382
ms: ~[@ast::method],
383383
rp: bool,
384-
rcvr_bounds: @~[ty::param_bounds],
385-
self_ty: ty::t) -> ~[converted_method] {
384+
rcvr_bounds: @~[ty::param_bounds]) -> ~[converted_method] {
386385

387386
let tcx = ccx.tcx;
388387
do vec::map(ms) |m| {
389-
write_ty_to_tcx(tcx, m.self_id, self_ty);
390388
let bounds = ty_param_bounds(ccx, m.tps);
391389
let mty = ty_of_method(ccx, m, rp);
392390
let fty = ty::mk_fn(tcx, mty.fty);
@@ -423,7 +421,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
423421
rp: rp,
424422
ty: selfty});
425423

426-
let cms = convert_methods(ccx, ms, rp, i_bounds, selfty);
424+
let cms = convert_methods(ccx, ms, rp, i_bounds);
427425
for trait_ref.each |t| {
428426
check_methods_against_trait(ccx, tps, rp, selfty, t, cms);
429427
}
@@ -436,9 +434,8 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
436434
ensure_trait_methods(ccx, it.id, tpt.ty);
437435

438436
let (_, provided_methods) = split_trait_methods(trait_methods);
439-
let selfty = ty::mk_self(tcx);
440437
let {bounds, _} = mk_substs(ccx, tps, rp);
441-
let _cms = convert_methods(ccx, provided_methods, rp, bounds, selfty);
438+
let _cms = convert_methods(ccx, provided_methods, rp, bounds);
442439
// FIXME (#2616): something like this, when we start having
443440
// trait inheritance?
444441
// for trait_ref.each |t| {
@@ -510,7 +507,7 @@ fn convert_struct(ccx: @crate_ctxt, rp: bool, struct_def: @ast::struct_def,
510507
}
511508
let {bounds, substs} = mk_substs(ccx, tps, rp);
512509
let selfty = ty::mk_class(tcx, local_def(id), substs);
513-
let cms = convert_methods(ccx, struct_def.methods, rp, bounds, selfty);
510+
let cms = convert_methods(ccx, struct_def.methods, rp, bounds);
514511
for struct_def.traits.each |trait_ref| {
515512
check_methods_against_trait(ccx, tps, rp, selfty, trait_ref, cms);
516513
// trait_ref.impl_id represents (class, trait) pair

0 commit comments

Comments
 (0)