rustc: Check self types in method lookup; allow required trait methods to have self types; write self types into metadata
This commit is contained in:
parent
567f881fdf
commit
2cfe8fb357
11 changed files with 181 additions and 22 deletions
|
|
@ -23,7 +23,7 @@ syn keyword rustKeyword use while with
|
|||
syn keyword rustKeyword mod trait class struct enum type nextgroup=rustIdentifier skipwhite
|
||||
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite
|
||||
|
||||
syn match rustIdentifier "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
|
||||
syn match rustIdentifier contains=rustIdentifierPrime "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
|
||||
syn match rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
|
||||
|
||||
" Reserved words
|
||||
|
|
@ -114,8 +114,11 @@ syn match rustFatArrowHead contained ">" conceal cchar=
|
|||
syn match rustFatArrowTail contained "=" conceal cchar=⟹
|
||||
syn match rustFatArrowFull "=>" contains=rustFatArrowHead,rustFatArrowTail
|
||||
|
||||
hi def link rustHexNumber rustNumber
|
||||
hi def link rustBinNumber rustNumber
|
||||
syn match rustIdentifierPrime /\<\@!_\(_*\>\)\@=/ conceal cchar=′
|
||||
|
||||
hi def link rustHexNumber rustNumber
|
||||
hi def link rustBinNumber rustNumber
|
||||
hi def link rustIdentifierPrime rustIdentifier
|
||||
|
||||
hi def link rustString String
|
||||
hi def link rustCharacter Character
|
||||
|
|
|
|||
|
|
@ -503,7 +503,8 @@ type ty_field = spanned<ty_field_>;
|
|||
|
||||
#[auto_serialize]
|
||||
type ty_method = {ident: ident, attrs: ~[attribute],
|
||||
decl: fn_decl, tps: ~[ty_param], span: span};
|
||||
decl: fn_decl, tps: ~[ty_param], self_ty: self_ty,
|
||||
span: span};
|
||||
|
||||
#[auto_serialize]
|
||||
// A trait method is either required (meaning it doesn't have an
|
||||
|
|
|
|||
|
|
@ -286,6 +286,7 @@ class parser {
|
|||
// methods are ignored; this could change.
|
||||
required({ident: ident, attrs: attrs,
|
||||
decl: {purity: pur with d}, tps: tps,
|
||||
self_ty: self_ty,
|
||||
span: mk_sp(lo, hi)})
|
||||
}
|
||||
token::LBRACE {
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ const tag_mod_impl_trait: uint = 0x47u;
|
|||
const tag_item_impl_method: uint = 0x48u;
|
||||
const tag_item_dtor: uint = 0x49u;
|
||||
const tag_paths_foreign_path: uint = 0x4a;
|
||||
const tag_item_trait_method_self_ty: uint = 0x4b;
|
||||
const tag_item_trait_method_self_ty_region: uint = 0x4c;
|
||||
|
||||
// used to encode crate_ctxt side tables
|
||||
enum astencode_tag { // Reserves 0x50 -- 0x6f
|
||||
|
|
|
|||
|
|
@ -565,19 +565,70 @@ fn get_enum_variants(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
|
|||
}
|
||||
|
||||
// NB: These types are duplicated in resolve.rs
|
||||
type method_info = {did: ast::def_id, n_tps: uint, ident: ast::ident};
|
||||
type method_info = {
|
||||
did: ast::def_id,
|
||||
n_tps: uint,
|
||||
ident: ast::ident,
|
||||
self_type: ast::self_ty_
|
||||
};
|
||||
|
||||
type _impl = {did: ast::def_id, ident: ast::ident, methods: ~[@method_info]};
|
||||
|
||||
fn get_self_ty(item: ebml::doc) -> ast::self_ty_ {
|
||||
fn get_mutability(ch: u8) -> ast::mutability {
|
||||
alt ch as char {
|
||||
'i' => { ast::m_imm }
|
||||
'm' => { ast::m_mutbl }
|
||||
'c' => { ast::m_const }
|
||||
_ => {
|
||||
fail fmt!{"unknown mutability character: `%c`", ch as char}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let self_type_doc = ebml::get_doc(item, tag_item_trait_method_self_ty);
|
||||
let string = ebml::doc_as_str(self_type_doc);
|
||||
|
||||
let self_ty_kind = string[0];
|
||||
alt self_ty_kind as char {
|
||||
'r' => { ret ast::sty_by_ref; }
|
||||
'v' => { ret ast::sty_value; }
|
||||
'@' => { ret ast::sty_box(get_mutability(string[1])); }
|
||||
'~' => { ret ast::sty_uniq(get_mutability(string[1])); }
|
||||
'&' => {
|
||||
let mutability = get_mutability(string[1]);
|
||||
|
||||
let region;
|
||||
let region_doc =
|
||||
ebml::get_doc(self_type_doc,
|
||||
tag_item_trait_method_self_ty_region);
|
||||
let region_string = str::from_bytes(ebml::doc_data(region_doc));
|
||||
if str::eq(region_string, ~"") {
|
||||
region = ast::re_anon;
|
||||
} else {
|
||||
region = ast::re_named(@region_string);
|
||||
}
|
||||
|
||||
ret ast::sty_region(@{ id: 0, node: region }, mutability);
|
||||
}
|
||||
_ => {
|
||||
fail fmt!{"unknown self type code: `%c`", self_ty_kind as char};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn item_impl_methods(cdata: cmd, item: ebml::doc, base_tps: uint)
|
||||
-> ~[@method_info] {
|
||||
let mut rslt = ~[];
|
||||
for ebml::tagged_docs(item, tag_item_impl_method) |doc| {
|
||||
let m_did = ebml::with_doc_data(doc, |d| parse_def_id(d));
|
||||
let mth_item = lookup_item(m_did.node, cdata.data);
|
||||
let self_ty = get_self_ty(mth_item);
|
||||
vec::push(rslt, @{did: translate_def_id(cdata, m_did),
|
||||
/* FIXME (maybe #2323) tjc: take a look at this. */
|
||||
n_tps: item_ty_param_count(mth_item) - base_tps,
|
||||
ident: item_name(mth_item)});
|
||||
ident: item_name(mth_item),
|
||||
self_type: self_ty});
|
||||
}
|
||||
rslt
|
||||
}
|
||||
|
|
@ -628,7 +679,9 @@ fn get_trait_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
|
|||
tcx.diag.handler().bug(
|
||||
~"get_trait_methods: id has non-function type");
|
||||
} };
|
||||
let self_ty = get_self_ty(mth);
|
||||
vec::push(result, {ident: name, tps: bounds, fty: fty,
|
||||
self_ty: self_ty,
|
||||
purity: alt check item_family(mth) {
|
||||
'u' { ast::unsafe_fn }
|
||||
'f' { ast::impure_fn }
|
||||
|
|
|
|||
|
|
@ -438,6 +438,58 @@ fn encode_visibility(ebml_w: ebml::writer, visibility: visibility) {
|
|||
});
|
||||
}
|
||||
|
||||
fn encode_region(ebml_w: ebml::writer, region: region) {
|
||||
alt region.node {
|
||||
re_anon => {
|
||||
ebml_w.wr_tagged_str(tag_item_trait_method_self_ty, ~"");
|
||||
}
|
||||
re_named(ident) => {
|
||||
ebml_w.wr_tagged_str(tag_item_trait_method_self_ty, *ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_self_type(ebml_w: ebml::writer, self_type: ast::self_ty_) {
|
||||
ebml_w.start_tag(tag_item_trait_method_self_ty);
|
||||
|
||||
// Encode the base self type.
|
||||
let ch;
|
||||
alt self_type {
|
||||
sty_by_ref => { ch = 'r' as u8; }
|
||||
sty_value => { ch = 'v' as u8; }
|
||||
sty_region(_, _) => { ch = '&' as u8; }
|
||||
sty_box(_) => { ch = '@' as u8; }
|
||||
sty_uniq(_) => { ch = '~' as u8; }
|
||||
}
|
||||
ebml_w.writer.write(&[ ch ]);
|
||||
|
||||
// Encode mutability.
|
||||
alt self_type {
|
||||
sty_by_ref | sty_value => { /* No-op. */ }
|
||||
sty_region(_, m_imm) | sty_box(m_imm) | sty_uniq(m_imm) => {
|
||||
ebml_w.writer.write(&[ 'i' as u8 ]);
|
||||
}
|
||||
sty_region(_, m_mutbl) | sty_box(m_mutbl) | sty_uniq(m_mutbl) => {
|
||||
ebml_w.writer.write(&[ 'm' as u8 ]);
|
||||
}
|
||||
sty_region(_, m_const) | sty_box(m_const) | sty_uniq(m_const) => {
|
||||
ebml_w.writer.write(&[ 'c' as u8 ]);
|
||||
}
|
||||
}
|
||||
|
||||
// Encode the region.
|
||||
alt self_type {
|
||||
sty_region(region, _) => {
|
||||
encode_region(ebml_w, *region);
|
||||
}
|
||||
sty_by_ref | sty_value | sty_box(*) | sty_uniq(*) => {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
/* Returns an index of items in this class */
|
||||
fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer,
|
||||
id: node_id, path: ast_map::path,
|
||||
|
|
@ -523,6 +575,7 @@ fn encode_info_for_method(ecx: @encode_ctxt, ebml_w: ebml::writer,
|
|||
encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id));
|
||||
encode_name(ebml_w, m.ident);
|
||||
encode_path(ebml_w, impl_path, ast_map::path_name(m.ident));
|
||||
encode_self_type(ebml_w, m.self_ty.node);
|
||||
if all_tps.len() > 0u || should_inline {
|
||||
ecx.encode_inlined_item(
|
||||
ecx, ebml_w, impl_path,
|
||||
|
|
@ -712,9 +765,10 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
|
|||
encode_type_param_bounds(ebml_w, ecx, m.tps);
|
||||
encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id));
|
||||
encode_def_id(ebml_w, local_def(m.id));
|
||||
encode_self_type(ebml_w, m.self_ty.node);
|
||||
ebml_w.end_tag();
|
||||
/* Write the info that's needed when viewing this class
|
||||
as an impl (just the method def_id) */
|
||||
as an impl (just the method def_id and self type) */
|
||||
ebml_w.start_tag(tag_item_impl_method);
|
||||
ebml_w.writer.write(str::bytes(def_to_str(local_def(m.id))));
|
||||
ebml_w.end_tag();
|
||||
|
|
@ -778,6 +832,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
|
|||
encode_type_param_bounds(ebml_w, ecx, ty_m.tps);
|
||||
encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty));
|
||||
encode_family(ebml_w, purity_fn_family(mty.purity));
|
||||
encode_self_type(ebml_w, mty.self_ty);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
provided(m) {
|
||||
|
|
|
|||
|
|
@ -28,13 +28,13 @@ import syntax::ast::{item_mod, item_trait, item_ty, le, local, local_crate};
|
|||
import syntax::ast::{lt, method, mul, ne, neg, node_id, pat, pat_enum};
|
||||
import syntax::ast::{pat_ident, path, prim_ty, pat_box, pat_uniq, pat_lit};
|
||||
import syntax::ast::{pat_range, pat_rec, pat_tup, pat_wild, provided};
|
||||
import syntax::ast::{required, rem, shl, stmt_decl, subtract, ty, ty_bool};
|
||||
import syntax::ast::{ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i, ty_i16};
|
||||
import syntax::ast::{ty_i32, ty_i64, ty_i8, ty_int, ty_param, ty_path};
|
||||
import syntax::ast::{ty_str, ty_u, ty_u16, ty_u32, ty_u64, ty_u8, ty_uint};
|
||||
import syntax::ast::{variant, view_item, view_item_export, view_item_import};
|
||||
import syntax::ast::{view_item_use, view_path_glob, view_path_list};
|
||||
import syntax::ast::{view_path_simple};
|
||||
import syntax::ast::{required, rem, self_ty_, shl, stmt_decl, subtract, ty};
|
||||
import syntax::ast::{ty_bool, ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i};
|
||||
import syntax::ast::{ty_i16, ty_i32, ty_i64, ty_i8, ty_int, ty_param};
|
||||
import syntax::ast::{ty_path, ty_str, ty_u, ty_u16, ty_u32, ty_u64, ty_u8};
|
||||
import syntax::ast::{ty_uint, variant, view_item, view_item_export};
|
||||
import syntax::ast::{view_item_import, view_item_use, view_path_glob};
|
||||
import syntax::ast::{view_path_list, view_path_simple};
|
||||
import syntax::ast_util::{def_id_of_def, dummy_sp, local_def, new_def_hash};
|
||||
import syntax::ast_util::{walk_pat};
|
||||
import syntax::attr::{attr_metas, contains_name};
|
||||
|
|
@ -59,7 +59,16 @@ import str_eq = str::eq;
|
|||
type DefMap = hashmap<node_id,def>;
|
||||
|
||||
// Implementation resolution
|
||||
type MethodInfo = { did: def_id, n_tps: uint, ident: ident };
|
||||
|
||||
// XXX: This kind of duplicates information kept in ty::method. Maybe it
|
||||
// should go away.
|
||||
type MethodInfo = {
|
||||
did: def_id,
|
||||
n_tps: uint,
|
||||
ident: ident,
|
||||
self_type: self_ty_
|
||||
};
|
||||
|
||||
type Impl = { did: def_id, ident: ident, methods: ~[@MethodInfo] };
|
||||
type ImplScope = @~[@Impl];
|
||||
type ImplScopes = @list<ImplScope>;
|
||||
|
|
@ -925,7 +934,8 @@ class Resolver {
|
|||
@{
|
||||
did: local_def(method.id),
|
||||
n_tps: method.tps.len(),
|
||||
ident: method.ident
|
||||
ident: method.ident,
|
||||
self_type: method.self_ty.node
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
@ -962,7 +972,8 @@ class Resolver {
|
|||
@{
|
||||
did: local_def(method.id),
|
||||
n_tps: method.tps.len(),
|
||||
ident: method.ident
|
||||
ident: method.ident,
|
||||
self_type: method.self_ty.node
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ type param_bounds = @~[param_bound];
|
|||
type method = {ident: ast::ident,
|
||||
tps: @~[param_bounds],
|
||||
fty: fn_ty,
|
||||
self_ty: ast::self_ty_,
|
||||
purity: ast::purity,
|
||||
vis: ast::visibility};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
/* Code to handle method lookups (which can be quite complex) */
|
||||
|
||||
import coherence::get_base_type_def_id;
|
||||
import middle::resolve3::Impl;
|
||||
import middle::resolve3::{Impl, MethodInfo};
|
||||
import middle::ty::{mk_box, mk_rptr, mk_uniq};
|
||||
import middle::typeck::infer::methods; // next_ty_vars
|
||||
import syntax::ast::def_id;
|
||||
import syntax::ast::{def_id, sty_box, sty_by_ref, sty_region, sty_uniq};
|
||||
import syntax::ast::{sty_value};
|
||||
import syntax::ast_map;
|
||||
import syntax::ast_map::node_id_to_str;
|
||||
import syntax::ast_util::new_def_hash;
|
||||
import syntax::ast_util::{dummy_sp, new_def_hash};
|
||||
import dvec::{dvec, extensions};
|
||||
|
||||
type candidate = {
|
||||
|
|
@ -18,6 +20,28 @@ type candidate = {
|
|||
entry: method_map_entry
|
||||
};
|
||||
|
||||
fn transform_self_type_for_method(fcx: @fn_ctxt,
|
||||
impl_ty: ty::t,
|
||||
method_info: MethodInfo)
|
||||
-> ty::t {
|
||||
alt method_info.self_type {
|
||||
sty_by_ref | sty_value => {
|
||||
impl_ty
|
||||
}
|
||||
sty_region(r, mutability) => {
|
||||
// XXX: dummy_sp is unfortunate here.
|
||||
let region = ast_region_to_region(fcx, fcx, dummy_sp(), r);
|
||||
mk_rptr(fcx.ccx.tcx, region, { ty: impl_ty, mutbl: mutability })
|
||||
}
|
||||
sty_box(mutability) => {
|
||||
mk_box(fcx.ccx.tcx, { ty: impl_ty, mutbl: mutability })
|
||||
}
|
||||
sty_uniq(mutability) => {
|
||||
mk_uniq(fcx.ccx.tcx, { ty: impl_ty, mutbl: mutability })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class lookup {
|
||||
let fcx: @fn_ctxt;
|
||||
let expr: @ast::expr;
|
||||
|
|
@ -370,6 +394,10 @@ class lookup {
|
|||
let {substs: impl_substs, ty: impl_ty} =
|
||||
impl_self_ty(self.fcx, im.did);
|
||||
|
||||
let impl_ty = transform_self_type_for_method(self.fcx,
|
||||
impl_ty,
|
||||
*m);
|
||||
|
||||
// Depending on our argument, we find potential
|
||||
// matches either by checking subtypability or
|
||||
// type assignability. Collect the matches.
|
||||
|
|
|
|||
|
|
@ -492,7 +492,8 @@ class CoherenceChecker {
|
|||
push(methods, @{
|
||||
did: local_def(ast_method.id),
|
||||
n_tps: ast_method.tps.len(),
|
||||
ident: ast_method.ident
|
||||
ident: ast_method.ident,
|
||||
self_type: ast_method.self_ty.node
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -513,7 +514,8 @@ class CoherenceChecker {
|
|||
push(methods, @{
|
||||
did: local_def(ast_method.id),
|
||||
n_tps: ast_method.tps.len(),
|
||||
ident: ast_method.ident
|
||||
ident: ast_method.ident,
|
||||
self_type: ast_method.self_ty.node
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -432,6 +432,7 @@ fn ty_of_method(ccx: @crate_ctxt,
|
|||
tps: ty_param_bounds(ccx, m.tps),
|
||||
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
|
||||
m.decl, none),
|
||||
self_ty: m.self_ty.node,
|
||||
purity: m.decl.purity,
|
||||
vis: m.vis}
|
||||
}
|
||||
|
|
@ -444,6 +445,7 @@ fn ty_of_ty_method(self: @crate_ctxt,
|
|||
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
|
||||
m.decl, none),
|
||||
// assume public, because this is only invoked on trait methods
|
||||
self_ty: m.self_ty.node,
|
||||
purity: m.decl.purity, vis: ast::public}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue