Skip to content

Commit

Permalink
Obliterate the callee_id hack
Browse files Browse the repository at this point in the history
Exprs that could be applications of overloaded operators
(expr_unary, expr_binary, expr_index) relied on the previous node ID
being "reserved" to carry extra typechecking info. This was
incredibly error-prone. Fixed it; now all exprs have two node IDs
(which will be wasted in some cases; future work could make this
an option instead if the extra int field ends up being a performance
problem).

Closes #2804
  • Loading branch information
catamorphism committed Jul 13, 2012
1 parent fec8059 commit 78ec6fe
Show file tree
Hide file tree
Showing 21 changed files with 148 additions and 57 deletions.
2 changes: 1 addition & 1 deletion src/fuzzer/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn find_rust_files(&files: ~[str], path: str) {

fn common_exprs() -> ~[ast::expr] {
fn dse(e: ast::expr_) -> ast::expr {
{ id: 0, node: e, span: ast_util::dummy_sp() }
{ id: 0, callee_id: -1, node: e, span: ast_util::dummy_sp() }
}

fn dsl(l: ast::lit_) -> ast::lit {
Expand Down
3 changes: 2 additions & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ enum blk_check_mode { default_blk, unchecked_blk, unsafe_blk, }
enum expr_check_mode { claimed_expr, checked_expr, }

#[auto_serialize]
type expr = {id: node_id, node: expr_, span: span};
type expr = {id: node_id, callee_id: node_id, node: expr_, span: span};
// Extra node ID is only used for index, assign_op, unary, binary

#[auto_serialize]
enum alt_mode { alt_check, alt_exhaustive, }
Expand Down
13 changes: 1 addition & 12 deletions src/libsyntax/ast_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,6 @@ pure fn unguarded_pat(a: arm) -> option<~[@pat]> {
if is_unguarded(a) { some(/* FIXME (#2543) */ copy a.pats) } else { none }
}

// Provides an extra node_id to hang callee information on, in case the
// operator is deferred to a user-supplied method. The parser is responsible
// for reserving this id.
fn op_expr_callee_id(e: @expr) -> node_id { e.id - 1 }

pure fn class_item_ident(ci: @class_member) -> ident {
alt ci.node {
instance_var(i,_,_,_,_) { /* FIXME (#2543) */ copy i }
Expand Down Expand Up @@ -455,14 +450,8 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
},

visit_expr: fn@(e: @expr) {
vfn(e.callee_id);
vfn(e.id);
alt e.node {
expr_index(*) | expr_assign_op(*) |
expr_unary(*) | expr_binary(*) {
vfn(ast_util::op_expr_callee_id(e));
}
_ { /* fallthrough */ }
}
},

visit_ty: fn@(t: @ty) {
Expand Down
3 changes: 2 additions & 1 deletion src/libsyntax/ext/auto_serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ impl helpers for ext_ctxt {
}

fn expr(span: span, node: ast::expr_) -> @ast::expr {
@{id: self.next_id(), node: node, span: span}
@{id: self.next_id(), callee_id: self.next_id(),
node: node, span: span}
}

fn var_ref(span: span, name: ast::ident) -> @ast::expr {
Expand Down
7 changes: 4 additions & 3 deletions src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import base::ext_ctxt;

fn mk_expr(cx: ext_ctxt, sp: codemap::span, expr: ast::expr_) ->
@ast::expr {
ret @{id: cx.next_id(), node: expr, span: sp};
ret @{id: cx.next_id(), callee_id: cx.next_id(),
node: expr, span: sp};
}

fn mk_lit(cx: ext_ctxt, sp: span, lit: ast::lit_) -> @ast::expr {
let sp_lit = @{node: lit, span: sp};
ret @{id: cx.next_id(), node: ast::expr_lit(sp_lit), span: sp};
mk_expr(cx, sp, ast::expr_lit(sp_lit))
}
fn mk_str(cx: ext_ctxt, sp: span, s: str) -> @ast::expr {
let lit = ast::lit_str(@s);
Expand Down Expand Up @@ -62,7 +63,7 @@ fn mk_call(cx: ext_ctxt, sp: span, fn_path: ~[ast::ident],
fn mk_base_vec_e(cx: ext_ctxt, sp: span, exprs: ~[@ast::expr]) ->
@ast::expr {
let vecexpr = ast::expr_vec(exprs, ast::m_imm);
ret @{id: cx.next_id(), node: vecexpr, span: sp};
mk_expr(cx, sp, vecexpr)
}
fn mk_vstore_e(cx: ext_ctxt, sp: span, expr: @ast::expr, vst: ast::vstore) ->
@ast::expr {
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/ext/concat_idents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
}

ret @{id: cx.next_id(),
callee_id: cx.next_id(),
node: ast::expr_path(@{span: sp, global: false, idents: ~[@res],
rp: none, types: ~[]}),
span: sp};
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/ext/log_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
);

//trivial expression
ret @{id: cx.next_id(), node: ast::expr_rec(~[], option::none),
span: sp};
ret @{id: cx.next_id(), callee_id: cx.next_id(),
node: ast::expr_rec(~[], option::none), span: sp};
}
2 changes: 1 addition & 1 deletion src/libsyntax/ext/simplext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import base::*;
import fold::*;
import ast_util::respan;
import ast::{ident, path, ty, blk_, expr, expr_path,
expr_vec, expr_mac, mac_invoc, node_id};
expr_vec, expr_mac, mac_invoc, node_id, expr_index};

export add_new_extension;

Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,7 @@ impl of ast_fold for ast_fold_precursor {
fn fold_expr(&&x: @expr) -> @expr {
let (n, s) = self.fold_expr(x.node, x.span, self as ast_fold);
ret @{id: self.new_id(x.id),
callee_id: self.new_id(x.callee_id),
node: n,
span: self.new_span(s)};
}
Expand Down
10 changes: 7 additions & 3 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import print::pprust::expr_to_str;

import result::result;
import either::{either, left, right};
import std::map::{hashmap, str_hash};
Expand Down Expand Up @@ -758,11 +760,13 @@ class parser {
}

fn mk_expr(lo: uint, hi: uint, +node: expr_) -> @expr {
ret @{id: self.get_id(), node: node, span: mk_sp(lo, hi)};
ret @{id: self.get_id(), callee_id: self.get_id(),
node: node, span: mk_sp(lo, hi)};
}

fn mk_mac_expr(lo: uint, hi: uint, m: mac_) -> @expr {
ret @{id: self.get_id(),
callee_id: self.get_id(),
node: expr_mac({node: m, span: mk_sp(lo, hi)}),
span: mk_sp(lo, hi)};
}
Expand All @@ -772,7 +776,8 @@ class parser {
let lv_lit = @{node: lit_uint(i as u64, ty_u32),
span: span};

ret @{id: self.get_id(), node: expr_lit(lv_lit), span: span};
ret @{id: self.get_id(), callee_id: self.get_id(),
node: expr_lit(lv_lit), span: span};
}

fn mk_pexpr(lo: uint, hi: uint, node: expr_) -> pexpr {
Expand Down Expand Up @@ -1112,7 +1117,6 @@ class parser {
let ix = self.parse_expr();
hi = ix.span.hi;
self.expect(token::RBRACKET);
self.get_id(); // see ast_util::op_expr_callee_id
e = self.mk_pexpr(lo, hi, expr_index(self.to_expr(e), ix));
}

Expand Down
28 changes: 20 additions & 8 deletions src/rustc/front/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,11 @@ fn mk_test_desc_vec(cx: test_ctxt) -> @ast::expr {
}

let inner_expr = @{id: cx.sess.next_node_id(),
callee_id: cx.sess.next_node_id(),
node: ast::expr_vec(descs, ast::m_imm),
span: dummy_sp()};
ret @{id: cx.sess.next_node_id(),
callee_id: cx.sess.next_node_id(),
node: ast::expr_vstore(inner_expr, ast::vstore_uniq),
span: dummy_sp()};
}
Expand All @@ -300,6 +302,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {
nospan(ast::lit_str(@ast_util::path_name_i(path)));
let name_expr: ast::expr =
{id: cx.sess.next_node_id(),
callee_id: cx.sess.next_node_id(),
node: ast::expr_lit(@name_lit),
span: span};

Expand All @@ -310,6 +313,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {

let fn_expr: ast::expr =
{id: cx.sess.next_node_id(),
callee_id: cx.sess.next_node_id(),
node: ast::expr_path(fn_path),
span: span};

Expand All @@ -322,6 +326,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {

let ignore_expr: ast::expr =
{id: cx.sess.next_node_id(),
callee_id: cx.sess.next_node_id(),
node: ast::expr_lit(@ignore_lit),
span: span};

Expand All @@ -332,6 +337,7 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {

let fail_expr: ast::expr =
{id: cx.sess.next_node_id(),
callee_id: cx.sess.next_node_id(),
node: ast::expr_lit(@fail_lit),
span: span};

Expand All @@ -342,7 +348,8 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {
ast::expr_rec(~[name_field, fn_field, ignore_field, fail_field],
option::none);
let desc_rec: ast::expr =
{id: cx.sess.next_node_id(), node: desc_rec_, span: span};
{id: cx.sess.next_node_id(), callee_id: cx.sess.next_node_id(),
node: desc_rec_, span: span};
ret @desc_rec;
}

Expand All @@ -354,6 +361,7 @@ fn mk_test_wrapper(cx: test_ctxt,
span: span) -> @ast::expr {
let call_expr: ast::expr = {
id: cx.sess.next_node_id(),
callee_id: cx.sess.next_node_id(),
node: ast::expr_call(@fn_path_expr, ~[], false),
span: span
};
Expand All @@ -379,6 +387,7 @@ fn mk_test_wrapper(cx: test_ctxt,

let wrapper_expr: ast::expr = {
id: cx.sess.next_node_id(),
callee_id: cx.sess.next_node_id(),
node: ast::expr_fn(ast::proto_bare, wrapper_decl,
wrapper_body, @~[]),
span: span
Expand Down Expand Up @@ -444,37 +453,40 @@ fn mk_test_main_call(cx: test_ctxt) -> @ast::expr {
let args_path_expr_: ast::expr_ = ast::expr_path(args_path);

let args_path_expr: ast::expr =
{id: cx.sess.next_node_id(), node: args_path_expr_, span: dummy_sp()};
{id: cx.sess.next_node_id(), callee_id: cx.sess.next_node_id(),
node: args_path_expr_, span: dummy_sp()};

// Call __test::test to generate the vector of test_descs
let test_path = path_node(~[@"tests"]);

let test_path_expr_: ast::expr_ = ast::expr_path(test_path);

let test_path_expr: ast::expr =
{id: cx.sess.next_node_id(), node: test_path_expr_, span: dummy_sp()};
{id: cx.sess.next_node_id(), callee_id: cx.sess.next_node_id(),
node: test_path_expr_, span: dummy_sp()};

let test_call_expr_ = ast::expr_call(@test_path_expr, ~[], false);

let test_call_expr: ast::expr =
{id: cx.sess.next_node_id(), node: test_call_expr_, span: dummy_sp()};
{id: cx.sess.next_node_id(), callee_id: cx.sess.next_node_id(),
node: test_call_expr_, span: dummy_sp()};

// Call std::test::test_main
let test_main_path = path_node(mk_path(cx, ~[@"test", @"test_main"]));

let test_main_path_expr_: ast::expr_ = ast::expr_path(test_main_path);

let test_main_path_expr: ast::expr =
{id: cx.sess.next_node_id(), node: test_main_path_expr_,
span: dummy_sp()};
{id: cx.sess.next_node_id(), callee_id: cx.sess.next_node_id(),
node: test_main_path_expr_, span: dummy_sp()};

let test_main_call_expr_: ast::expr_ =
ast::expr_call(@test_main_path_expr,
~[@args_path_expr, @test_call_expr], false);

let test_main_call_expr: ast::expr =
{id: cx.sess.next_node_id(), node: test_main_call_expr_,
span: dummy_sp()};
{id: cx.sess.next_node_id(), callee_id: cx.sess.next_node_id(),
node: test_main_call_expr_, span: dummy_sp()};

ret @test_main_call_expr;
}
Expand Down
1 change: 0 additions & 1 deletion src/rustc/middle/borrowck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ import std::list::{list, cons, nil};
import result::{result, ok, err, extensions};
import syntax::print::pprust;
import util::common::indenter;
import ast_util::op_expr_callee_id;
import ty::to_str;
import driver::session::session;
import dvec::{dvec, extensions};
Expand Down
4 changes: 2 additions & 2 deletions src/rustc/middle/borrowck/check_loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,15 +616,15 @@ fn check_loans_in_expr(expr: @ast::expr,
if self.bccx.method_map.contains_key(expr.id) {
self.check_call(expr,
none,
ast_util::op_expr_callee_id(expr),
expr.callee_id,
expr.span,
~[rval]);
}
ast::expr_unary(*) | ast::expr_index(*)
if self.bccx.method_map.contains_key(expr.id) {
self.check_call(expr,
none,
ast_util::op_expr_callee_id(expr),
expr.callee_id,
expr.span,
~[]);
}
Expand Down
1 change: 1 addition & 0 deletions src/rustc/middle/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) {
visit_stmt: fn@(s: @ast::stmt) {
alt s.node {
ast::stmt_semi(@{id: id,
callee_id: _,
node: ast::expr_path(@path),
span: _}, _) {
cx.sess.span_lint(
Expand Down
24 changes: 11 additions & 13 deletions src/rustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1475,12 +1475,12 @@ fn trans_unary(bcx: block, op: ast::unop, e: @ast::expr,
// Check for user-defined method call
alt bcx.ccx().maps.method_map.find(un_expr.id) {
some(mentry) {
let callee_id = ast_util::op_expr_callee_id(un_expr);
let fty = node_id_type(bcx, callee_id);
let fty = node_id_type(bcx, un_expr.callee_id);
ret trans_call_inner(
bcx, un_expr.info(), fty,
expr_ty(bcx, un_expr),
|bcx| impl::trans_method_callee(bcx, callee_id, e, mentry),
|bcx| impl::trans_method_callee(bcx, un_expr.callee_id, e,
mentry),
arg_exprs(~[]), dest);
}
_ {}
Expand Down Expand Up @@ -1703,10 +1703,9 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
alt bcx.ccx().maps.method_map.find(ex.id) {
some(origin) {
let bcx = lhs_res.bcx;
let callee_id = ast_util::op_expr_callee_id(ex);
#debug["user-defined method callee_id: %s",
ast_map::node_id_to_str(bcx.tcx().items, callee_id)];
let fty = node_id_type(bcx, callee_id);
ast_map::node_id_to_str(bcx.tcx().items, ex.callee_id)];
let fty = node_id_type(bcx, ex.callee_id);

let dty = expr_ty(bcx, dst);
let target = alloc_ty(bcx, dty);
Expand All @@ -1717,7 +1716,7 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
|bcx| {
// FIXME (#2528): provide the already-computed address, not
// the expr.
impl::trans_method_callee(bcx, callee_id, dst, origin)
impl::trans_method_callee(bcx, ex.callee_id, dst, origin)
},
arg_exprs(~[src]), save_in(target));

Expand Down Expand Up @@ -1851,13 +1850,12 @@ fn trans_binary(bcx: block, op: ast::binop, lhs: @ast::expr,
// User-defined operators
alt bcx.ccx().maps.method_map.find(ex.id) {
some(origin) {
let callee_id = ast_util::op_expr_callee_id(ex);
let fty = node_id_type(bcx, callee_id);
let fty = node_id_type(bcx, ex.callee_id);
ret trans_call_inner(
bcx, ex.info(), fty,
expr_ty(bcx, ex),
|bcx| {
impl::trans_method_callee(bcx, callee_id, lhs, origin)
impl::trans_method_callee(bcx, ex.callee_id, lhs, origin)
},
arg_exprs(~[rhs]), dest);
}
Expand Down Expand Up @@ -3597,12 +3595,12 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
// If it is here, it's not an lval, so this is a user-defined
// index op
let origin = bcx.ccx().maps.method_map.get(e.id);
let callee_id = ast_util::op_expr_callee_id(e);
let fty = node_id_type(bcx, callee_id);
let fty = node_id_type(bcx, e.callee_id);
ret trans_call_inner(
bcx, e.info(), fty,
expr_ty(bcx, e),
|bcx| impl::trans_method_callee(bcx, callee_id, base, origin),
|bcx| impl::trans_method_callee(bcx, e.callee_id, base,
origin),
arg_exprs(~[idx]), dest);
}

Expand Down
Loading

5 comments on commit 78ec6fe

@nikomatsakis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Horray!

@nikomatsakis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading more carefully—do we really want to allocate a second ID for all expressions? It certainly makes our expression ids less tight, so things like smallintmap will be less effective. It will also probably affect our hash functions etc (not that these are especially well-tuned, but they will want to take into account that most IDs will be even or odd). I had expected to add a new field to expr_index(), expr_binary(), and other things that could be overloaded. This has the advantage of making it clearer which expression forms can correspond to overloaded methods, which to me is quite unclear right now (I am not sure of the full set of forms, to be honest)

@nikomatsakis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(To be clear, I see though that there is an advantage in making thee code more uniform. This is an area where unification of enums/classes would be very useful, I think, as we could have a base enum for overloadable things which defines the callee_id field)

@catamorphism
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered doing it the way you suggest, but I didn't like having to change all the pattern-matches. Ideally callee_id would be an option that's only defined if the node field is in a certain refinement of expr_, but we can't do that right now...

Maybe it's worth changing once we unify enums/classes? If in the meantime someone does profiling and finds it's a terrible performance loss, I could change it sooner.

@nikomatsakis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait and see sounds reasonable.

Please sign in to comment.