Skip to content

Commit f4acaf6

Browse files
committed
Only look for a matching method when normal field access fails
We should probalby warn when defining a method foo on {foo: int} etc. This should reduce the amount of useless typevars that are allocated. Issue #1227
1 parent b36ade1 commit f4acaf6

File tree

10 files changed

+120
-95
lines changed

10 files changed

+120
-95
lines changed

src/comp/middle/trans.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2759,7 +2759,7 @@ fn trans_object_field_inner(bcx: @block_ctxt, o: ValueRef,
27592759
let ccx = bcx_ccx(bcx), tcx = ccx.tcx;
27602760
let mths = alt ty::struct(tcx, o_ty) { ty::ty_obj(ms) { ms } };
27612761

2762-
let ix = ty::method_idx(ccx.sess, bcx.sp, field, mths);
2762+
let ix = option::get(ty::method_idx(field, mths));
27632763
let vtbl = Load(bcx, GEPi(bcx, o, [0, abi::obj_field_vtbl]));
27642764
let vtbl_type = T_ptr(T_array(T_ptr(T_nil()), ix + 1u));
27652765
vtbl = PointerCast(bcx, vtbl, vtbl_type);
@@ -2782,7 +2782,7 @@ fn trans_rec_field(bcx: @block_ctxt, base: @ast::expr,
27822782
let {bcx, val} = trans_temp_expr(bcx, base);
27832783
let {bcx, val, ty} = autoderef(bcx, val, ty::expr_ty(bcx_tcx(bcx), base));
27842784
let fields = alt ty::struct(bcx_tcx(bcx), ty) { ty::ty_rec(fs) { fs } };
2785-
let ix = ty::field_idx(bcx_ccx(bcx).sess, bcx.sp, field, fields);
2785+
let ix = option::get(ty::field_idx(field, fields));
27862786
// Silly check
27872787
check type_is_tup_like(bcx, ty);
27882788
let {bcx, val} = GEP_tup_like(bcx, ty, val, [0, ix as int]);

src/comp/middle/trans_alt.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,7 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail,
413413
alt ty::struct(ccx.tcx, rec_ty) { ty::ty_rec(fields) { fields } };
414414
let rec_vals = [];
415415
for field_name: ast::ident in rec_fields {
416-
let ix: uint =
417-
ty::field_idx(ccx.sess, dummy_sp(), field_name, fields);
416+
let ix = option::get(ty::field_idx(field_name, fields));
418417
// not sure how to get rid of this check
419418
check type_is_tup_like(bcx, rec_ty);
420419
let r = trans::GEP_tup_like(bcx, rec_ty, val, [0, ix as int]);
@@ -722,8 +721,7 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef,
722721
let rec_fields =
723722
alt ty::struct(ccx.tcx, rec_ty) { ty::ty_rec(fields) { fields } };
724723
for f: ast::field_pat in fields {
725-
let ix: uint =
726-
ty::field_idx(ccx.sess, pat.span, f.ident, rec_fields);
724+
let ix = option::get(ty::field_idx(f.ident, rec_fields));
727725
// how to get rid of this check?
728726
check type_is_tup_like(bcx, rec_ty);
729727
let r = trans::GEP_tup_like(bcx, rec_ty, val, [0, ix as int]);

src/comp/middle/trans_objects.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ fn process_bkwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method,
642642
let ix: uint = 0u;
643643
alt ty::struct(bcx_tcx(bcx), outer_obj_ty) {
644644
ty::ty_obj(methods) {
645-
ix = ty::method_idx(cx.ccx.sess, sp, m.ident, methods);
645+
ix = option::get(ty::method_idx(m.ident, methods));
646646
}
647647
_ {
648648
// Shouldn't happen.
@@ -787,7 +787,7 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: span, m: @ty::method,
787787
let ix: uint = 0u;
788788
alt ty::struct(bcx_tcx(bcx), inner_obj_ty) {
789789
ty::ty_obj(methods) {
790-
ix = ty::method_idx(cx.ccx.sess, sp, m.ident, methods);
790+
ix = option::get(ty::method_idx(m.ident, methods));
791791
}
792792
_ {
793793
// Shouldn't happen.

src/comp/middle/ty.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,11 +1698,10 @@ fn stmt_node_id(s: @ast::stmt) -> ast::node_id {
16981698
}
16991699
}
17001700

1701-
fn field_idx(sess: session::session, sp: span, id: ast::ident,
1702-
fields: [field]) -> uint {
1703-
let i: uint = 0u;
1704-
for f: field in fields { if str::eq(f.ident, id) { ret i; } i += 1u; }
1705-
sess.span_fatal(sp, "unknown field '" + id + "' of record");
1701+
fn field_idx(id: ast::ident, fields: [field]) -> option::t<uint> {
1702+
let i = 0u;
1703+
for f in fields { if f.ident == id { ret some(i); } i += 1u; }
1704+
ret none;
17061705
}
17071706

17081707
fn get_field(tcx: ctxt, rec_ty: t, id: ast::ident) -> field {
@@ -1715,11 +1714,10 @@ fn get_field(tcx: ctxt, rec_ty: t, id: ast::ident) -> field {
17151714
}
17161715
}
17171716

1718-
fn method_idx(sess: session::session, sp: span, id: ast::ident,
1719-
meths: [method]) -> uint {
1720-
let i: uint = 0u;
1721-
for m: method in meths { if str::eq(m.ident, id) { ret i; } i += 1u; }
1722-
sess.span_fatal(sp, "unknown method '" + id + "' of obj");
1717+
fn method_idx(id: ast::ident, meths: [method]) -> option::t<uint> {
1718+
let i = 0u;
1719+
for m in meths { if m.ident == id { ret some(i); } i += 1u; }
1720+
ret none;
17231721
}
17241722

17251723
fn sort_methods(meths: [method]) -> [method] {

src/comp/middle/typeck.rs

Lines changed: 76 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,30 +1466,32 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
14661466
-> option::t<{method: @resolve::method_info, ids: [int]}> {
14671467
let result = none;
14681468
std::list::iter(isc) {|impls|
1469+
if option::is_some(result) { ret; }
14691470
for @{did, methods, _} in *impls {
1470-
let (n_tps, self_ty) = if did.crate == ast::local_crate {
1471-
alt fcx.ccx.tcx.items.get(did.node) {
1472-
ast_map::node_item(@{node: ast::item_impl(tps, st, _), _}) {
1473-
(vec::len(tps), ast_ty_to_ty_crate(fcx.ccx, st))
1474-
}
1475-
}
1476-
} else {
1477-
let tpt = csearch::get_type(fcx.ccx.tcx, did);
1478-
(vec::len(tpt.kinds), tpt.ty)
1479-
};
1480-
let {ids, ty: self_ty} = if n_tps > 0u {
1481-
bind_params_in_type(ast_util::dummy_sp(), fcx.ccx.tcx,
1482-
bind next_ty_var_id(fcx), self_ty, n_tps)
1483-
} else { {ids: [], ty: self_ty} };
1484-
// FIXME[impl] Don't unify in the current fcx, use
1485-
// scratch context
1486-
alt unify::unify(fcx, ty, self_ty) {
1487-
ures_ok(_) {
1488-
for m in methods {
1489-
if m.ident == name {
1490-
result = some({method: m, ids: ids});
1491-
ret;
1471+
alt vec::find(methods, {|m| m.ident == name}) {
1472+
some(m) {
1473+
let (n_tps, self_ty) = if did.crate == ast::local_crate {
1474+
alt fcx.ccx.tcx.items.get(did.node) {
1475+
ast_map::node_item(@{node: ast::item_impl(tps, st, _),
1476+
_}) {
1477+
(vec::len(tps), ast_ty_to_ty_crate(fcx.ccx, st))
1478+
}
14921479
}
1480+
} else {
1481+
let tpt = csearch::get_type(fcx.ccx.tcx, did);
1482+
(vec::len(tpt.kinds), tpt.ty)
1483+
};
1484+
let {ids, ty: self_ty} = if n_tps > 0u {
1485+
bind_params_in_type(ast_util::dummy_sp(), fcx.ccx.tcx,
1486+
bind next_ty_var_id(fcx), self_ty,
1487+
n_tps)
1488+
} else { {ids: [], ty: self_ty} };
1489+
alt unify::unify(fcx, ty, self_ty) {
1490+
ures_ok(_) {
1491+
result = some({method: m, ids: ids});
1492+
ret;
1493+
}
1494+
_ {}
14931495
}
14941496
}
14951497
_ {}
@@ -2128,60 +2130,66 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
21282130
}
21292131
ast::expr_field(base, field) {
21302132
bot |= check_expr(fcx, base);
2131-
let base_t = expr_ty(tcx, base);
2132-
let iscope = fcx.ccx.impl_map.get(expr.id);
2133-
alt lookup_method(fcx, iscope, field, base_t) {
2134-
some({method, ids}) {
2135-
let fty = if method.did.crate == ast::local_crate {
2136-
alt tcx.items.get(method.did.node) {
2137-
ast_map::node_method(m) {
2138-
let mt = ty_of_method(tcx, m_check, m);
2139-
ty::mk_fn(tcx, mt.proto, mt.inputs,
2140-
mt.output, mt.cf, mt.constrs)
2141-
}
2142-
}
2143-
} else { csearch::get_type(tcx, method.did).ty };
2144-
let ids = ids;
2145-
if method.n_tps > 0u {
2146-
let b = bind_params_in_type(expr.span, tcx,
2147-
bind next_ty_var_id(fcx),
2148-
fty, method.n_tps);
2149-
ids += b.ids;
2150-
fty = b.ty;
2151-
}
2152-
let substs = vec::map(ids, {|id| ty::mk_var(tcx, id)});
2153-
write::ty_fixup(fcx, id, {substs: some(substs), ty: fty});
2154-
fcx.ccx.method_map.insert(id, method.did);
2155-
}
2156-
_ {
2157-
base_t = do_autoderef(fcx, expr.span, base_t);
2158-
alt structure_of(fcx, expr.span, base_t) {
2159-
ty::ty_rec(fields) {
2160-
let ix = ty::field_idx(tcx.sess, expr.span, field, fields);
2161-
if ix >= vec::len::<ty::field>(fields) {
2162-
tcx.sess.span_fatal(expr.span, "bad index on record");
2163-
}
2133+
let expr_t = expr_ty(tcx, base);
2134+
let base_t = do_autoderef(fcx, expr.span, expr_t);
2135+
let handled = false;
2136+
alt structure_of(fcx, expr.span, base_t) {
2137+
ty::ty_rec(fields) {
2138+
alt ty::field_idx(field, fields) {
2139+
some(ix) {
21642140
write::ty_only_fixup(fcx, id, fields[ix].mt.ty);
2141+
handled = true;
21652142
}
2166-
ty::ty_obj(methods) {
2167-
let ix = ty::method_idx(tcx.sess, expr.span, field, methods);
2168-
if ix >= vec::len::<ty::method>(methods) {
2169-
tcx.sess.span_fatal(expr.span, "bad index on obj");
2170-
}
2143+
_ {}
2144+
}
2145+
}
2146+
ty::ty_obj(methods) {
2147+
alt ty::method_idx(field, methods) {
2148+
some(ix) {
21712149
let meth = methods[ix];
2172-
let t = ty::mk_fn(tcx, meth.proto, meth.inputs, meth.output,
2173-
meth.cf, meth.constrs);
2150+
let t = ty::mk_fn(tcx, meth.proto, meth.inputs,
2151+
meth.output, meth.cf, meth.constrs);
21742152
write::ty_only_fixup(fcx, id, t);
2153+
handled = true;
21752154
}
2176-
_ {
2177-
let t_err = resolve_type_vars_if_possible(fcx, base_t);
2178-
let msg = #fmt["attempted field access on type %s, but no \
2179-
method implementation was found",
2180-
ty_to_str(tcx, t_err)];
2155+
_ {}
2156+
}
2157+
}
2158+
_ {}
2159+
}
2160+
if !handled {
2161+
let iscope = fcx.ccx.impl_map.get(expr.id);
2162+
alt lookup_method(fcx, iscope, field, expr_t) {
2163+
some({method, ids}) {
2164+
let fty = if method.did.crate == ast::local_crate {
2165+
alt tcx.items.get(method.did.node) {
2166+
ast_map::node_method(m) {
2167+
let mt = ty_of_method(tcx, m_check, m);
2168+
ty::mk_fn(tcx, mt.proto, mt.inputs,
2169+
mt.output, mt.cf, mt.constrs)
2170+
}
2171+
}
2172+
} else { csearch::get_type(tcx, method.did).ty };
2173+
let ids = ids;
2174+
if method.n_tps > 0u {
2175+
let b = bind_params_in_type(expr.span, tcx,
2176+
bind next_ty_var_id(fcx),
2177+
fty, method.n_tps);
2178+
ids += b.ids;
2179+
fty = b.ty;
2180+
}
2181+
let substs = vec::map(ids, {|id| ty::mk_var(tcx, id)});
2182+
write::ty_fixup(fcx, id, {substs: some(substs), ty: fty});
2183+
fcx.ccx.method_map.insert(id, method.did);
2184+
}
2185+
none. {
2186+
let t_err = resolve_type_vars_if_possible(fcx, expr_t);
2187+
let msg = #fmt["attempted access of field %s on type %s, but \
2188+
no method implementation was found",
2189+
field, ty_to_str(tcx, t_err)];
21812190
tcx.sess.span_fatal(expr.span, msg);
21822191
}
21832192
}
2184-
}
21852193
}
21862194
}
21872195
ast::expr_index(base, idx) {

src/comp/syntax/print/pprust.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -467,11 +467,10 @@ fn print_item(s: ps, &&item: @ast::item) {
467467
space(s.s);
468468
bopen(s);
469469
for meth: @ast::method in _obj.methods {
470-
let typarams: [ast::ty_param] = [];
471470
hardbreak_if_not_bol(s);
472471
maybe_print_comment(s, meth.span.lo);
473472
print_fn(s, meth.node.meth.decl, meth.node.meth.proto,
474-
meth.node.ident, typarams, []);
473+
meth.node.ident, meth.node.tps, []);
475474
word(s.s, " ");
476475
print_block(s, meth.node.meth.body);
477476
}
@@ -490,7 +489,7 @@ fn print_item(s: ps, &&item: @ast::item) {
490489
hardbreak_if_not_bol(s);
491490
maybe_print_comment(s, meth.span.lo);
492491
print_fn(s, meth.node.meth.decl, meth.node.meth.proto,
493-
meth.node.ident, [], []);
492+
meth.node.ident, meth.node.tps, []);
494493
word(s.s, " ");
495494
print_block(s, meth.node.meth.body);
496495
}
@@ -964,11 +963,10 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
964963

965964
// Methods
966965
for meth: @ast::method in anon_obj.methods {
967-
let typarams: [ast::ty_param] = [];
968966
hardbreak_if_not_bol(s);
969967
maybe_print_comment(s, meth.span.lo);
970968
print_fn(s, meth.node.meth.decl, meth.node.meth.proto,
971-
meth.node.ident, typarams, []);
969+
meth.node.ident, meth.node.tps, []);
972970
word(s.s, " ");
973971
print_block(s, meth.node.meth.body);
974972
}

src/test/compile-fail/direct-obj-fn-call.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// error-pattern: attempted field access
1+
// error-pattern: attempted access of field hello
22

33
obj x() {
44
fn hello() { log "hello"; }

src/test/compile-fail/self-missing-method.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// error-pattern:attempted field access on type fn
1+
// error-pattern:attempted access of field m on type fn
22
fn main() {
33

44
obj foo() {

src/test/compile-fail/vec-field.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// error-pattern:attempted field access on type [int]
1+
// error-pattern:attempted access of field some_field_name on type [int]
22
// issue #367
33

44
fn f() {

src/test/run-pass/static-impl.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,33 @@ mod b {
99
impl baz for str { fn plus() -> int { 200 } }
1010
}
1111

12+
impl util for uint {
13+
fn str() -> str { uint::str(self) }
14+
fn times(f: block(uint)) {
15+
let c = 0u;
16+
while c < self { f(c); c += 1u; }
17+
}
18+
}
19+
20+
impl util<T> for [T] {
21+
fn len() -> uint { vec::len(self) }
22+
fn iter(f: block(T)) { for x in self { f(x); } }
23+
fn map<U>(f: block(T) -> U) -> [U] {
24+
let r = [];
25+
for elt in self { r += [f(elt)]; }
26+
r
27+
}
28+
}
29+
1230
fn main() {
1331
impl foo for int { fn plus() -> int { self + 10 } }
1432
assert 10.plus() == 20;
1533
assert 10u.plus() == 30;
1634
assert "hi".plus() == 200;
17-
}
1835

36+
assert [1].len().str() == "1";
37+
assert [3, 4].map({|a| a + 4})[0] == 7;
38+
let x = 0u;
39+
10u.times {|_n| x += 2u;}
40+
assert x == 20u;
41+
}

0 commit comments

Comments
 (0)