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

Allow classes to be cast to ifaces that are in the same crate

I had to xfail one existing test case (class-implements-int) because,
I think, of the same bug described in #2272.
上级 1c39fda0
......@@ -448,7 +448,7 @@ fn map<T, U>(v: [T], f: fn(T) -> U) -> [U] {
}
#[doc = "
Apply a function eo each element of a vector and return a concatenation
Apply a function to each element of a vector and return a concatenation
of each result vector
"]
fn flat_map<T, U>(v: [T], f: fn(T) -> [U]) -> [U] {
......
......@@ -636,6 +636,10 @@ enum attr_style { attr_outer, attr_inner, }
#[auto_serialize]
type attribute_ = {style: attr_style, value: meta_item};
/*
iface_refs appear in both impls and in classes that implement ifaces.
resolve maps each iface_ref's id to its defining iface.
*/
#[auto_serialize]
type iface_ref = {path: @path, id: node_id};
......@@ -661,14 +665,14 @@ enum item_ {
node_id /* dtor id */, node_id /* ctor id */,
region_param),
item_class([ty_param], /* ty params for class */
[iface_ref], /* ifaces this class implements */
[@iface_ref], /* ifaces this class implements */
[@class_member], /* methods, etc. */
/* (not including ctor) */
class_ctor,
region_param
),
item_iface([ty_param], [ty_method]),
item_impl([ty_param], option<@ty> /* iface */,
item_impl([ty_param], option<@iface_ref> /* iface */,
@ty /* self */, [@method]),
}
......
......@@ -2,20 +2,20 @@
import ast::*;
fn spanned<T: copy>(lo: uint, hi: uint, t: T) -> spanned<T> {
ret respan(mk_sp(lo, hi), t);
respan(mk_sp(lo, hi), t)
}
fn respan<T: copy>(sp: span, t: T) -> spanned<T> {
ret {node: t, span: sp};
{node: t, span: sp}
}
fn dummy_spanned<T: copy>(t: T) -> spanned<T> {
ret respan(dummy_sp(), t);
respan(dummy_sp(), t)
}
/* assuming that we're not in macro expansion */
fn mk_sp(lo: uint, hi: uint) -> span {
ret {lo: lo, hi: hi, expn_info: none};
{lo: lo, hi: hi, expn_info: none}
}
// make this a const, once the compiler supports it
......@@ -334,6 +334,16 @@ fn accept<E>(e: E, v: visit::vt<E>) {
}
}
}
/* True if d is either a def_self, or a chain of def_upvars
referring to a def_self */
fn is_self(d: ast::def) -> bool {
alt d {
def_self(_) { true }
def_upvar(_, d, _) { is_self(*d) }
_ { false }
}
}
// Local Variables:
// mode: rust
// fill-column: 78;
......
......@@ -279,9 +279,7 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
let ctor_id = fld.new_id(ctor.node.id);
item_class(
typms,
vec::map(ifaces, {|p|
{path: fld.fold_path(p.path),
id: fld.new_id(p.id)}}),
vec::map(ifaces, {|p| fold_iface_ref(p, fld) }),
vec::map(items, fld.fold_class_item),
{node: {body: ctor_body,
dec: ctor_decl,
......@@ -290,7 +288,8 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
rp)
}
item_impl(tps, ifce, ty, methods) {
item_impl(tps, option::map(ifce, fld.fold_ty), fld.fold_ty(ty),
item_impl(tps, option::map(ifce, {|p| fold_iface_ref(p, fld)}),
fld.fold_ty(ty),
vec::map(methods, fld.fold_method))
}
item_iface(tps, methods) { item_iface(tps, methods) }
......@@ -305,6 +304,10 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
};
}
fn fold_iface_ref(&&p: @iface_ref, fld: ast_fold) -> @iface_ref {
@{path: fld.fold_path(p.path), id: fld.new_id(p.id)}
}
fn noop_fold_method(&&m: @method, fld: ast_fold) -> @method {
ret @{ident: fld.fold_ident(m.ident),
attrs: m.attrs,
......
......@@ -5,6 +5,7 @@
import codemap::{span,fss_none};
import util::interner;
import ast_util::{spanned, mk_sp, ident_to_path};
import ast::{node_id};
import lexer::reader;
import prec::{op_spec, as_prec};
import attr::{parse_outer_attrs_or_ext,
......@@ -1788,9 +1789,6 @@ fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item {
// impl name<T> for [T] { ... }
fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item {
let lo = p.last_span.lo;
fn wrap_path(p: parser, pt: @ast::path) -> @ast::ty {
@{id: p.get_id(), node: ast::ty_path(pt, p.get_id()), span: pt.span}
}
let mut (ident, tps) = if !is_word(p, "of") {
if p.token == token::LT { (none, parse_ty_params(p)) }
else { (some(parse_ident(p)), parse_ty_params(p)) }
......@@ -1800,7 +1798,7 @@ fn wrap_path(p: parser, pt: @ast::path) -> @ast::ty {
if option::is_none(ident) {
ident = some(vec::last(path.idents));
}
some(wrap_path(p, path))
some(@{path: path, id: p.get_id()})
} else { none };
let ident = alt ident {
some(name) { name }
......@@ -1855,9 +1853,13 @@ fn ident_to_path_tys(p: parser, i: ast::ident,
}
}
fn parse_iface_ref_list(p:parser) -> [ast::iface_ref] {
fn parse_iface_ref(p:parser) -> @ast::iface_ref {
@{path: parse_path(p), id: p.get_id()}
}
fn parse_iface_ref_list(p:parser) -> [@ast::iface_ref] {
parse_seq_to_before_end(token::LBRACE, seq_sep(token::COMMA),
{|p| {path: parse_path(p), id: p.get_id()}}, p)
parse_iface_ref, p)
}
fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item {
......@@ -1866,7 +1868,7 @@ fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item {
let rp = parse_region_param(p);
let ty_params = parse_ty_params(p);
let class_path = ident_to_path_tys(p, class_name, ty_params);
let ifaces : [ast::iface_ref] = if eat_word(p, "implements")
let ifaces : [@ast::iface_ref] = if eat_word(p, "implements")
{ parse_iface_ref_list(p) }
else { [] };
expect(p, token::LBRACE);
......@@ -1918,7 +1920,7 @@ fn parse_single_class_item(p: parser, privcy: ast::privacy)
enum class_contents { ctor_decl(ast::fn_decl, ast::blk, codemap::span),
members([@ast::class_member]) }
fn parse_class_item(p:parser, class_name_with_tps:@ast::path)
fn parse_class_item(p:parser, class_name_with_tps: @ast::path)
-> class_contents {
if eat_word(p, "new") {
let lo = p.last_span.lo;
......
......@@ -561,14 +561,11 @@ fn print_item(s: ps, &&item: @ast::item) {
word(s.s, item.ident);
print_type_params(s, tps);
space(s.s);
alt ifce {
some(ty) {
option::iter(ifce, {|p|
word_nbsp(s, "of");
print_type(s, ty);
print_path(s, p.path, false);
space(s.s);
}
_ {}
}
});
word_nbsp(s, "for");
print_type(s, ty);
space(s.s);
......
......@@ -134,7 +134,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
}
item_impl(tps, ifce, ty, methods) {
v.visit_ty_params(tps, e, v);
alt ifce { some(ty) { v.visit_ty(ty, e, v); } none {} }
option::iter(ifce, {|p| visit_path(p.path, e, v)});
v.visit_ty(ty, e, v);
for methods.each {|m|
visit_method_helper(m, e, v)
......
......@@ -160,8 +160,9 @@ fn get_field_type(tcx: ty::ctxt, class_id: ast::def_id,
ret {bounds: @[], rp: ast::rp_none, ty: ty};
}
fn get_impl_iface(tcx: ty::ctxt, def: ast::def_id)
-> option<ty::t> {
// Given a def_id for an impl or class, return the iface it implements,
// or none if it's not for an impl or for a class that implements ifaces
fn get_impl_iface(tcx: ty::ctxt, def: ast::def_id) -> option<ty::t> {
let cstore = tcx.sess.cstore;
let cdata = cstore::get_crate_data(cstore, def.crate);
decoder::get_impl_iface(cdata, def.node, tcx)
......
......@@ -27,7 +27,6 @@
export get_impl_method;
export lookup_def;
export lookup_item_name;
export get_impl_iface;
export resolve_path;
export get_crate_attributes;
export list_crate_metadata;
......@@ -157,11 +156,9 @@ fn item_impl_iface(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
-> option<ty::t> {
let mut result = none;
ebml::tagged_docs(item, tag_impl_iface) {|ity|
let t = parse_ty_data(ity.data, cdata.cnum, ity.start, tcx, {|did|
translate_def_id(cdata, did)
});
result = some(t);
}
result = some(parse_ty_data(ity.data, cdata.cnum, ity.start, tcx,
{|did| translate_def_id(cdata, did)}));
};
result
}
......
......@@ -659,9 +659,7 @@ fn add_to_index_(item: @item, ebml_w: ebml::writer,
}
alt ifce {
some(t) {
let i_ty = alt check t.node {
ty_path(_, id) { ty::node_id_to_type(tcx, id) }
};
let i_ty = ty::node_id_to_type(tcx, t.id);
ebml_w.start_tag(tag_impl_iface);
write_type(ecx, ebml_w, i_ty);
ebml_w.end_tag();
......
......@@ -204,16 +204,16 @@ fn map_item(i: @item, cx: ctx, v: vt) {
cx.map.insert(nitem.id, node_native_item(nitem, abi, @cx.path));
}
}
item_class(_, _, items, ctor, _) {
item_class(tps, ifces, items, ctor, _) {
let (_, ms) = ast_util::split_class_items(items);
// Map iface refs to their parent classes. This is
// so we can find the self_ty
vec::iter(ifces) {|p| cx.map.insert(p.id,
node_item(i, item_path)); };
let d_id = ast_util::local_def(i.id);
let p = extend(cx, i.ident);
for items.each {|ci|
// only need to handle methods
alt ci.node {
class_method(m) { map_method(d_id, p, m, cx); }
_ {}
}
}
vec::iter(ms) {|m| map_method(d_id, p, m, cx); }
}
_ { }
}
......
......@@ -9,6 +9,7 @@
import driver::session::session;
import util::common::*;
import std::map::{int_hash, str_hash, hashmap};
import vec::each;
import syntax::codemap::span;
import syntax::visit;
import visit::vt;
......@@ -402,6 +403,11 @@ fn maybe_insert(e: @env, id: node_id, def: option<def>) {
}
}
fn resolve_iface_ref(p: @iface_ref, sc: scopes, e: @env) {
maybe_insert(e, p.id,
lookup_path_strict(*e, sc, p.path.span, p.path, ns_type));
}
fn resolve_names(e: @env, c: @ast::crate) {
e.used_imports.track = true;
let v =
......@@ -431,9 +437,10 @@ fn walk_item(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
alt i.node {
ast::item_class(_, ifaces, _, _, _) {
/* visit the iface paths... */
for ifaces.each {|p|
maybe_insert(e, p.id,
lookup_path_strict(*e, sc, p.path.span, p.path, ns_type))};
for ifaces.each {|p| resolve_iface_ref(p, sc, e)};
}
ast::item_impl(_, ifce, _, _) {
option::iter(ifce, {|p| resolve_iface_ref(p, sc, e)});
}
_ {}
}
......@@ -535,7 +542,7 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
alt i.node {
ast::item_impl(tps, ifce, sty, methods) {
visit::visit_ty_params(tps, sc, v);
alt ifce { some(ty) { v.visit_ty(ty, sc, v); } _ {} }
option::iter(ifce) {|p| visit::visit_path(p.path, sc, v)};
v.visit_ty(sty, sc, v);
for methods.each {|m|
v.visit_ty_params(m.tps, sc, v);
......@@ -1109,11 +1116,11 @@ fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) ->
}
ret some(df);
}
_ {}
}
if left_fn {
left_fn_level2 = true;
} else if ns != ns_module {
_ {}
}
if left_fn {
left_fn_level2 = true;
} else if ns != ns_module {
left_fn = scope_is_fn(hd);
alt scope_closes(hd) {
some(node_id) { closing += [node_id]; }
......@@ -1121,8 +1128,8 @@ fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) ->
}
}
sc = *tl;
}
}
}
};
}
......@@ -2103,6 +2110,8 @@ enum %s",
// Impl resolution
type method_info = {did: def_id, n_tps: uint, ident: ast::ident};
/* what are the did and ident here? */
/* ident = the name of the impl */
type _impl = {did: def_id, ident: ast::ident, methods: [@method_info]};
type iscopes = list<@[@_impl]>;
......@@ -2177,6 +2186,12 @@ fn lookup_imported_impls(e: env, id: node_id,
}
}
/*
Given an item <i>, adds one record to the mutable vec
<impls> if the item is an impl; zero or more records if the
item is a class; and none otherwise. Each record describes
one interface implemented by i.
*/
fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl],
name: option<ident>,
ck_exports: option<@indexed_mod>) {
......@@ -2196,6 +2211,20 @@ fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl],
})}];
}
}
ast::item_class(tps, ifces, items, _, _) {
let (_, mthds) = ast_util::split_class_items(items);
let n_tps = tps.len();
vec::iter(ifces) {|p|
// The def_id, in this case, identifies the combination of
// class and iface
impls += [@{did: local_def(p.id),
ident: i.ident,
methods: vec::map(mthds, {|m|
@{did: local_def(m.id),
n_tps: n_tps + m.tps.len(),
ident: m.ident}})}];
}
}
_ {}
}
}
......
......@@ -164,7 +164,7 @@ fn enter_opt(tcx: ty::ctxt, m: match, opt: opt, col: uint,
alt p.node {
ast::pat_enum(_, subpats) {
if opt_eq(tcx, variant_opt(tcx, p.id), opt) {
some(option::get_or_default(subpats,
some(option::get_default(subpats,
vec::from_elem(variant_size, dummy))) }
else { none }
}
......
......@@ -1963,7 +1963,7 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
let mono_ty = ty::subst_tps(ccx.tcx, substs, item_ty);
let llfty = type_of_fn_from_ty(ccx, mono_ty);
let depth = option::get_or_default(ccx.monomorphizing.find(fn_id), 0u);
let depth = option::get_default(ccx.monomorphizing.find(fn_id), 0u);
// Random cut-off -- code that needs to instantiate the same function
// recursively more than ten times can probably safely be assumed to be
// causing an infinite expansion.
......
......@@ -5,13 +5,13 @@
import build::*;
import driver::session::session;
import syntax::ast;
import syntax::ast_util::local_def;
import syntax::ast_util::{local_def, split_class_items};
import metadata::csearch;
import back::{link, abi};
import lib::llvm::llvm;
import lib::llvm::{ValueRef, TypeRef};
import lib::llvm::llvm::LLVMGetParam;
import ast_map::{path, path_mod, path_name};
import ast_map::{path, path_mod, path_name, node_id_to_str};
import std::map::hashmap;
fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
......@@ -82,12 +82,21 @@ fn trans_vtable_callee(bcx: block, env: callee_env, vtable: ValueRef,
{bcx: bcx, val: mptr, kind: owned, env: env}
}
fn method_from_methods(ms: [@ast::method], name: ast::ident) -> ast::def_id {
local_def(option::get(vec::find(ms, {|m| m.ident == name})).id)
}
fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
name: ast::ident) -> ast::def_id {
if impl_id.crate == ast::local_crate {
alt check ccx.tcx.items.get(impl_id.node) {
ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) {
local_def(option::get(vec::find(ms, {|m| m.ident == name})).id)
method_from_methods(ms, name)
}
ast_map::node_item(@{node:
ast::item_class(_, _, items, _, _), _}, _) {
let (_,ms) = split_class_items(items);
method_from_methods(ms, name)
}
}
} else {
......@@ -245,9 +254,8 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t],
let tcx = ccx.tcx;
let ifce_id = ty::ty_to_def_id(option::get(ty::impl_iface(tcx, impl_id)));
let has_tps = (*ty::lookup_item_type(ccx.tcx, impl_id).bounds).len() > 0u;
make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id), {|im|
let fty = ty::subst_tps(tcx, substs,
ty::mk_fn(tcx, im.fty));
make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id)) {|im|
let fty = ty::subst_tps(tcx, substs, ty::mk_fn(tcx, im.fty));
if (*im.tps).len() > 0u || ty::type_has_vars(fty) {
C_null(T_ptr(T_nil()))
} else {
......@@ -260,7 +268,7 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t],
trans_external_path(ccx, m_id, fty)
}
}
}))
})
}
fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest)
......
......@@ -1326,6 +1326,17 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
}
lowest
}
// FIXME: (tjc) there are rules about when classes are copyable/
// sendable, but I'm just treating them like records (#1726)
ty_class(did, substs) {
// also factor out this code, copied from the records case
let mut lowest = kind_sendable;
let flds = class_items_as_fields(cx, did, substs);
for flds.each {|f|
lowest = lower_kind(lowest, type_kind(cx, f.mt.ty));
}
lowest
}
// Tuples lower to the lowest of their members.
ty_tup(tys) {
let mut lowest = kind_sendable;
......@@ -1356,7 +1367,6 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
}
ty_constr(t, _) { type_kind(cx, t) }
ty_class(_, _) { fail "FIXME"; }
ty_var(_) { fail "FIXME"; }
ty_self(_) { kind_noncopyable }
};
......@@ -2248,12 +2258,24 @@ fn iface_methods(cx: ctxt, id: ast::def_id) -> @[method] {
fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
if id.crate == ast::local_crate {
alt cx.items.get(id.node) {
ast_map::node_item(@{node: ast::item_impl(
_, some(@{node: ast::ty_path(_, id), _}), _, _), _}, _) {
some(node_id_to_type(cx, id))
}
_ { none }
alt cx.items.find(id.node) {
some(ast_map::node_item(@{node: ast::item_impl(
_, some(@{id: id, _}), _, _), _}, _)) {
some(node_id_to_type(cx, id))
}
some(ast_map::node_item(@{node: ast::item_class(_, _, _, _, _),
_},_)) {
alt cx.def_map.find(id.node) {
some(def_ty(iface_id)) {
some(node_id_to_type(cx, id.node))
}
_ {
cx.sess.bug("impl_iface: iface ref isn't in iface map \
and isn't bound to a def_ty");
}
}
}
_ { none }
}
} else {
csearch::get_impl_iface(cx, id)
......
......@@ -20,6 +20,7 @@
import std::map::{hashmap, int_hash};
import std::serialization::{serialize_uint, deserialize_uint};
import std::ufind;
import vec::each;
import syntax::print::pprust::*;
import util::common::indent;
import std::list;
......@@ -43,10 +44,27 @@ enum method_origin {
// Resolutions for bounds of all parameters, left to right, for a given path.
type vtable_res = @[vtable_origin];
enum vtable_origin {
/*
Statically known vtable. def_id gives the class or impl item
from whence comes the vtable, and tys are the type substs.
vtable_res is the vtable itself
*/
vtable_static(ast::def_id, [ty::t], vtable_res),
// Param number, bound number
/*
Dynamic vtable, comes from a parameter that has a bound on it:
fn foo<T: quux, baz, bar>(a: T) -- a's vtable would have a
vtable_param origin
The first uint is the param number (identifying T in the example),
and the second is the bound number (identifying baz)
*/
vtable_param(uint, uint),
/*
Dynamic vtable, comes from something known to have an interface
type. def_id refers to the iface item, tys are the substs
*/
vtable_iface(ast::def_id, [ty::t]),
}
......@@ -119,12 +137,12 @@ enum vtable_origin {
// Determines whether the given node ID is a use of the def of
// the self ID for the current method, if there is one
// self IDs in an outer scope count. so that means that you can
// call your own private methods from nested functions inside
// class methods
fn self_ref(fcx: @fn_ctxt, id: ast::node_id) -> bool {
// check what def `id` was resolved to (if anything)
alt fcx.ccx.tcx.def_map.find(id) {
some(ast::def_self(_)) { true }
_ { false }
}
option::map_default(fcx.ccx.tcx.def_map.find(id), false,
ast_util::is_self)
}
fn lookup_local(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> ty_vid {
......@@ -465,19 +483,7 @@ fn ast_region_to_region<AC: ast_conv, RS: region_scope>(
get_region_reporting_err(self.tcx(), span, res)
}
// Parses the programmer's textual representation of a type into our
// internal notion of a type. `getter` is a function that returns the type
// corresponding to a definition ID:
fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, &&ast_ty: @ast::ty) -> ty::t {
fn ast_mt_to_mt<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, mt: ast::mt) -> ty::mt {
ret {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl};
}
fn instantiate<AC: ast_conv, RS: region_scope copy>(
fn instantiate<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, sp: span, id: ast::def_id,
path_id: ast::node_id, args: [@ast::ty]) -> ty::t {
......@@ -511,6 +517,40 @@ fn instantiate<AC: ast_conv, RS: region_scope copy>(
let ty = ty::subst(tcx, substs, ty);
write_substs_to_tcx(tcx, path_id, substs.tps);
ret ty;
}
/*
Instantiates the path for the given iface reference, assuming that
it's bound to a valid iface type. Returns the def_id for the defining
iface
*/
fn instantiate_iface_ref(ccx: @crate_ctxt, t: @ast::iface_ref)
-> ast::def_id {
alt lookup_def_tcx(ccx.tcx, t.path.span, t.id) {
ast::def_ty(t_id) {
// tjc: will probably need to refer to
// impl or class ty params too
instantiate(ccx, empty_rscope, t.path.span, t_id, t.id,
t.path.types);
t_id
}
_ {
ccx.tcx.sess.span_fatal(t.path.span,
"can only implement interface types");
}
}
}
// Parses the programmer's textual representation of a type into our
// internal notion of a type. `getter` is a function that returns the type
// corresponding to a definition ID:
fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, &&ast_ty: @ast::ty) -> ty::t {
fn ast_mt_to_mt<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, mt: ast::mt) -> ty::mt {
ret {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl};
}
fn mk_bounded<AC: ast_conv, RS: region_scope copy>(
......@@ -1169,6 +1209,7 @@ fn mk_substs(ccx: @crate_ctxt, atps: [ast::ty_param], rp: ast::region_param)
fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
impl_tps: uint, if_m: ty::method, substs: [ty::t],
self_ty: ty::t) -> ty::t {
if impl_m.tps != if_m.tps {
tcx.sess.span_err(sp, "method `" + if_m.ident +
"` has an incompatible set of type parameters");
......@@ -1371,39 +1412,37 @@ fn check_methods_against_iface(ccx: @crate_ctxt,
tps: [ast::ty_param],
rp: ast::region_param,
selfty: ty::t,
t: @ast::ty,
ms: [@ast::method]) {
t: @ast::iface_ref,
ms: [@ast::method]) -> ast::def_id {
let tcx = ccx.tcx;
let i_bounds = ty_param_bounds(ccx, tps);
let my_methods = convert_methods(ccx, ms, rp, i_bounds, selfty);
let iface_ty = ccx.to_ty(empty_rscope, t);
alt ty::get(iface_ty).struct {
ty::ty_iface(did, tys) {
// Store the iface type in the type node
alt check t.node {
ast::ty_path(_, t_id) {
write_ty_to_tcx(tcx, t_id, iface_ty);
}
}
if did.crate == ast::local_crate {
ensure_iface_methods(ccx, did.node);
}
for vec::each(*ty::iface_methods(tcx, did)) {|if_m|
alt vec::find(my_methods,
{|m| if_m.ident == m.mty.ident}) {
some({mty: m, id, span}) {
if m.purity != if_m.purity {
ccx.tcx.sess.span_err(
span, #fmt["method `%s`'s purity \
let did = instantiate_iface_ref(ccx, t);
// not sure whether it's correct to use empty_rscope
// -- tjc
let tys = vec::map(t.path.types,
{|t| ccx.to_ty(empty_rscope,t)});
// Store the iface type in the type node
write_ty_to_tcx(tcx, t.id, ty::mk_iface(ccx.tcx, did, tys));
if did.crate == ast::local_crate {
ensure_iface_methods(ccx, did.node);
}
for vec::each(*ty::iface_methods(tcx, did)) {|if_m|
alt vec::find(my_methods,
{|m| if_m.ident == m.mty.ident}) {
some({mty: m, id, span}) {
if m.purity != if_m.purity {
ccx.tcx.sess.span_err(
span, #fmt["method `%s`'s purity \
not match the iface method's \
purity", m.ident]);
}
let mt = compare_impl_method(
}
let mt = compare_impl_method(
ccx.tcx, span, m, vec::len(tps),
if_m, tys, selfty);
let old = tcx.tcache.get(local_def(id));
if old.ty != mt {
let old = tcx.tcache.get(local_def(id));
if old.ty != mt {
tcx.tcache.insert(
local_def(id),
{bounds: old.bounds,
......@@ -1412,27 +1451,24 @@ fn check_methods_against_iface(ccx: @crate_ctxt,
write_ty_to_tcx(tcx, id, mt);
}
}
none {
tcx.sess.span_err(t.span, "missing method `" +
none {
tcx.sess.span_err(t.path.span, "missing method `" +
if_m.ident + "`");
}
} // alt
} // |if_m|
} // for
_ {
tcx.sess.span_fatal(t.span, "can only implement \
interface types");
}
}
}
}
} // alt
} // |if_m|
did
} // fn
fn convert_class_item(ccx: @crate_ctxt,
rp: ast::region_param,
v: ast_util::ivar) {
/* we want to do something here, b/c within the
scope of the class, it's ok to refer to fields &
methods unqualified */
/* they have these types *within the scope* of the
class. outside the class, it's done with expr_field */
let tt = ccx.to_ty(type_rscope(rp), v.ty);
#debug("convert_class_item: %s %?", v.ident, v.id);
write_ty_to_tcx(ccx.tcx, v.id, tt);
}
......@@ -1485,7 +1521,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
ty: selfty});
alt ifce {
some(t) {
check_methods_against_iface(
check_methods_against_iface(
ccx, tps, ast::rp_none, // NDM iface/impl regions
selfty, t, ms);
}
......@@ -1569,29 +1605,16 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
that it claims to implement.
*/
for ifaces.each { |ifce|
alt lookup_def_tcx(tcx, it.span, ifce.id) {
ast::def_ty(t_id) {
let t = ty::lookup_item_type(tcx, t_id).ty;
alt ty::get(t).struct {
ty::ty_iface(_,_) {
write_ty_to_tcx(tcx, ifce.id, t);
check_methods_against_iface(
ccx, tps, rp, selfty,
@{id: ifce.id,
node: ast::ty_path(ifce.path, ifce.id),
span: ifce.path.span},
methods);
}
_ {
tcx.sess.span_fatal(
ifce.path.span,
"can only implement interface types");
}
}
}
_ { tcx.sess.span_err(ifce.path.span, "not an interface \
type"); }
}
let t_id = check_methods_against_iface(ccx, tps, rp, selfty,
ifce, methods);
// FIXME: This assumes classes only implement
// non-parameterized ifaces. add a test case for
// a class implementing a parameterized iface.
// -- tjc (#1726)
let t = ty::mk_iface(tcx, t_id, []);
write_ty_to_tcx(tcx, ifce.id, t);
// FIXME: likewise, assuming no bounds -- tjc
tcx.tcache.insert(local_def(ifce.id), no_params(t));
}
}
_ {
......@@ -1601,7 +1624,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
let tpt = ty_of_item(ccx, it);
write_ty_to_tcx(tcx, it.id, tpt.ty);
}
}
}
}
fn convert_native(ccx: @crate_ctxt, i: @ast::native_item) {
// As above, this call populates the type table with the converted
......@@ -1696,8 +1719,7 @@ fn require_same_types(
alt infer::compare_tys(tcx, t1, t2) {
result::ok(()) { true }
result::err(terr) {
tcx.sess.span_err(
span, msg() + ": " +
tcx.sess.span_err(span, msg() + ": " +
ty::type_err_to_str(tcx, terr));
false
}
......@@ -2368,12 +2390,28 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
let tcx = fcx.ccx.tcx;
let {n_tps, raw_ty} = if did.crate == ast::local_crate {
alt check tcx.items.get(did.node) {
ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
_}, _) {
{n_tps: vec::len(ts),
alt check tcx.items.find(did.node) {
some(ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
_}, _)) {
{n_tps: ts.len(),
raw_ty: fcx.to_ty(st)}
}
// Node doesn't map to an impl. It might map to a class.
some(ast_map::node_item(@{node: ast::item_class(ts,
_,_,_,rp), id: class_id, _},_)) {
/* If the impl is a class, the self ty is just the class ty
(doing a no-op subst for the ty params; in the next step,
we substitute in fresh vars for them)
*/
{n_tps: ts.len(),
raw_ty: ty::mk_class(tcx, local_def(class_id),
{self_r: alt rp {
ast::rp_self { some(fcx.next_region_var()) }
ast::rp_none { none }},
tps: ty::ty_params_to_tys(tcx, ts)})}
}
_ { tcx.sess.bug("impl_self_ty: unbound item or item that \
doesn't have a self_ty"); }
}
} else {
let ity = ty::lookup_item_type(tcx, did);
......@@ -4300,6 +4338,8 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
check_bare_fn(class_ccx, ctor.node.dec,
ctor.node.body, ctor.node.id,
some(class_t));
// Write the ctor's self's type
write_ty_to_tcx(tcx, ctor.node.self_id, class_t);
// typecheck the members
for members.each {|m| check_class_member(class_ccx, class_t, m); }
......@@ -4403,6 +4443,10 @@ fn lookup_vtables(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
@result
}
/*
Look up the vtable to use when treating an item of type <t>
as if it has type <iface_ty>
*/
fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
ty: ty::t, iface_ty: ty::t, allow_unsafe: bool)
-> vtable_origin {
......@@ -4449,14 +4493,17 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
for list::each(isc) {|impls|
let mut found = none;
for vec::each(*impls) {|im|
/* What iface does this item implement? */
let match = alt ty::impl_iface(tcx, im.did) {
some(ity) {
alt check ty::get(ity).struct {
/* Does it match the one we're searching for? */
ty::ty_iface(id, _) { id == iface_id }
}
}
_ { false }
};
/* Found a matching iface */
if match {
let {substs: substs, ty: self_ty} =
impl_self_ty(fcx, im.did);
......@@ -4566,10 +4613,21 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
let target_ty = fcx.expr_ty(ex);
alt ty::get(target_ty).struct {
ty::ty_iface(_, _) {
/* Casting to an interface type.
Look up all impls for the cast expr...
*/
let impls = cx.impl_map.get(ex.id);
/*
Look up vtables for the type we're casting to,
passing in the source and target type
*/
let vtable = lookup_vtable(fcx, impls, ex.span,
fcx.expr_ty(src), target_ty,
true);
/*
Map this expression to that vtable (that is: "ex has
vtable <vtable>")
*/
cx.vtable_map.insert(ex.id, @[vtable]);
}
_ {}
......
......@@ -249,8 +249,8 @@ fn fold_impl(
ast_map::node_item(@{
node: ast::item_impl(_, iface_ty, self_ty, _), _
}, _) {
let iface_ty = option::map(iface_ty) {|iface_ty|
pprust::ty_to_str(iface_ty)
let iface_ty = option::map(iface_ty) {|p|
pprust::path_to_str(p.path)
};
(iface_ty, some(pprust::ty_to_str(self_ty)))
}
......
// error-pattern: attempted access of field eat on type noisy
iface noisy {
fn speak();
}
class cat implements noisy {
priv {
let mut meows : uint;
fn meow() {
#error("Meow");
self.meows += 1u;
if self.meows % 5u == 0u {
self.how_hungry += 1;
}
}
}
let mut how_hungry : int;
let name : str;
new(in_x : uint, in_y : int, in_name: str)
{ self.meows = in_x; self.how_hungry = in_y; self.name = in_name; }
fn speak() { self.meow(); }
fn eat() -> bool {
if self.how_hungry > 0 {
#error("OM NOM NOM");
self.how_hungry -= 2;
ret true;
}
else {
#error("Not hungry!");
ret false;
}
}
}
fn main() {
let nyan : noisy = cat(0u, 2, "nyan") as noisy;
nyan.eat();
}
\ No newline at end of file
// error-pattern:not an interface type
class cat implements int {
// xfail-test
/*
tjc: currently this results in a memory leak after a call to
span_fatal in typeck. I think it's the same issue as #2272, because
if I make type_needs_unwind_cleanup always return true, the test passes.
FIXME: Un-xfail this when #2272 is fixed.
*/
class cat implements int { //! ERROR can only implement interface types
let meows: uint;
new(in_x : uint) { self.meows = in_x; }
}
......
iface noisy {
fn speak() -> int;
}
class dog implements noisy {
priv {
let barks : @mut uint;
fn bark() -> int {
#debug("Woof %u %d", *self.barks, *self.volume);
*self.barks += 1u;
if *self.barks % 3u == 0u {
*self.volume += 1;
}
if *self.barks % 10u == 0u {
*self.volume -= 2;
}
#debug("Grrr %u %d", *self.barks, *self.volume);
*self.volume
}
}
let volume : @mut int;
new() { self.volume = @mut 0; self.barks = @mut 0u; }
fn speak() -> int { self.bark() }
}
class cat implements noisy {
priv {
let meows : @mut uint;
fn meow() -> uint {
#debug("Meow");
*self.meows += 1u;
if *self.meows % 5u == 0u {
*self.how_hungry += 1;
}
*self.meows
}
}
let how_hungry : @mut int;
let name : str;
new(in_x : uint, in_y : int, in_name: str)
{ self.meows = @mut in_x; self.how_hungry = @mut in_y;
self.name = in_name; }
fn speak() -> int { self.meow() as int }
fn meow_count() -> uint { *self.meows }
}
fn annoy_neighbors<T: noisy>(critter: T) {
uint::range(0u, 10u) {|i| critter.speak(); }
}
fn main() {
let nyan : cat = cat(0u, 2, "nyan");
let whitefang : dog = dog();
annoy_neighbors(nyan as noisy);
annoy_neighbors(whitefang as noisy);
assert(nyan.meow_count() == 10u);
assert(*whitefang.volume == 1);
}
\ No newline at end of file
iface noisy {
fn speak();
}
class cat implements noisy {
priv {
let mut meows : uint;
fn meow() {
#error("Meow");
self.meows += 1u;
if self.meows % 5u == 0u {
self.how_hungry += 1;
}
}
}
let mut how_hungry : int;
let name : str;
new(in_x : uint, in_y : int, in_name: str)
{ self.meows = in_x; self.how_hungry = in_y; self.name = in_name; }
fn speak() { self.meow(); }
fn eat() -> bool {
if self.how_hungry > 0 {
#error("OM NOM NOM");
self.how_hungry -= 2;
ret true;
}
else {
#error("Not hungry!");
ret false;
}
}
}
fn main() {
let nyan : noisy = cat(0u, 2, "nyan") as noisy;
nyan.speak();
}
\ No newline at end of file
use std;
import std::map::*;
import vec::*;
enum furniture { chair, couch, bed }
enum body_part { finger, toe, nose, ear }
iface noisy {
fn speak() -> int;
}
iface scratchy {
fn scratch() -> option<furniture>;
}
iface bitey {
fn bite() -> body_part;
}
fn vec_includes<T>(xs: [T], x: T) -> bool {
for each(xs) {|y| if y == x { ret true; }}
ret false;
}
// vtables other than the 1st one don't seem to work
class cat implements noisy, scratchy, bitey {
priv {
let meows : @mut uint;
let scratched : @mut [furniture];
let bite_counts : hashmap<body_part, uint>;
fn meow() -> uint {
#debug("Meow: %u", *self.meows);
*self.meows += 1u;
if *self.meows % 5u == 0u {
*self.how_hungry += 1;
}
*self.meows
}
}
let how_hungry : @mut int;
let name : str;
new(in_x : uint, in_y : int, in_name: str)
{ self.meows = @mut in_x; self.how_hungry = @mut in_y;
self.name = in_name; self.scratched = @mut [];
let hsher: hashfn<body_part> =
fn@(p: body_part) -> uint { int::hash(p as int) };
let eqer : eqfn<body_part> =
fn@(p: body_part, q: body_part) -> bool { p == q };
let t : hashmap<body_part, uint> =
hashmap::<body_part, uint>(hsher, eqer);
self.bite_counts = t;
iter([finger, toe, nose, ear]) {|p|
self.bite_counts.insert(p, 0u);
};
}
fn speak() -> int { self.meow() as int }
fn meow_count() -> uint { *self.meows }
fn scratch() -> option<furniture> {
let all = [chair, couch, bed];
log(error, *(self.scratched));
let mut rslt = none;
for each(all) {|thing| if !vec_includes(*(self.scratched), thing) {
*self.scratched += [thing];
ret some(thing); }}
rslt
}
fn bite() -> body_part {
#error("In bite()");
let all = [toe, nose, ear];
let mut min = finger;
iter(all) {|next|
#debug("min = %?", min);
if self.bite_counts.get(next) < self.bite_counts.get(min) {
min = next;
}};
self.bite_counts.insert(min, self.bite_counts.get(min) + 1u);
#debug("Bit %?", min);
min
}
}
fn annoy_neighbors<T: noisy>(critter: T) {
uint::range(0u, 10u) {|i|
let what = critter.speak();
#debug("%u %d", i, what);
}
}
fn bite_everything<T: bitey>(critter: T) -> bool {
let mut left : [body_part] = [finger, toe, nose, ear];
while vec::len(left) > 0u {
let part = critter.bite();
#debug("%? %?", left, part);
if vec_includes(left, part) {
left = vec::filter(left, {|p| p != part});
}
else {
ret false;
}
}
true
}
fn scratched_something<T: scratchy>(critter: T) -> bool {
option::is_some(critter.scratch())
}
fn main() {
let nyan : cat = cat(0u, 2, "nyan");
annoy_neighbors(nyan as noisy);
assert(nyan.meow_count() == 10u);
assert(bite_everything(nyan as bitey));
assert(scratched_something(nyan as scratchy));
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册