提交 e2fa6f03 编写于 作者: T Tim Chevalier

Translate simple classes

    Programs using classes with fields only (no methods) compile and run,
    as long as nothing refers to a class in a different crate (todo).

    Also changed the AST representation of classes to have a separate
    record for constructor info (instead of inlining the fields in the
    item_class node), and fixed up spans and pretty-printing for
    classes.
上级 1d826b73
此差异已折叠。
......@@ -127,7 +127,7 @@ fn encode_module_item_paths(ebml_w: ebml::writer, module: _mod, path: [str],
encode_def_id(ebml_w, local_def(it.id));
ebml_w.end_tag();
}
item_class(_,_,_,_,_) {
item_class(_,_,_) {
fail "encode: implement item_class";
}
item_enum(variants, tps) {
......@@ -384,7 +384,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
encode_enum_variant_info(ecx, ebml_w, item.id, variants,
path, index, tps);
}
item_class(_,_,_,_,_) {
item_class(_,_,_) {
fail "encode: implement item_class";
}
item_res(_, tps, _, _, ctor_id) {
......
......@@ -541,12 +541,12 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
v.visit_ty(m.decl.output, msc, v);
}
}
ast::item_class(tps, members, ctor_id, ctor_decl, ctor_block) {
ast::item_class(tps, members, ctor) {
visit::visit_ty_params(tps, sc, v);
let class_scope = cons(scope_item(i), @sc);
/* visit the constructor... */
visit_fn_with_scope(e, visit::fk_item_fn(i.ident, tps), ctor_decl,
ctor_block, ctor_block.span, ctor_id,
visit_fn_with_scope(e, visit::fk_item_fn(i.ident, tps), ctor.node.dec,
ctor.node.body, ctor.span, ctor.node.id,
class_scope, v);
/* visit the items */
for cm in members {
......@@ -1029,12 +1029,12 @@ fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) ->
ast::item_native_mod(m) {
ret lookup_in_local_native_mod(e, it.id, sp, name, ns);
}
ast::item_class(tps, members, ctor_id, _, _) {
ast::item_class(tps, members, ctor) {
if ns == ns_type {
ret lookup_in_ty_params(e, name, tps);
}
if ns == ns_val(value_or_enum) && name == it.ident {
ret some(ast::def_fn(local_def(ctor_id),
ret some(ast::def_fn(local_def(ctor.node.id),
ast::impure_fn));
}
if ns == ns_val(value_or_enum) {
......@@ -1359,7 +1359,7 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option<def> {
_ { }
}
}
ast::item_class(_, _, _, _, _) {
ast::item_class(_, _, _) {
if ns == ns_type {
ret some(ast::def_class(local_def(i.id)));
}
......@@ -1664,16 +1664,16 @@ fn index_mod(md: ast::_mod) -> mod_index {
variant_idx += 1u;
}
}
ast::item_class(tps, items, ctor_id, ctor_decl, ctor_body) {
ast::item_class(tps, items, ctor) {
// add the class name itself
add_to_index(index, it.ident, mie_item(it));
// add the constructor decl
add_to_index(index, it.ident,
mie_item(@{ident: it.ident, attrs: [],
id: ctor_id,
node:
item_fn(ctor_decl, tps, ctor_body),
span: ctor_body.span}));
id: ctor.node.id,
node:
item_fn(ctor.node.dec, tps, ctor.node.body),
span: ctor.node.body.span}));
// add the members
for ci in items {
add_to_index(index, class_item_ident(ci),
......
......@@ -49,6 +49,8 @@
import type_of::type_of; // Issue #1873
import ast_map::{path, path_mod, path_name};
import std::smallintmap;
// Destinations
// These are passed around by the code generating functions to track the
......@@ -1208,6 +1210,15 @@ fn iter_variant(cx: block, a_tup: ValueRef,
}
ret next_cx;
}
ty::ty_class(did, tps) {
// a class is like a record type
let i: int = 0;
for fld: ty::field in ty::class_items_as_fields(cx.tcx(), did) {
let {bcx: bcx, val: llfld_a} = GEP_tup_like(cx, t, av, [0, i]);
cx = f(bcx, llfld_a, fld.mt.ty);
i += 1;
}
}
_ { cx.sess().unimpl("type in iter_structural_ty"); }
}
ret cx;
......@@ -2096,7 +2107,7 @@ fn monomorphic_fn(ccx: crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
alt check map_node {
ast_map::node_item(@{node: ast::item_fn(decl, _, body), _}, _) {
trans_fn(ccx, pt, decl, body, lldecl, no_self, [],
psubsts, fn_id.node);
psubsts, fn_id.node, none);
}
ast_map::node_item(@{node: ast::item_res(decl, _, _, _, _), _}, _) {
trans_res_ctor(ccx, pt, decl, fn_id.node, [], psubsts, lldecl);
......@@ -2112,7 +2123,7 @@ fn monomorphic_fn(ccx: crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
let selfty = ty::lookup_item_type(ccx.tcx, impl_def_id).ty;
let selfty = ty::substitute_type_params(ccx.tcx, substs, selfty);
trans_fn(ccx, pt, mth.decl, mth.body, lldecl,
impl_self(selfty), [], psubsts, fn_id.node);
impl_self(selfty), [], psubsts, fn_id.node, none);
}
}
some({llfn: lldecl, fty: mono_ty})
......@@ -2267,17 +2278,26 @@ fn take_local(table: hashmap<ast::node_id, local_val>,
ret {val: ptr, kind: owned};
}
_ {
cx.sess().unimpl("unsupported def type in trans_local_def");
cx.sess().unimpl(#fmt("unsupported def type in trans_local_def: %?",
def));
}
}
}
fn trans_path(cx: block, id: ast::node_id)
// The third argument (path) ends up getting used when the id
// refers to a field within the enclosing class, since the name
// gets turned into a record field name.
fn trans_path(cx: block, id: ast::node_id, path: @ast::path)
-> lval_maybe_callee {
ret trans_var(cx, cx.tcx().def_map.get(id), id);
alt cx.tcx().def_map.find(id) {
none { cx.sess().bug("trans_path: unbound node ID"); }
some(df) {
ret trans_var(cx, df, id, path);
}
}
}
fn trans_var(cx: block, def: ast::def, id: ast::node_id)
fn trans_var(cx: block, def: ast::def, id: ast::node_id, path: @ast::path)
-> lval_maybe_callee {
let ccx = cx.ccx();
alt def {
......@@ -2313,6 +2333,18 @@ fn trans_var(cx: block, def: ast::def, id: ast::node_id)
ret lval_no_env(cx, load_if_immediate(cx, val, tp), owned_imm);
}
}
ast::def_class_field(parent, did) {
// base is implicitly "Self"
alt cx.fcx.self_id {
some(slf) {
let {bcx, val, kind} = trans_rec_field(cx, slf,
// TODO: only supporting local objects for now
path_to_ident(path));
ret lval_no_env(bcx, val, kind);
}
_ { cx.sess().bug("unbound self param in class"); }
}
}
_ {
let loc = trans_local_var(cx, def);
ret lval_no_env(cx, loc.val, loc.kind);
......@@ -2326,6 +2358,7 @@ fn trans_rec_field(bcx: block, base: @ast::expr,
let {bcx, val, ty} = autoderef(bcx, val, expr_ty(bcx, base));
let fields = alt ty::get(ty).struct {
ty::ty_rec(fs) { fs }
ty::ty_class(did,_) { ty::class_items_as_fields(bcx.tcx(), did) }
// Constraint?
_ { bcx.tcx().sess.span_bug(base.span, "trans_rec_field:\
base expr has non-record type"); }
......@@ -2386,7 +2419,7 @@ fn expr_is_lval(bcx: block, e: @ast::expr) -> bool {
fn trans_callee(bcx: block, e: @ast::expr) -> lval_maybe_callee {
alt e.node {
ast::expr_path(_) { ret trans_path(bcx, e.id); }
ast::expr_path(path) { ret trans_path(bcx, e.id, path); }
ast::expr_field(base, ident, _) {
// Lval means this is a record field, so not a method
if !expr_is_lval(bcx, e) {
......@@ -2412,8 +2445,8 @@ fn trans_callee(bcx: block, e: @ast::expr) -> lval_maybe_callee {
// immediate).
fn trans_lval(cx: block, e: @ast::expr) -> lval_result {
alt e.node {
ast::expr_path(_) {
let v = trans_path(cx, e.id);
ast::expr_path(p) {
let v = trans_path(cx, e.id, p);
ret lval_maybe_callee_to_lval(v, expr_ty(cx, e));
}
ast::expr_field(base, ident, _) {
......@@ -3839,6 +3872,7 @@ fn mk_standard_basic_blocks(llfn: ValueRef) ->
// - trans_args
fn new_fn_ctxt_w_id(ccx: crate_ctxt, path: path,
llfndecl: ValueRef, id: ast::node_id,
maybe_self_id: option<@ast::expr>,
param_substs: option<param_substs>,
sp: option<span>) -> fn_ctxt {
let llbbs = mk_standard_basic_blocks(llfndecl);
......@@ -3860,6 +3894,7 @@ fn new_fn_ctxt_w_id(ccx: crate_ctxt, path: path,
mutable lltyparams: [],
derived_tydescs: ty::new_ty_hash(),
id: id,
self_id: maybe_self_id,
param_substs: param_substs,
span: sp,
path: path,
......@@ -3868,7 +3903,7 @@ fn new_fn_ctxt_w_id(ccx: crate_ctxt, path: path,
fn new_fn_ctxt(ccx: crate_ctxt, path: path, llfndecl: ValueRef,
sp: option<span>) -> fn_ctxt {
ret new_fn_ctxt_w_id(ccx, path, llfndecl, -1, none, sp);
ret new_fn_ctxt_w_id(ccx, path, llfndecl, -1, none, none, sp);
}
// NB: must keep 4 fns in sync:
......@@ -3991,12 +4026,13 @@ fn trans_closure(ccx: crate_ctxt, path: path, decl: ast::fn_decl,
ty_self: self_arg,
tps_bounds: [ty::param_bounds],
param_substs: option<param_substs>,
id: ast::node_id, maybe_load_env: fn(fn_ctxt)) {
id: ast::node_id, maybe_self_id: option<@ast::expr>,
maybe_load_env: fn(fn_ctxt)) {
set_uwtable(llfndecl);
// Set up arguments to the function.
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, param_substs,
some(body.span));
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, maybe_self_id,
param_substs, some(body.span));
create_llargs_for_fn_args(fcx, ty_self, decl.inputs, tps_bounds);
// Create the first basic block in the function and keep a handle on it to
......@@ -4014,9 +4050,14 @@ fn trans_closure(ccx: crate_ctxt, path: path, decl: ast::fn_decl,
// translation calls that don't have a return value (trans_crate,
// trans_mod, trans_item, et cetera) and those that do
// (trans_block, trans_expr, et cetera).
if option::is_none(body.node.expr) ||
if option::is_none(maybe_self_id) // hack --
/* avoids the need for special cases to assign a type to
the constructor body (since it has no explicit return) */
&&
(option::is_none(body.node.expr) ||
ty::type_is_bot(block_ty) ||
ty::type_is_nil(block_ty) {
ty::type_is_nil(block_ty)) {
bcx = trans_block(bcx, body, ignore);
} else {
bcx = trans_block(bcx, body, save_in(fcx.llretptr));
......@@ -4037,12 +4078,13 @@ fn trans_fn(ccx: crate_ctxt,
ty_self: self_arg,
tps_bounds: [ty::param_bounds],
param_substs: option<param_substs>,
id: ast::node_id) {
id: ast::node_id,
maybe_self_id: option<@ast::expr>) {
let do_time = ccx.sess.opts.stats;
let start = if do_time { time::get_time() }
else { {sec: 0u32, usec: 0u32} };
trans_closure(ccx, path, decl, body, llfndecl, ty_self,
tps_bounds, param_substs, id, {|fcx|
tps_bounds, param_substs, id, maybe_self_id, {|fcx|
if ccx.sess.opts.extra_debuginfo {
debuginfo::create_function(fcx);
}
......@@ -4058,7 +4100,7 @@ fn trans_res_ctor(ccx: crate_ctxt, path: path, dtor: ast::fn_decl,
param_substs: option<param_substs>, llfndecl: ValueRef) {
// Create a function for the constructor
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, ctor_id,
param_substs, none);
none, param_substs, none);
create_llargs_for_fn_args(fcx, no_self, dtor.inputs, tps_bounds);
let bcx = top_scope_block(fcx, none), lltop = bcx.llbb;
let fty = node_id_type(bcx, ctor_id);
......@@ -4100,7 +4142,7 @@ fn trans_enum_variant(ccx: crate_ctxt, enum_id: ast::node_id,
ident: "arg" + uint::to_str(i, 10u),
id: varg.id}];
}
let fcx = new_fn_ctxt_w_id(ccx, [], llfndecl, variant.node.id,
let fcx = new_fn_ctxt_w_id(ccx, [], llfndecl, variant.node.id, none,
param_substs, none);
create_llargs_for_fn_args(fcx, no_self, fn_args,
param_bounds(ccx, ty_params));
......@@ -4261,7 +4303,7 @@ fn trans_item(ccx: crate_ctxt, item: ast::item) {
if decl.purity != ast::crust_fn {
trans_fn(ccx, *path + [path_name(item.ident)], decl, body,
llfndecl, no_self, param_bounds(ccx, tps),
none, item.id);
none, item.id, none);
} else {
native::trans_crust_fn(ccx, *path + [path_name(item.ident)],
decl, body, llfndecl, item.id);
......@@ -4280,7 +4322,7 @@ fn trans_item(ccx: crate_ctxt, item: ast::item) {
some(lldtor_decl) {
trans_fn(ccx, *path + [path_name(item.ident)], decl, body,
lldtor_decl, no_self, param_bounds(ccx, tps),
none, dtor_id);
none, dtor_id, none);
}
_ {
ccx.sess.span_fatal(item.span, "unbound dtor in trans_item");
......@@ -4311,6 +4353,83 @@ fn trans_item(ccx: crate_ctxt, item: ast::item) {
};
native::trans_native_mod(ccx, native_mod, abi);
}
ast::item_class(tps, items, ctor) {
alt ccx.item_ids.find(ctor.node.id) {
some(llctor_decl) {
// Translate the ctor
// First, add a preamble that
// generates a new name, obj:
// let obj = { ... } (uninit record fields)
let sess = ccx.sess;
let rslt_path_ = {global: false,
idents: ["obj"],
types: []}; // ??
let rslt_path = @{node: rslt_path_,
span: ctor.node.body.span};
let rslt_id : ast::node_id = sess.next_node_id();
let rslt_pat : @ast::pat =
@{id: sess.next_node_id(),
node: ast::pat_ident(rslt_path, none),
span: ctor.node.body.span};
// Set up obj's type
let rslt_ast_ty : @ast::ty = @{node: ast::ty_infer,
span: ctor.node.body.span};
// kludgy
let ty_args = [], i = 0u;
for tp in tps {
ty_args += [ty::mk_param(ccx.tcx, i,
local_def(tps[i].id))];
}
let rslt_ty = ty::mk_class(ccx.tcx,
local_def(item.id),
ty_args);
// Set up a local for obj
let rslt_loc_ : ast::local_ = {is_mutbl: true,
ty: rslt_ast_ty, // ???
pat: rslt_pat,
init: none::<ast::initializer>,
id: rslt_id};
// Register a type for obj
smallintmap::insert(*ccx.tcx.node_types,
rslt_loc_.id as uint, rslt_ty);
// Create the decl statement that initializers obj
let rslt_loc : @ast::local =
@{node: rslt_loc_, span: ctor.node.body.span};
let rslt_decl_ : ast::decl_ = ast::decl_local([rslt_loc]);
let rslt_decl : @ast::decl
= @{node: rslt_decl_, span: ctor.node.body.span};
let prologue : @ast::stmt = @{node: ast::stmt_decl(rslt_decl,
sess.next_node_id()),
span: ctor.node.body.span};
let rslt_node_id = sess.next_node_id();
ccx.tcx.def_map.insert(rslt_node_id,
ast::def_local(rslt_loc_.id, true));
// And give the statement a type
smallintmap::insert(*ccx.tcx.node_types,
rslt_node_id as uint, rslt_ty);
// The result expression of the constructor is now a
// reference to obj
let rslt_expr : @ast::expr =
@{id: rslt_node_id,
node: ast::expr_path(rslt_path),
span: ctor.node.body.span};
let ctor_body_new : ast::blk_ = {stmts: [prologue]
+ ctor.node.body.node.stmts,
expr: some(rslt_expr)
with ctor.node.body.node};
let ctor_body__ : ast::blk = {node: ctor_body_new
with ctor.node.body};
trans_fn(ccx, *path + [path_name(item.ident)], ctor.node.dec,
ctor_body__, llctor_decl, no_self,
param_bounds(ccx, tps), none, ctor.node.id,
some(rslt_expr));
// TODO: translate methods!
}
_ {
ccx.sess.span_bug(item.span, "unbound ctor in trans_item");
}
}
}
_ {/* fall through */ }
}
}
......@@ -4348,7 +4467,7 @@ fn trans_inlined_items(ccx: crate_ctxt, inline_map: inline_map) {
let llfndecl = ccx.item_ids.get(m.id);
trans_fn(ccx, m_path, m.decl, m.body,
llfndecl, impl_self(impl_ty), m_bounds,
none, m.id);
none, m.id, none);
}
}
}
......@@ -4605,6 +4724,12 @@ fn collect_item(ccx: crate_ctxt, abi: @mutable option<ast::native_abi>,
}
}
}
ast::item_class(tps,_,ctor) {
// Register the ctor
let t = ty::node_id_to_type(ccx.tcx, ctor.node.id);
register_fn_full(ccx, i.span, my_path, "ctor",
param_bounds(ccx, tps), ctor.node.id, t);
}
_ { }
}
}
......
......@@ -470,7 +470,7 @@ fn trans_expr_fn(bcx: block,
ccx.tcx, id, proto, cap_clause);
let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, ck, id);
trans_closure(ccx, sub_path, decl, body, llfn, no_self, [],
bcx.fcx.param_substs, id, {|fcx|
bcx.fcx.param_substs, id, none, {|fcx|
load_environment(bcx, fcx, cdata_ty, cap_vars, ck);
});
llbox
......@@ -482,7 +482,7 @@ fn trans_expr_fn(bcx: block,
ast::proto_uniq { trans_closure_env(ty::ck_uniq) }
ast::proto_bare {
trans_closure(ccx, sub_path, decl, body, llfn, no_self, [], none,
id, {|_fcx|});
id, none, {|_fcx|});
C_null(T_opaque_box_ptr(ccx))
}
};
......
......@@ -196,6 +196,10 @@ enum local_val { local_mem(ValueRef), local_imm(ValueRef), }
// a user-defined function.
id: ast::node_id,
// The expr for the "self" object (only if this function corresponds
// to a class constructor function)
self_id: option<@ast::expr>,
// If this function is being monomorphized, this contains the type
// substitutions used.
param_substs: option<param_substs>,
......
......@@ -52,7 +52,7 @@ fn trans_impl(ccx: crate_ctxt, path: path, name: ast::ident,
let m_bounds = param_bounds(ccx, tps + m.tps);
trans_fn(ccx, sub_path + [path_name(m.ident)], m.decl, m.body,
llfn, impl_self(ty::node_id_to_type(ccx.tcx, id)),
m_bounds, none, m.id);
m_bounds, none, m.id, none);
}
_ {
ccx.sess.bug("Unbound id in trans_impl");
......
......@@ -274,7 +274,8 @@ fn build_rust_fn(ccx: crate_ctxt, path: ast_map::path,
ccx, path + [ast_map::path_name("__rust_abi")]);
let llty = type_of_fn_from_ty(ccx, t, []);
let llfndecl = decl_internal_cdecl_fn(ccx.llmod, ps, llty);
trans_fn(ccx, path, decl, body, llfndecl, no_self, [], none, id);
trans_fn(ccx, path, decl, body, llfndecl, no_self, [], none, id,
none);
ret llfndecl;
}
......
......@@ -2,6 +2,9 @@
import lib::llvm::{TypeRef};
import syntax::ast;
import lib::llvm::llvm;
import driver::session::session;
import ty::*;
fn type_of_explicit_args(cx: crate_ctxt, inputs: [ty::arg]) -> [TypeRef] {
vec::map(inputs) {|arg|
......@@ -102,8 +105,25 @@ fn type_of(cx: crate_ctxt, t: ty::t) -> TypeRef {
}
ty::ty_opaque_closure_ptr(_) { T_opaque_box_ptr(cx) }
ty::ty_constr(subt,_) { type_of(cx, subt) }
_ { fail "type_of not implemented for this kind of type"; }
ty::ty_class(did, _) {
let tys: [TypeRef] = [];
// TODO: only handles local classes
let cls_items = lookup_class_items(cx.tcx, did);
for ci in cls_items {
// only instance vars are record fields at runtime
alt ci.node.decl {
ast::instance_var(_,_,_,_) {
let fty = type_of(cx, class_item_type(cx.tcx, ci));
tys += [fty];
}
_ {}
}
}
T_struct(tys)
}
ty::ty_self(_) { cx.tcx.sess.unimpl("type_of: ty_self \
not implemented"); }
ty::ty_var(_) { cx.tcx.sess.bug("type_of shouldn't see a ty_var"); }
};
cx.lltypes.insert(t, llty);
ret llty;
......
......@@ -56,7 +56,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) {
ccx: ccx};
find_pre_post_fn(fcx, body);
}
item_class(_,_,_,_,_) {
item_class(_,_,_) {
fail "find_pre_post_item: implement item_class";
}
item_impl(_, _, _, ms) { for m in ms { find_pre_post_method(ccx, m); } }
......
......@@ -18,6 +18,8 @@
export args_eq;
export ast_constr_to_constr;
export block_ty;
export class_item_type;
export class_items_as_fields;
export constr;
export constr_general;
export constr_table;
......@@ -37,6 +39,7 @@
export get_element_type;
export is_binopable;
export is_pred_ty;
export lookup_class_items;
export lookup_item_type;
export method;
export method_idx;
......@@ -628,7 +631,7 @@ fn type_is_bool(ty: t) -> bool { get(ty).struct == ty_bool }
fn type_is_structural(ty: t) -> bool {
alt get(ty).struct {
ty_rec(_) | ty_tup(_) | ty_enum(_, _) | ty_fn(_) |
ty_rec(_) | ty_class(_,_) | ty_tup(_) | ty_enum(_, _) | ty_fn(_) |
ty_iface(_, _) | ty_res(_, _, _) { true }
_ { false }
}
......@@ -1228,7 +1231,10 @@ fn constrs_eq(cs: [@constr], ds: [@constr]) -> bool {
}
fn node_id_to_type(cx: ctxt, id: ast::node_id) -> t {
smallintmap::get(*cx.node_types, id as uint)
alt smallintmap::find(*cx.node_types, id as uint) {
some(t) { t }
none { cx.sess.bug(#fmt("node_id_to_type: unbound node ID %?", id)); }
}
}
fn node_id_to_type_params(cx: ctxt, id: ast::node_id) -> [t] {
......@@ -2292,6 +2298,54 @@ fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
}
}
// Look up the list of items for a given class (in the item map).
// Fails if the id is not bound to a class.
fn lookup_class_items(cx: ctxt, did: ast::def_id) -> [@class_item] {
alt cx.items.find(did.node) {
some(ast_map::node_item(i,_)) {
alt i.node {
ast::item_class(_, items, _) {
items
}
_ { cx.sess.bug("class ID bound to non-class"); }
}
}
_ { cx.sess.bug("class ID not bound to an item"); }
}
}
// Return a list of fields corresponding to the class's items
// (as if the class was a record). trans uses this
fn class_items_as_fields(cx:ctxt, did: ast::def_id) -> [field] {
let rslt = [];
for ci in lookup_class_items(cx, did) {
rslt += [alt ci.node.decl {
instance_var(i, _, _, id) {
// consider all instance vars mutable, because the
// constructor may mutate all vars
{ident: i, mt: {ty: node_id_to_type(cx, id),
mutbl: m_mutbl}}
}
class_method(it) {
{ident:it.ident, mt: {ty: node_id_to_type(cx, it.id),
mutbl: m_const}}
}
}];
}
rslt
}
// Looks up the type for a given class item. Must be called
// post-typechecking.
fn class_item_type(cx: ctxt, ci: @ast::class_item) -> t {
alt ci.node.decl {
ast::instance_var(_,_,_,id) { node_id_to_type(cx, id) }
// TODO: only works for local classes
ast::class_method(it) { lookup_item_type(cx,
ast_util::local_def(it.id)).ty }
}
}
fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool {
const tycat_other: int = 0;
const tycat_bool: int = 1;
......
......@@ -10,7 +10,7 @@
import middle::ty;
import middle::ty::{node_id_to_type, arg, block_ty,
expr_ty, field, node_type_table, mk_nil,
ty_param_bounds_and_ty};
ty_param_bounds_and_ty, lookup_class_items};
import util::ppaux::ty_to_str;
import middle::ty::unify::{ures_ok, ures_err, fix_ok, fix_err};
import std::smallintmap;
......@@ -375,7 +375,7 @@ fn instantiate(tcx: ty::ctxt, sp: span, mode: mode,
ast::def_class(class_id) {
alt tcx.items.find(class_id.node) {
some(ast_map::node_item(
@{node: ast::item_class(tps, _, _, _, _), _}, _)) {
@{node: ast::item_class(tps, _, _), _}, _)) {
if vec::len(tps) != vec::len(path.node.types) {
tcx.sess.span_err(ast_ty.span, "incorrect number of \
type parameters to object type");
......@@ -492,7 +492,7 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
ast::item_class(tps,_,_,_,_) {
ast::item_class(tps,_,_) {
let {bounds,params} = mk_ty_params(tcx, tps);
let t = ty::mk_class(tcx, local_def(it.id), params);
let tpt = {bounds: bounds, ty: t};
......@@ -944,7 +944,7 @@ fn convert(tcx: ty::ctxt, it: @ast::item) {
write_ty(tcx, it.id, tpt.ty);
ensure_iface_methods(tcx, it.id);
}
ast::item_class(tps, members, ctor_id, ctor_decl, ctor_block) {
ast::item_class(tps, members, ctor) {
// Write the class type
let {bounds,params} = mk_ty_params(tcx, tps);
let class_ty = ty::mk_class(tcx, local_def(it.id), params);
......@@ -954,9 +954,9 @@ fn convert(tcx: ty::ctxt, it: @ast::item) {
// Write the ctor type
let t_ctor = ty::mk_fn(tcx,
ty_of_fn_decl(tcx, m_collect,
ast::proto_any, ctor_decl));
write_ty(tcx, ctor_id, t_ctor);
tcx.tcache.insert(local_def(ctor_id),
ast::proto_any, ctor.node.dec));
write_ty(tcx, ctor.node.id, t_ctor);
tcx.tcache.insert(local_def(ctor.node.id),
{bounds: bounds, ty: t_ctor});
/* FIXME: check for proper public/privateness */
// Write the type of each of the members
......@@ -2549,19 +2549,9 @@ fn get_node(f: spanned<field>) -> field { f.node }
// For now, this code assumes the class is defined in the local
// crate
// FIXME: handle field references to classes in external crate
let err = "Class ID is not bound to a class";
let field_ty = alt fcx.ccx.tcx.items.find(base_id.node) {
some(ast_map::node_item(i,_)) {
alt i.node {
ast::item_class(_, items, _, _, _) {
lookup_field_ty(fcx.ccx.tcx, items, field,
expr.span)
}
_ { fcx.ccx.tcx.sess.span_bug(expr.span, err); }
}
}
_ { fcx.ccx.tcx.sess.span_bug(expr.span, err); }
};
let cls_items = lookup_class_items(tcx, base_id);
let field_ty = lookup_field_ty(fcx.ccx.tcx, cls_items, field,
expr.span);
// (2) look up what field's type is, and return it
// FIXME: actually instantiate any type params
write_ty(tcx, id, field_ty);
......@@ -3034,14 +3024,14 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
for m in ms { check_method(ccx, m); }
vec::pop(ccx.self_infos);
}
ast::item_class(tps, members, ctor_id, ctor_decl, ctor_body) {
ast::item_class(tps, members, ctor) {
let cid = some(it.id);
let members_info = class_types(ccx, members);
let class_ccx = @{enclosing_class_id:cid,
enclosing_class:members_info with *ccx};
// typecheck the ctor
check_fn(class_ccx, ast::proto_bare, ctor_decl, ctor_body, ctor_id,
none);
check_fn(class_ccx, ast::proto_bare, ctor.node.dec,
ctor.node.body, ctor.node.id, none);
// typecheck the members
for m in members { check_class_member(class_ccx, m.node.decl); }
}
......
......@@ -9,9 +9,6 @@
// Functions may or may not have names.
type fn_ident = option<ident>;
// FIXME: with typestate constraint, could say
// idents and types are the same length, and are
// non-empty
type path_ = {global: bool, idents: [ident], types: [@ty]};
type path = spanned<path_>;
......@@ -499,9 +496,7 @@ enum item_ {
item_class([ty_param], /* ty params for class */
[@class_item], /* methods, etc. */
/* (not including ctor) */
node_id, /* ctor id */
fn_decl, /* ctor decl */
blk /* ctor body */
class_ctor
),
item_iface([ty_param], [ty_method]),
item_impl([ty_param], option<@ty> /* iface */,
......@@ -523,6 +518,11 @@ enum class_mutability { class_mutable, class_immutable }
enum privacy { priv, pub }
type class_ctor = spanned<class_ctor_>;
type class_ctor_ = {id: node_id,
dec: fn_decl,
body: blk};
type native_item =
{ident: ident,
attrs: [attribute],
......
......@@ -269,12 +269,14 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
item_enum(vec::map(variants, fld.fold_variant),
fold_ty_params(typms, fld))
}
item_class(typms, items, id, ctor_decl, ctor_body) {
item_class(fold_ty_params(typms, fld),
item_class(typms, items, ctor) {
let ctor_body = fld.fold_block(ctor.node.body);
let ctor_decl = fold_fn_decl(ctor.node.dec, fld);
item_class(typms,
vec::map(items, fld.fold_class_item),
id,
fold_fn_decl(ctor_decl, fld),
fld.fold_block(ctor_body))
{node: {body: ctor_body,
dec: ctor_decl with ctor.node}
with ctor})
}
item_impl(tps, ifce, ty, methods) {
item_impl(tps, option::map(ifce, fld.fold_ty), fld.fold_ty(ty),
......
......@@ -1590,8 +1590,9 @@ fn parse_let(p: parser) -> @ast::decl {
ret @spanned(lo, p.last_span.hi, ast::decl_local(locals));
}
fn parse_instance_var(p:parser) -> ast::class_member {
fn parse_instance_var(p:parser) -> (ast::class_member, codemap::span) {
let is_mutbl = ast::class_immutable;
let lo = p.span.lo;
expect_word(p, "let");
if eat_word(p, "mut") || eat_word(p, "mutable") {
is_mutbl = ast::class_mutable;
......@@ -1602,7 +1603,8 @@ fn parse_instance_var(p:parser) -> ast::class_member {
let name = parse_ident(p);
expect(p, token::COLON);
let ty = parse_ty(p, false);
ret ast::instance_var(name, ty, is_mutbl, p.get_id());
ret (ast::instance_var(name, ty, is_mutbl, p.get_id()),
ast_util::mk_sp(lo, p.last_span.hi));
}
fn parse_stmt(p: parser, first_item_attrs: [ast::attribute]) -> @ast::stmt {
......@@ -1976,27 +1978,33 @@ fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item {
expect(p, token::LBRACE);
let items: [@ast::class_item] = [];
let ctor_id = p.get_id();
let the_ctor : option<(ast::fn_decl, ast::blk)> = none;
let the_ctor : option<(ast::fn_decl, ast::blk, codemap::span)> = none;
while p.token != token::RBRACE {
alt parse_class_item(p, class_path) {
ctor_decl(a_fn_decl, blk) {
the_ctor = some((a_fn_decl, blk));
ctor_decl(a_fn_decl, blk, s) {
the_ctor = some((a_fn_decl, blk, s));
}
plain_decl(a_decl) {
plain_decl(a_decl, s) {
items += [@{node: {privacy: ast::pub, decl: a_decl},
span: p.last_span}];
span: s}];
}
priv_decls(some_decls) {
items += vec::map(some_decls, {|d|
items += vec::map(some_decls, {|p|
let (d, s) = p;
@{node: {privacy: ast::priv, decl: d},
span: p.last_span}});
span: s}});
}
}
}
p.bump();
alt the_ctor {
some((ct_d, ct_b)) { ret mk_item(p, lo, p.last_span.hi, class_name,
ast::item_class(ty_params, items, ctor_id, ct_d, ct_b), attrs); }
some((ct_d, ct_b, ct_s)) { ret mk_item(p, lo, p.last_span.hi,
class_name,
ast::item_class(ty_params, items,
{node: {id: ctor_id,
dec: ct_d,
body: ct_b},
span: ct_s}), attrs); }
/*
Is it strange for the parser to check this?
*/
......@@ -2007,16 +2015,17 @@ fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item {
// lets us identify the constructor declaration at
// parse time
// we don't really want just the fn_decl...
enum class_contents { ctor_decl(ast::fn_decl, ast::blk),
enum class_contents { ctor_decl(ast::fn_decl, ast::blk, codemap::span),
// assumed to be public
plain_decl(ast::class_member),
plain_decl(ast::class_member, codemap::span),
// contents of a priv section --
// parse_class_item ensures that
// none of these are a ctor decl
priv_decls([ast::class_member])}
priv_decls([(ast::class_member, codemap::span)])}
fn parse_class_item(p:parser, class_name:@ast::path) -> class_contents {
if eat_word(p, "new") {
let lo = p.last_span.lo;
// Can ctors have attrs?
// result type is always the type of the class
let decl_ = parse_fn_decl(p, ast::impure_fn);
......@@ -2024,7 +2033,7 @@ fn parse_class_item(p:parser, class_name:@ast::path) -> class_contents {
span: decl_.output.span}
with decl_};
let body = parse_block(p);
ret ctor_decl(decl, body);
ret ctor_decl(decl, body, ast_util::mk_sp(lo, p.last_span.hi));
}
// FIXME: refactor
else if eat_word(p, "priv") {
......@@ -2033,7 +2042,7 @@ fn parse_class_item(p:parser, class_name:@ast::path) -> class_contents {
while p.token != token::RBRACE {
alt parse_item(p, []) {
some(i) {
results += [ast::class_method(i)];
results += [(ast::class_method(i), i.span)];
}
_ {
let a_var = parse_instance_var(p);
......@@ -2049,12 +2058,12 @@ fn parse_class_item(p:parser, class_name:@ast::path) -> class_contents {
// Probably need to parse attrs
alt parse_item(p, []) {
some(i) {
ret plain_decl(ast::class_method(i));
ret plain_decl(ast::class_method(i), i.span);
}
_ {
let a_var = parse_instance_var(p);
let (a_var, a_span) = parse_instance_var(p);
expect(p, token::SEMI);
ret plain_decl(a_var);
ret plain_decl(a_var, a_span);
}
}
}
......
......@@ -471,22 +471,24 @@ fn print_item(s: ps, &&item: @ast::item) {
bclose(s, item.span);
}
}
ast::item_class(tps,items,_,ctor_decl,ctor_body) {
ast::item_class(tps,items,ctor) {
head(s, "class");
word_nbsp(s, item.ident);
print_type_params(s, tps);
bopen(s);
hardbreak_if_not_bol(s);
maybe_print_comment(s, ctor.span.lo);
head(s, "new");
print_fn_args_and_ret(s, ctor_decl);
print_fn_args_and_ret(s, ctor.node.dec);
space(s.s);
print_block(s, ctor_body);
print_block(s, ctor.node.body);
for ci in items {
/*
FIXME: collect all private items and print them
in a single "priv" section
*/
hardbreak_if_not_bol(s);
maybe_print_comment(s, ci.span.lo);
alt ci.node.privacy {
ast::priv {
head(s, "priv");
......@@ -516,6 +518,7 @@ fn print_item(s: ps, &&item: @ast::item) {
_ {}
}
}
bclose(s, item.span);
}
ast::item_impl(tps, ifce, ty, methods) {
head(s, "impl");
......
......@@ -133,13 +133,13 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
visit_method_helper(m, e, v)
}
}
item_class(tps, members, _, ctor_decl, ctor_blk) {
item_class(tps, members, ctor) {
v.visit_ty_params(tps, e, v);
for m in members {
v.visit_class_item(m.span, m.node.privacy, m.node.decl, e, v);
}
visit_fn_decl(ctor_decl, e, v);
v.visit_block(ctor_blk, e, v);
visit_fn_decl(ctor.node.dec, e, v);
v.visit_block(ctor.node.body, e, v);
}
item_iface(tps, methods) {
v.visit_ty_params(tps, e, v);
......
// xfail-test
class cat {
priv {
let mutable meows : uint;
......@@ -12,6 +11,6 @@
fn main() {
let nyan : cat = cat(52u, 99);
let kitty = cat(1000u, 2);
log(debug, nyan.how_hungry);
log(debug, kitty.how_hungry);
}
\ No newline at end of file
assert(nyan.how_hungry == 99);
assert(kitty.how_hungry == 2);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册