diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index fdb82a7303bea..95d963a36e3aa 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -1394,7 +1394,7 @@ pub mod funcs { use libc::types::common::posix88::{DIR, dirent_t}; use libc::types::os::arch::c95::{c_char, c_int, c_long}; - // NOTE: On OS X opendir and readdir have two versions, + // NB: On OS X opendir and readdir have two versions, // one for 32-bit kernelspace and one for 64. // We should be linking to the 64-bit ones, called // opendir$INODE64, etc. but for some reason rustc diff --git a/src/libcore/option.rs b/src/libcore/option.rs index cd34d7ab0c0bb..de1482e2c3918 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -46,7 +46,8 @@ use ops::Add; use kinds::Copy; use util; use num::Zero; -use iter::{BaseIter, MutableIter}; +use iter::{BaseIter, MutableIter, ExtendedIter}; +use iter; #[cfg(test)] use ptr; #[cfg(test)] use str; @@ -118,6 +119,31 @@ impl MutableIter for Option { } } +impl ExtendedIter for Option { + pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) { + iter::eachi(self, blk) + } + pub fn all(&self, blk: &fn(&A) -> bool) -> bool { + iter::all(self, blk) + } + pub fn any(&self, blk: &fn(&A) -> bool) -> bool { + iter::any(self, blk) + } + pub fn foldl(&self, b0: B, blk: &fn(&B, &A) -> B) -> B { + iter::foldl(self, b0, blk) + } + pub fn position(&self, f: &fn(&A) -> bool) -> Option { + iter::position(self, f) + } + fn map_to_vec(&self, op: &fn(&A) -> B) -> ~[B] { + iter::map_to_vec(self, op) + } + fn flat_map_to_vec>(&self, op: &fn(&A) -> IB) + -> ~[B] { + iter::flat_map_to_vec(self, op) + } +} + pub impl Option { /// Returns true if the option equals `none` fn is_none(&const self) -> bool { diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs index 3e11febc5bfaa..a449c4e73cf7e 100644 --- a/src/libcore/reflect.rs +++ b/src/libcore/reflect.rs @@ -443,9 +443,9 @@ impl TyVisitor for MovePtrAdaptor { } fn visit_trait(&self) -> bool { - self.align_to::(); + self.align_to::<@TyVisitor>(); if ! self.inner.visit_trait() { return false; } - self.bump_past::(); + self.bump_past::<@TyVisitor>(); true } diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 8116ea952e425..98564beeba901 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -298,7 +298,7 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program { @ProgRes(repr) as @Program } -fn read_all(rd: io::Reader) -> ~str { +fn read_all(rd: @io::Reader) -> ~str { let buf = io::with_bytes_writer(|wr| { let mut bytes = [0, ..4096]; while !rd.eof() { diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 3b1401ae1d2c8..cd1af369570ef 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -308,7 +308,7 @@ pub fn compile_rest(sess: Session, cfg: ast::crate_cfg, }; - // NOTE: Android hack + // NB: Android hack if sess.targ_cfg.arch == abi::Arm && (sess.opts.output_type == link::output_type_object || sess.opts.output_type == link::output_type_exe) { diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 920631a55b4ec..71a1f1b3f9b20 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -74,7 +74,9 @@ pub static tag_crate_dep_vers: uint = 0x2cu; pub static tag_mod_impl: uint = 0x30u; pub static tag_item_trait_method: uint = 0x31u; -pub static tag_impl_trait: uint = 0x32u; + +pub static tag_item_trait_ref: uint = 0x32u; +pub static tag_item_super_trait_ref: uint = 0x33u; // discriminator value for variants pub static tag_disr_val: uint = 0x34u; @@ -102,6 +104,7 @@ pub static tag_item_dtor: uint = 0x49u; pub static tag_item_trait_method_self_ty: uint = 0x4b; pub static tag_item_trait_method_self_ty_region: uint = 0x4c; + // Reexports are found within module tags. Each reexport contains def_ids // and names. pub static tag_items_data_item_reexport: uint = 0x4d; @@ -159,6 +162,10 @@ pub static tag_items_data_item_visibility: uint = 0x78; pub static tag_link_args: uint = 0x79; pub static tag_link_args_arg: uint = 0x7a; +pub static tag_item_method_tps: uint = 0x7b; +pub static tag_item_method_fty: uint = 0x7c; +pub static tag_item_method_transformed_self_ty: uint = 0x7d; + pub struct LinkMeta { name: @str, vers: @str, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 16b896f11d6a4..74e891a01942f 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -111,12 +111,24 @@ pub fn get_impls_for_mod(cstore: @mut cstore::CStore, def: ast::def_id, } } -pub fn get_trait_methods(tcx: ty::ctxt, - def: ast::def_id) - -> @~[ty::method] { - let cstore = tcx.cstore; +pub fn get_method(tcx: ty::ctxt, + def: ast::def_id) -> ty::method +{ + let cdata = cstore::get_crate_data(tcx.cstore, def.crate); + decoder::get_method(tcx.cstore.intr, cdata, def.node, tcx) +} + +pub fn get_method_name_and_self_ty(cstore: @mut cstore::CStore, + def: ast::def_id) -> (ast::ident, ast::self_ty_) +{ + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_method_name_and_self_ty(cstore.intr, cdata, def.node) +} + +pub fn get_trait_method_def_ids(cstore: @mut cstore::CStore, + def: ast::def_id) -> ~[ast::def_id] { let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::get_trait_methods(cstore.intr, cdata, def.node, tcx) + decoder::get_trait_method_def_ids(cdata, def.node) } pub fn get_provided_trait_methods(tcx: ty::ctxt, @@ -127,19 +139,12 @@ pub fn get_provided_trait_methods(tcx: ty::ctxt, decoder::get_provided_trait_methods(cstore.intr, cdata, def.node, tcx) } -pub fn get_supertraits(tcx: ty::ctxt, def: ast::def_id) -> ~[ty::t] { +pub fn get_supertraits(tcx: ty::ctxt, def: ast::def_id) -> ~[@ty::TraitRef] { let cstore = tcx.cstore; let cdata = cstore::get_crate_data(cstore, def.crate); decoder::get_supertraits(cdata, def.node, tcx) } -pub fn get_method_names_if_trait(cstore: @mut cstore::CStore, - def: ast::def_id) - -> Option<~[(ast::ident, ast::self_ty_)]> { - let cdata = cstore::get_crate_data(cstore, def.crate); - return decoder::get_method_names_if_trait(cstore.intr, cdata, def.node); -} - pub fn get_type_name_if_impl(cstore: @mut cstore::CStore, def: ast::def_id) -> Option { let cdata = cstore::get_crate_data(cstore, def.crate); @@ -175,6 +180,12 @@ pub fn get_type(tcx: ty::ctxt, decoder::get_type(cdata, def.node, tcx) } +pub fn get_trait_def(tcx: ty::ctxt, def: ast::def_id) -> ty::TraitDef { + let cstore = tcx.cstore; + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_trait_def(cdata, def.node, tcx) +} + pub fn get_region_param(cstore: @mut metadata::cstore::CStore, def: ast::def_id) -> Option { let cdata = cstore::get_crate_data(cstore, def.crate); @@ -199,8 +210,8 @@ pub fn get_field_type(tcx: ty::ctxt, class_id: ast::def_id, debug!("got field data %?", the_field); let ty = decoder::item_type(def, the_field, tcx, cdata); ty::ty_param_bounds_and_ty { - bounds: @~[], - region_param: None, + generics: ty::Generics {bounds: @~[], + region_param: None}, ty: ty } } @@ -208,7 +219,8 @@ pub fn get_field_type(tcx: ty::ctxt, class_id: ast::def_id, // Given a def_id for an impl or class, return the traits it implements, // or the empty vector if it's not for an impl or for a class that implements // traits -pub fn get_impl_traits(tcx: ty::ctxt, def: ast::def_id) -> ~[ty::t] { +pub fn get_impl_traits(tcx: ty::ctxt, + def: ast::def_id) -> ~[@ty::TraitRef] { let cstore = tcx.cstore; let cdata = cstore::get_crate_data(cstore, def.crate); decoder::get_impl_traits(cdata, def.node, tcx) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index dcea22b09d6d6..d9ef30ff297d0 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -19,7 +19,8 @@ use metadata::csearch::{ProvidedTraitMethodInfo, StaticMethodInfo}; use metadata::csearch; use metadata::cstore; use metadata::decoder; -use metadata::tydecode::{parse_ty_data, parse_def_id, parse_bounds_data}; +use metadata::tydecode::{parse_ty_data, parse_def_id, parse_bounds_data, + parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::{ty, resolve}; use core::hash::HashUtil; @@ -229,6 +230,22 @@ fn doc_type(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::t { |_, did| translate_def_id(cdata, did)) } +fn doc_method_fty(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::BareFnTy { + let tp = reader::get_doc(doc, tag_item_method_fty); + parse_bare_fn_ty_data(tp.data, cdata.cnum, tp.start, tcx, + |_, did| translate_def_id(cdata, did)) +} + +fn doc_transformed_self_ty(doc: ebml::Doc, + tcx: ty::ctxt, + cdata: cmd) -> Option +{ + do reader::maybe_get_doc(doc, tag_item_method_transformed_self_ty).map |tp| { + parse_ty_data(tp.data, cdata.cnum, tp.start, tcx, + |_, did| translate_def_id(cdata, did)) + } +} + pub fn item_type(item_id: ast::def_id, item: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::t { let t = doc_type(item, tcx, cdata); @@ -239,18 +256,21 @@ pub fn item_type(item_id: ast::def_id, item: ebml::Doc, } } -fn item_impl_traits(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ~[ty::t] { - let mut results = ~[]; - for reader::tagged_docs(item, tag_impl_trait) |ity| { - results.push(doc_type(ity, tcx, cdata)); - }; - results +fn doc_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::TraitRef { + parse_trait_ref_data(doc.data, cdata.cnum, doc.start, tcx, + |_, did| translate_def_id(cdata, did)) +} + +fn item_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::TraitRef { + let tp = reader::get_doc(doc, tag_item_trait_ref); + doc_trait_ref(tp, tcx, cdata) } -fn item_ty_param_bounds(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd) +fn item_ty_param_bounds(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd, + tag: uint) -> @~[ty::param_bounds] { let mut bounds = ~[]; - for reader::tagged_docs(item, tag_items_data_item_ty_param_bounds) |p| { + for reader::tagged_docs(item, tag) |p| { let bd = parse_bounds_data(p.data, p.start, cdata.cnum, tcx, |_, did| translate_def_id(cdata, did)); bounds.push(bd); @@ -338,7 +358,8 @@ fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num) let enum_did = item_reqd_and_translated_parent_item(cnum, item); dl_def(ast::def_variant(enum_did, did)) } - Trait | Enum => dl_def(ast::def_ty(did)), + Trait => dl_def(ast::def_trait(did)), + Enum => dl_def(ast::def_ty(did)), Impl => dl_impl(did), PublicField | PrivateField | InheritedField => dl_field, } @@ -352,6 +373,21 @@ pub fn lookup_def(cnum: ast::crate_num, data: @~[u8], did_: ast::def_id) -> return def_like_to_def(item_to_def_like(item, did, cnum)); } +pub fn get_trait_def(cdata: cmd, + item_id: ast::node_id, + tcx: ty::ctxt) -> ty::TraitDef +{ + let item_doc = lookup_item(item_id, cdata.data); + let tp_bounds = item_ty_param_bounds(item_doc, tcx, cdata, + tag_items_data_item_ty_param_bounds); + let rp = item_ty_region_param(item_doc); + ty::TraitDef { + generics: ty::Generics {bounds: tp_bounds, + region_param: rp}, + trait_ref: @item_trait_ref(item_doc, tcx, cdata) + } +} + pub fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) -> ty::ty_param_bounds_and_ty { @@ -359,12 +395,12 @@ pub fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) let t = item_type(ast::def_id { crate: cdata.cnum, node: id }, item, tcx, cdata); let tp_bounds = if family_has_type_params(item_family(item)) { - item_ty_param_bounds(item, tcx, cdata) + item_ty_param_bounds(item, tcx, cdata, tag_items_data_item_ty_param_bounds) } else { @~[] }; let rp = item_ty_region_param(item); ty::ty_param_bounds_and_ty { - bounds: tp_bounds, - region_param: rp, + generics: ty::Generics {bounds: tp_bounds, + region_param: rp}, ty: t } } @@ -380,9 +416,19 @@ pub fn get_type_param_count(data: @~[u8], id: ast::node_id) -> uint { item_ty_param_count(lookup_item(id, data)) } -pub fn get_impl_traits(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) - -> ~[ty::t] { - item_impl_traits(lookup_item(id, cdata.data), tcx, cdata) +pub fn get_impl_traits(cdata: cmd, + id: ast::node_id, + tcx: ty::ctxt) -> ~[@ty::TraitRef] +{ + let item_doc = lookup_item(id, cdata.data); + let mut results = ~[]; + for reader::tagged_docs(item_doc, tag_item_trait_ref) |tp| { + let trait_ref = + @parse_trait_ref_data(tp.data, cdata.cnum, tp.start, tcx, + |_, did| translate_def_id(cdata, did)); + results.push(trait_ref); + }; + results } pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, @@ -690,36 +736,53 @@ pub fn get_impls_for_mod(intr: @ident_interner, @result } -/* Works for both classes and traits */ -pub fn get_trait_methods(intr: @ident_interner, cdata: cmd, id: ast::node_id, - tcx: ty::ctxt) -> @~[ty::method] { +pub fn get_method_name_and_self_ty( + intr: @ident_interner, + cdata: cmd, + id: ast::node_id) -> (ast::ident, ast::self_ty_) +{ + let method_doc = lookup_item(id, cdata.data); + let name = item_name(intr, method_doc); + let self_ty = get_self_ty(method_doc); + (name, self_ty) +} + +pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, + tcx: ty::ctxt) -> ty::method +{ + let method_doc = lookup_item(id, cdata.data); + let def_id = item_def_id(method_doc, cdata); + let name = item_name(intr, method_doc); + let bounds = + item_ty_param_bounds(method_doc, tcx, cdata, + tag_item_method_tps); + let transformed_self_ty = doc_transformed_self_ty(method_doc, tcx, cdata); + let fty = doc_method_fty(method_doc, tcx, cdata); + let vis = item_visibility(method_doc); + let self_ty = get_self_ty(method_doc); + ty::method { + ident: name, + generics: ty::Generics { + bounds: bounds, + region_param: None + }, + transformed_self_ty: transformed_self_ty, + fty: fty, + self_ty: self_ty, + vis: vis, + def_id: def_id + } +} + +pub fn get_trait_method_def_ids(cdata: cmd, + id: ast::node_id) -> ~[ast::def_id] { let data = cdata.data; let item = lookup_item(id, data); let mut result = ~[]; for reader::tagged_docs(item, tag_item_trait_method) |mth| { - let bounds = item_ty_param_bounds(mth, tcx, cdata); - let name = item_name(intr, mth); - let ty = doc_type(mth, tcx, cdata); - let def_id = item_def_id(mth, cdata); - let fty = match ty::get(ty).sty { - ty::ty_bare_fn(ref f) => copy *f, - _ => { - tcx.diag.handler().bug( - ~"get_trait_methods: id has non-function type"); - } - }; - let self_ty = get_self_ty(mth); - result.push(ty::method { - ident: name, - tps: bounds, - fty: fty, - self_ty: self_ty, - vis: ast::public, - def_id: def_id - }); + result.push(item_def_id(mth, cdata)); } - debug!("get_trait_methods: }"); - @result + result } pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, @@ -734,7 +797,8 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, let did = item_def_id(mth, cdata); - let bounds = item_ty_param_bounds(mth, tcx, cdata); + let bounds = item_ty_param_bounds(mth, tcx, cdata, + tag_items_data_item_ty_param_bounds); let name = item_name(intr, mth); let ty = doc_type(mth, tcx, cdata); @@ -746,10 +810,15 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, } }; + let transformed_self_ty = doc_transformed_self_ty(mth, tcx, cdata); let self_ty = get_self_ty(mth); let ty_method = ty::method { ident: name, - tps: bounds, + generics: ty::Generics { + bounds: bounds, + region_param: None + }, + transformed_self_ty: transformed_self_ty, fty: fty, self_ty: self_ty, vis: ast::public, @@ -768,35 +837,15 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, /// Returns the supertraits of the given trait. pub fn get_supertraits(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) - -> ~[ty::t] { + -> ~[@ty::TraitRef] { let mut results = ~[]; let item_doc = lookup_item(id, cdata.data); - for reader::tagged_docs(item_doc, tag_impl_trait) |trait_doc| { - results.push(doc_type(trait_doc, tcx, cdata)); + for reader::tagged_docs(item_doc, tag_item_super_trait_ref) |trait_doc| { + results.push(@doc_trait_ref(trait_doc, tcx, cdata)); } return results; } -// If the item in question is a trait, returns its set of methods and -// their self types. Otherwise, returns none. This overlaps in an -// annoying way with get_trait_methods. -pub fn get_method_names_if_trait(intr: @ident_interner, cdata: cmd, - node_id: ast::node_id) - -> Option<~[(ast::ident, ast::self_ty_)]> { - - let item = lookup_item(node_id, cdata.data); - if item_family(item) != Trait { - return None; - } - - let mut resulting_methods = ~[]; - for reader::tagged_docs(item, tag_item_trait_method) |method| { - resulting_methods.push( - (item_name(intr, method), get_self_ty(method))); - } - return Some(resulting_methods); -} - pub fn get_type_name_if_impl(intr: @ident_interner, cdata: cmd, node_id: ast::node_id) -> Option { @@ -821,8 +870,8 @@ pub fn get_static_methods_if_impl(intr: @ident_interner, return None; } - // If this impl has a trait ref, don't consider it. - for reader::tagged_docs(item, tag_impl_trait) |_doc| { + // If this impl implements a trait, don't consider it. + for reader::tagged_docs(item, tag_item_trait_ref) |_doc| { return None; } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 6000e559554f3..e251af7c8a85b 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -153,14 +153,23 @@ fn add_to_index(ecx: @EncodeContext, ebml_w: writer::Encoder, path: &[ident], }); } -fn encode_trait_ref(ebml_w: writer::Encoder, ecx: @EncodeContext, - t: @trait_ref) { - ebml_w.start_tag(tag_impl_trait); - encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, t.ref_id)); +fn encode_trait_ref(ebml_w: writer::Encoder, + ecx: @EncodeContext, + trait_ref: &ty::TraitRef, + tag: uint) +{ + let ty_str_ctxt = @tyencode::ctxt { + diag: ecx.diag, + ds: def_to_str, + tcx: ecx.tcx, + reachable: |a| reachable(ecx, a), + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + + ebml_w.start_tag(tag); + tyencode::enc_trait_ref(ebml_w.writer, ty_str_ctxt, trait_ref); ebml_w.end_tag(); } - // Item info table encoding fn encode_family(ebml_w: writer::Encoder, c: char) { ebml_w.start_tag(tag_items_data_item_family); @@ -170,8 +179,10 @@ fn encode_family(ebml_w: writer::Encoder, c: char) { pub fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) } -fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, ecx: @EncodeContext, - params: @~[ty::param_bounds]) { +fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, + ecx: @EncodeContext, + params: @~[ty::param_bounds], + tag: uint) { let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, @@ -179,7 +190,7 @@ fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, ecx: @EncodeContext, reachable: |a| reachable(ecx, a), abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; for params.each |param| { - ebml_w.start_tag(tag_items_data_item_ty_param_bounds); + ebml_w.start_tag(tag); tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, *param); ebml_w.end_tag(); } @@ -190,7 +201,8 @@ fn encode_type_param_bounds(ebml_w: writer::Encoder, params: &OptVec) { let ty_param_bounds = @params.map_to_vec(|param| *ecx.tcx.ty_param_bounds.get(¶m.id)); - encode_ty_type_param_bounds(ebml_w, ecx, ty_param_bounds); + encode_ty_type_param_bounds(ebml_w, ecx, ty_param_bounds, + tag_items_data_item_ty_param_bounds); } @@ -227,6 +239,34 @@ fn encode_type(ecx: @EncodeContext, ebml_w: writer::Encoder, typ: ty::t) { ebml_w.end_tag(); } +fn encode_transformed_self_ty(ecx: @EncodeContext, + ebml_w: writer::Encoder, + opt_typ: Option) +{ + for opt_typ.each |&typ| { + ebml_w.start_tag(tag_item_method_transformed_self_ty); + write_type(ecx, ebml_w, typ); + ebml_w.end_tag(); + } +} + +fn encode_method_fty(ecx: @EncodeContext, + ebml_w: writer::Encoder, + typ: &ty::BareFnTy) +{ + ebml_w.start_tag(tag_item_method_fty); + + let ty_str_ctxt = @tyencode::ctxt { + diag: ecx.diag, + ds: def_to_str, + tcx: ecx.tcx, + reachable: |a| reachable(ecx, a), + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + tyencode::enc_bare_fn_ty(ebml_w.writer, ty_str_ctxt, typ); + + ebml_w.end_tag(); +} + fn encode_symbol(ecx: @EncodeContext, ebml_w: writer::Encoder, id: node_id) { ebml_w.start_tag(tag_items_data_item_symbol); match ecx.item_symbols.find(&id) { @@ -542,13 +582,26 @@ fn encode_info_for_struct_ctor(ecx: @EncodeContext, ebml_w.end_tag(); } +fn encode_method_ty_fields(ecx: @EncodeContext, + ebml_w: writer::Encoder, + method_ty: &ty::method) +{ + encode_def_id(ebml_w, method_ty.def_id); + encode_name(ecx, ebml_w, method_ty.ident); + encode_ty_type_param_bounds(ebml_w, ecx, method_ty.generics.bounds, + tag_item_method_tps); + encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty); + encode_method_fty(ecx, ebml_w, &method_ty.fty); + encode_visibility(ebml_w, method_ty.vis); + encode_self_type(ebml_w, method_ty.self_ty); +} + fn encode_info_for_method(ecx: @EncodeContext, ebml_w: writer::Encoder, impl_path: &[ast_map::path_elt], should_inline: bool, parent_id: node_id, m: @method, - parent_visibility: ast::visibility, owner_generics: &ast::Generics, method_generics: &ast::Generics) { debug!("encode_info_for_method: %d %s %u %u", m.id, @@ -556,7 +609,10 @@ fn encode_info_for_method(ecx: @EncodeContext, owner_generics.ty_params.len(), method_generics.ty_params.len()); ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(m.id)); + + let method_def_id = local_def(m.id); + let method_ty: @ty::method = ty::method(ecx.tcx, method_def_id); + encode_method_ty_fields(ecx, ebml_w, method_ty); match m.self_ty.node { ast::sty_static => { @@ -572,16 +628,7 @@ fn encode_info_for_method(ecx: @EncodeContext, encode_type_param_bounds(ebml_w, ecx, &combined_ty_params); encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); - encode_name(ecx, ebml_w, m.ident); encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident)); - encode_self_type(ebml_w, m.self_ty.node); - - // Combine parent visibility and this visibility. - let visibility = match m.vis { - ast::inherited => parent_visibility, - vis => vis, - }; - encode_visibility(ebml_w, visibility); if len > 0u || should_inline { (ecx.encode_inlined_item)( @@ -590,6 +637,7 @@ fn encode_info_for_method(ecx: @EncodeContext, } else { encode_symbol(ecx, ebml_w, m.id); } + ebml_w.end_tag(); } @@ -833,8 +881,9 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder, ebml_w.writer.write(str::to_bytes(def_to_str(method_def_id))); ebml_w.end_tag(); } - for opt_trait.each |associated_trait| { - encode_trait_ref(ebml_w, ecx, *associated_trait); + for opt_trait.each |ast_trait_ref| { + let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id); + encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref); } encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); ebml_w.end_tag(); @@ -843,17 +892,6 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder, let mut impl_path = vec::append(~[], path); impl_path += ~[ast_map::path_name(item.ident)]; - // If there is a trait reference, treat the methods as always public. - // This is to work around some incorrect behavior in privacy checking: - // when the method belongs to a trait, it should acquire the privacy - // from the trait, not the impl. Forcing the visibility to be public - // makes things sorta work. - let parent_visibility = if opt_trait.is_some() { - ast::public - } else { - item.vis - }; - for methods.each |m| { index.push(entry {val: m.id, pos: ebml_w.writer.tell()}); encode_info_for_method(ecx, @@ -862,113 +900,95 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder, should_inline(m.attrs), item.id, *m, - parent_visibility, generics, &m.generics); } } - item_trait(ref generics, ref traits, ref ms) => { - let mut provided_methods = ~[]; - + item_trait(ref generics, ref super_traits, ref ms) => { add_to_index(); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); encode_family(ebml_w, 'I'); encode_region_param(ecx, ebml_w, item); encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + let trait_def = ty::lookup_trait_def(tcx, local_def(item.id)); + encode_trait_ref(ebml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); - let mut i = 0u; - for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| { - match (*ms)[i] { - required(ref ty_m) => { - ebml_w.start_tag(tag_item_trait_method); - encode_def_id(ebml_w, local_def((*ty_m).id)); - encode_name(ecx, ebml_w, mty.ident); - encode_type_param_bounds(ebml_w, ecx, - &ty_m.generics.ty_params); - encode_type(ecx, ebml_w, - ty::mk_bare_fn(tcx, copy mty.fty)); - encode_family(ebml_w, purity_fn_family(mty.fty.purity)); - encode_self_type(ebml_w, mty.self_ty); - encode_method_sort(ebml_w, 'r'); - encode_visibility(ebml_w, ast::public); - ebml_w.end_tag(); - } - provided(m) => { - provided_methods.push(m); - - ebml_w.start_tag(tag_item_trait_method); - encode_def_id(ebml_w, local_def(m.id)); - encode_name(ecx, ebml_w, mty.ident); - encode_type_param_bounds(ebml_w, ecx, - &m.generics.ty_params); - encode_type(ecx, ebml_w, - ty::mk_bare_fn(tcx, copy mty.fty)); - encode_family(ebml_w, purity_fn_family(mty.fty.purity)); - encode_self_type(ebml_w, mty.self_ty); - encode_method_sort(ebml_w, 'p'); - encode_visibility(ebml_w, m.vis); - ebml_w.end_tag(); - } - } - i += 1; + for ty::trait_method_def_ids(tcx, local_def(item.id)).each |&method_def_id| { + ebml_w.start_tag(tag_item_trait_method); + encode_def_id(ebml_w, method_def_id); + ebml_w.end_tag(); } encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - for traits.each |associated_trait| { - encode_trait_ref(ebml_w, ecx, *associated_trait) + for super_traits.each |ast_trait_ref| { + let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id); + encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref); } - ebml_w.end_tag(); - // Now, output all of the static methods as items. Note that for the - // method info, we output static methods with type signatures as - // written. Here, we output the *real* type signatures. I feel like - // maybe we should only ever handle the real type signatures. - for ms.each |m| { - let ty_m = ast_util::trait_method_to_ty_method(m); - if ty_m.self_ty.node != ast::sty_static { loop; } + // Now output the method info for each method. + for ty::trait_method_def_ids(tcx, local_def(item.id)).eachi |i, &method_def_id| { + assert!(method_def_id.crate == ast::local_crate); + + let method_ty: @ty::method = ty::method(tcx, method_def_id); - index.push(entry { val: ty_m.id, pos: ebml_w.writer.tell() }); + index.push(entry {val: method_def_id.node, pos: ebml_w.writer.tell()}); ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(ty_m.id)); + + encode_method_ty_fields(ecx, ebml_w, method_ty); + encode_parent_item(ebml_w, local_def(item.id)); - encode_name(ecx, ebml_w, ty_m.ident); - encode_family(ebml_w, - purity_static_method_family(ty_m.purity)); - let polyty = ecx.tcx.tcache.get(&local_def(ty_m.id)); - encode_ty_type_param_bounds(ebml_w, ecx, polyty.bounds); - encode_type(ecx, ebml_w, polyty.ty); - let mut m_path = vec::append(~[], path); // :-( - m_path += [ast_map::path_name(item.ident)]; - encode_path(ecx, ebml_w, m_path, ast_map::path_name(ty_m.ident)); - - // For now, use the item visibility until trait methods can have - // real visibility in the AST. - encode_visibility(ebml_w, item.vis); - ebml_w.end_tag(); - } + let mut trait_path = vec::append(~[], path); + trait_path.push(ast_map::path_name(item.ident)); + encode_path(ecx, ebml_w, trait_path, ast_map::path_name(method_ty.ident)); + + match method_ty.self_ty { + sty_static => { + encode_family(ebml_w, + purity_static_method_family( + method_ty.fty.purity)); - // Finally, output all the provided methods as items. - for provided_methods.each |m| { - index.push(entry { val: m.id, pos: ebml_w.writer.tell() }); + let tpt = ty::lookup_item_type(tcx, method_def_id); + encode_ty_type_param_bounds(ebml_w, ecx, tpt.generics.bounds, + tag_items_data_item_ty_param_bounds); + encode_type(ecx, ebml_w, tpt.ty); + } - // We do not concatenate the generics of the owning impl and that - // of provided methods. I am not sure why this is. -ndm - let owner_generics = ast_util::empty_generics(); + _ => { + encode_family(ebml_w, + purity_fn_family( + method_ty.fty.purity)); + } + } - encode_info_for_method(ecx, - ebml_w, - /*bad*/copy path, - true, - item.id, - *m, - item.vis, - &owner_generics, - &m.generics); + match ms[i] { + required(_) => { + encode_method_sort(ebml_w, 'r'); + } + + provided(m) => { + // This is obviously a bogus assert but I don't think this + // ever worked before anyhow...near as I can tell, before + // we would emit two items. + if method_ty.self_ty == sty_static { + tcx.sess.span_unimpl( + item.span, + fmt!("Method %s is both provided and static", + *tcx.sess.intr().get(method_ty.ident))); + } + encode_type_param_bounds(ebml_w, ecx, + &m.generics.ty_params); + encode_method_sort(ebml_w, 'p'); + (ecx.encode_inlined_item)( + ecx, ebml_w, path, + ii_method(local_def(item.id), m)); + } + } + + ebml_w.end_tag(); } } item_mac(*) => fail!(~"item macros unimplemented") diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 111bc307ed308..2ec13abb483d6 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -119,6 +119,18 @@ pub fn parse_ty_data(data: @~[u8], crate_num: int, pos: uint, tcx: ty::ctxt, parse_ty(st, conv) } +pub fn parse_bare_fn_ty_data(data: @~[u8], crate_num: int, pos: uint, tcx: ty::ctxt, + conv: conv_did) -> ty::BareFnTy { + let st = parse_state_from_data(data, crate_num, pos, tcx); + parse_bare_fn_ty(st, conv) +} + +pub fn parse_trait_ref_data(data: @~[u8], crate_num: int, pos: uint, tcx: ty::ctxt, + conv: conv_did) -> ty::TraitRef { + let st = parse_state_from_data(data, crate_num, pos, tcx); + parse_trait_ref(st, conv) +} + pub fn parse_arg_data(data: @~[u8], crate_num: int, pos: uint, tcx: ty::ctxt, conv: conv_did) -> ty::arg { let st = parse_state_from_data(data, crate_num, pos, tcx); @@ -177,7 +189,6 @@ fn parse_trait_store(st: @mut PState) -> ty::TraitStore { '~' => ty::UniqTraitStore, '@' => ty::BoxTraitStore, '&' => ty::RegionTraitStore(parse_region(st)), - '.' => ty::BareTraitStore, c => st.tcx.sess.bug(fmt!("parse_trait_store(): bad input '%c'", c)) } } @@ -259,6 +270,12 @@ fn parse_str(st: @mut PState, term: char) -> ~str { return result; } +fn parse_trait_ref(st: @mut PState, conv: conv_did) -> ty::TraitRef { + let def = parse_def(st, NominalType, conv); + let substs = parse_substs(st, conv); + ty::TraitRef {def_id: def, substs: substs} +} + fn parse_ty(st: @mut PState, conv: conv_did) -> ty::t { match next(st) { 'n' => return ty::mk_nil(st.tcx), @@ -545,7 +562,7 @@ fn parse_bounds(st: @mut PState, conv: conv_did) -> @~[ty::param_bound] { 'C' => ty::bound_copy, 'K' => ty::bound_const, 'O' => ty::bound_durable, - 'I' => ty::bound_trait(parse_ty(st, conv)), + 'I' => ty::bound_trait(@parse_trait_ref(st, conv)), '.' => break, _ => fail!(~"parse_bounds: bad bounds") }); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 251ba9b35cbd9..ca2d66de9c44d 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -214,11 +214,16 @@ pub fn enc_vstore(w: @io::Writer, cx: @ctxt, v: ty::vstore) { } } +pub fn enc_trait_ref(w: @io::Writer, cx: @ctxt, s: &ty::TraitRef) { + w.write_str((cx.ds)(s.def_id)); + w.write_char('|'); + enc_substs(w, cx, s.substs); +} + pub fn enc_trait_store(w: @io::Writer, cx: @ctxt, s: ty::TraitStore) { match s { ty::UniqTraitStore => w.write_char('~'), ty::BoxTraitStore => w.write_char('@'), - ty::BareTraitStore => w.write_char('.'), ty::RegionTraitStore(re) => { w.write_char('&'); enc_region(w, cx, re); @@ -384,7 +389,7 @@ fn enc_onceness(w: @io::Writer, o: Onceness) { } } -fn enc_bare_fn_ty(w: @io::Writer, cx: @ctxt, ft: &ty::BareFnTy) { +pub fn enc_bare_fn_ty(w: @io::Writer, cx: @ctxt, ft: &ty::BareFnTy) { enc_purity(w, ft.purity); enc_abi_set(w, ft.abis); enc_fn_sig(w, cx, &ft.sig); @@ -415,8 +420,8 @@ pub fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @~[ty::param_bound]) { ty::bound_const => w.write_char('K'), ty::bound_durable => w.write_char('O'), ty::bound_trait(tp) => { - w.write_char('I'); - enc_ty(w, cx, tp); + w.write_char('I'); + enc_trait_ref(w, cx, tp); } } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index b6b6730620e9e..20b72a19df794 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -417,6 +417,7 @@ impl tr for ast::def { ast::def_variant(e_did, v_did) => { ast::def_variant(e_did.tr(xcx), v_did.tr(xcx)) } + ast::def_trait(did) => ast::def_trait(did.tr(xcx)), ast::def_ty(did) => ast::def_ty(did.tr(xcx)), ast::def_prim_ty(p) => ast::def_prim_ty(p), ast::def_ty_param(did, v) => ast::def_ty_param(did.tr(xcx), v), @@ -778,16 +779,20 @@ impl ebml_writer_helpers for writer::Encoder { fn emit_tpbt(&self, ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty) { - do self.emit_struct("ty_param_bounds_and_ty", 3) { - do self.emit_field(~"bounds", 0) { - do self.emit_from_vec(*tpbt.bounds) |bs| { - self.emit_bounds(ecx, *bs); + do self.emit_struct("ty_param_bounds_and_ty", 2) { + do self.emit_field(~"generics", 0) { + do self.emit_struct("Generics", 2) { + do self.emit_field(~"bounds", 0) { + do self.emit_from_vec(*tpbt.generics.bounds) |bs| { + self.emit_bounds(ecx, *bs); + } + } + do self.emit_field(~"region_param", 1) { + tpbt.generics.region_param.encode(self); + } } } - do self.emit_field(~"region_param", 1u) { - tpbt.region_param.encode(self); - } - do self.emit_field(~"ty", 2u) { + do self.emit_field(~"ty", 1) { self.emit_ty(ecx, tpbt.ty); } } @@ -1045,15 +1050,19 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) -> ty::ty_param_bounds_and_ty { - do self.read_struct("ty_param_bounds_and_ty", 3) { + do self.read_struct("ty_param_bounds_and_ty", 2) { ty::ty_param_bounds_and_ty { - bounds: self.read_field(~"bounds", 0u, || { - @self.read_to_vec(|| self.read_bounds(xcx) ) - }), - region_param: self.read_field(~"region_param", 1u, || { - Decodable::decode(self) - }), - ty: self.read_field(~"ty", 2u, || { + generics: do self.read_struct("Generics", 2) { + ty::Generics { + bounds: self.read_field(~"bounds", 0, || { + @self.read_to_vec(|| self.read_bounds(xcx) ) + }), + region_param: self.read_field(~"region_param", 1, || { + Decodable::decode(self) + }) + } + }, + ty: self.read_field(~"ty", 1, || { self.read_ty(xcx) }) } diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index a25e2f49e099e..96e8ef40770a2 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -91,7 +91,7 @@ fn check_struct_safe_for_destructor(cx: Context, span: span, struct_did: def_id) { let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did); - if struct_tpt.bounds.len() == 0 { + if struct_tpt.generics.bounds.len() == 0 { let struct_ty = ty::mk_struct(cx.tcx, struct_did, ty::substs { self_r: None, self_ty: None, @@ -279,7 +279,7 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt) { let bounds = match e.node { expr_path(_) => { let did = ast_util::def_id_of_def(*cx.tcx.def_map.get(&e.id)); - ty::lookup_item_type(cx.tcx, did).bounds + ty::lookup_item_type(cx.tcx, did).generics.bounds } _ => { // Type substitutions should only occur on paths and @@ -340,7 +340,7 @@ fn check_ty(aty: @Ty, cx: Context, v: visit::vt) { // FIXME(#5562): removing this copy causes a segfault before stage2 let ts = /*bad*/ copy **ts; let did = ast_util::def_id_of_def(*cx.tcx.def_map.get(&id)); - let bounds = ty::lookup_item_type(cx.tcx, did).bounds; + let bounds = ty::lookup_item_type(cx.tcx, did).generics.bounds; for vec::each2(ts, *bounds) |ty, bound| { check_bounds(cx, aty.id, aty.span, *ty, *bound) } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index a21cc26bd9124..b4aff91ed5b28 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -825,8 +825,7 @@ fn check_item_heap(cx: ty::ctxt, it: @ast::item) { ast::item_fn(*) | ast::item_ty(*) | ast::item_enum(*) | - ast::item_struct(*) | - ast::item_trait(*) => check_type(cx, it.id, it.id, it.span, + ast::item_struct(*) => check_type(cx, it.id, it.id, it.span, ty::node_id_to_type(cx, it.id)), _ => () } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index b7ec6208d5607..6473cb8e8e006 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -462,7 +462,7 @@ pub impl mem_categorization_ctxt { ast::def_fn(*) | ast::def_static_method(*) | ast::def_mod(_) | ast::def_foreign_mod(_) | ast::def_const(_) | ast::def_use(_) | ast::def_variant(*) | - ast::def_ty(_) | ast::def_prim_ty(_) | + ast::def_trait(_) | ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty_param(*) | ast::def_struct(*) | ast::def_typaram_binder(*) | ast::def_region(_) | ast::def_label(_) | ast::def_self_ty(*) => { diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index 2f379ece5d374..1401d86123e64 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -211,7 +211,7 @@ use core::prelude::*; use middle::pat_util::{pat_bindings}; use middle::freevars; use middle::ty; -use middle::typeck::method_map; +use middle::typeck::{method_map}; use util::ppaux; use util::common::indenter; @@ -463,7 +463,7 @@ pub impl VisitContext { expr_method_call(callee, _, _, ref args, _) => { // callee.m(args) // Implicit self is equivalent to & mode, but every // other kind should be + mode. - self.use_receiver(expr.id, expr.span, callee, visitor); + self.use_receiver(callee, visitor); self.use_fn_args(expr.callee_id, *args, visitor); } @@ -665,7 +665,7 @@ pub impl VisitContext { return false; } - self.use_receiver(expr.id, expr.span, receiver_expr, visitor); + self.use_receiver(receiver_expr, visitor); // for overloaded operatrs, we are always passing in a // borrowed pointer, so it's always read mode: @@ -718,8 +718,6 @@ pub impl VisitContext { } fn use_receiver(&self, - _expr_id: node_id, - _span: span, receiver_expr: @expr, visitor: vt) { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 75eb8ef1a8580..1c60c37ed12a0 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -690,7 +690,9 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, match ty.node { ast::ty_path(path, id) => { match cx.def_map.find(&id) { - Some(&ast::def_ty(did)) | Some(&ast::def_struct(did)) => { + Some(&ast::def_ty(did)) | + Some(&ast::def_trait(did)) | + Some(&ast::def_struct(did)) => { if did.crate == ast::local_crate { if cx.region_is_relevant(path.rp) { cx.add_dep(did.node); diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 08542301e238f..fcf0b7022a7a7 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -12,7 +12,8 @@ use core::prelude::*; use driver::session; use driver::session::Session; -use metadata::csearch::{each_path, get_method_names_if_trait}; +use metadata::csearch::{each_path, get_trait_method_def_ids}; +use metadata::csearch::get_method_name_and_self_ty; use metadata::csearch::get_static_methods_if_impl; use metadata::csearch::get_type_name_if_impl; use metadata::cstore::find_extern_mod_stmt_cnum; @@ -31,7 +32,7 @@ use syntax::ast::{crate, decl_item, def, def_arg, def_binding}; use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label}; use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self}; use syntax::ast::{def_self_ty, def_static_method, def_struct, def_ty}; -use syntax::ast::{def_ty_param, def_typaram_binder}; +use syntax::ast::{def_ty_param, def_typaram_binder, def_trait}; use syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op}; use syntax::ast::{expr_binary, expr_break, expr_field}; use syntax::ast::{expr_fn_block, expr_index, expr_method_call, expr_path}; @@ -78,6 +79,7 @@ use syntax::opt_vec::OptVec; use core::option::Some; use core::str::each_split_str; use core::hashmap::{HashMap, HashSet}; +use core::util; // Definition mapping pub type DefMap = @mut HashMap; @@ -1341,7 +1343,7 @@ pub impl Resolver { let def_id = local_def(item.id); self.trait_info.insert(def_id, method_names); - name_bindings.define_type(privacy, def_ty(def_id), sp); + name_bindings.define_type(privacy, def_trait(def_id), sp); visit_item(item, new_parent, visitor); } @@ -1611,36 +1613,40 @@ pub impl Resolver { crate) building value %s", final_ident); child_name_bindings.define_value(Public, def, dummy_sp()); } - def_ty(def_id) => { - debug!("(building reduced graph for external \ - crate) building type %s", final_ident); - - // If this is a trait, add all the method names - // to the trait info. - - match get_method_names_if_trait(self.session.cstore, def_id) { - None => { - // Nothing to do. - } - Some(method_names) => { - let mut interned_method_names = HashSet::new(); - for method_names.each |method_data| { - let (method_name, self_ty) = *method_data; - debug!("(building reduced graph for \ - external crate) ... adding \ - trait method '%s'", - *self.session.str_of(method_name)); - - // Add it to the trait info if not static. - if self_ty != sty_static { - interned_method_names.insert(method_name); - } - } - self.trait_info.insert(def_id, interned_method_names); + def_trait(def_id) => { + debug!("(building reduced graph for external \ + crate) building type %s", final_ident); + + // If this is a trait, add all the method names + // to the trait info. + + let method_def_ids = get_trait_method_def_ids(self.session.cstore, + def_id); + let mut interned_method_names = HashSet::new(); + for method_def_ids.each |&method_def_id| { + let (method_name, self_ty) = + get_method_name_and_self_ty(self.session.cstore, + method_def_id); + + debug!("(building reduced graph for \ + external crate) ... adding \ + trait method '%s'", + *self.session.str_of(method_name)); + + // Add it to the trait info if not static. + if self_ty != sty_static { + interned_method_names.insert(method_name); + } } - } + self.trait_info.insert(def_id, interned_method_names); - child_name_bindings.define_type(Public, def, dummy_sp()); + child_name_bindings.define_type(Public, def, dummy_sp()); + } + def_ty(_) => { + debug!("(building reduced graph for external \ + crate) building type %s", final_ident); + + child_name_bindings.define_type(Public, def, dummy_sp()); } def_struct(def_id) => { debug!("(building reduced graph for external \ @@ -3409,7 +3415,6 @@ pub impl Resolver { self_type, ref methods) => { self.resolve_implementation(item.id, - item.span, generics, implemented_traits, self_type, @@ -3718,13 +3723,30 @@ pub impl Resolver { for type_parameters.each |type_parameter| { for type_parameter.bounds.each |&bound| { match bound { - TraitTyParamBound(ty) => self.resolve_type(ty, visitor), + TraitTyParamBound(tref) => { + self.resolve_trait_reference(tref, visitor) + } RegionTyParamBound => {} } } } } + fn resolve_trait_reference(@mut self, + trait_reference: &trait_ref, + visitor: ResolveVisitor) { + match self.resolve_path(trait_reference.path, TypeNS, true, visitor) { + None => { + self.session.span_err(trait_reference.path.span, + ~"attempt to implement an \ + unknown trait"); + } + Some(def) => { + self.record_def(trait_reference.ref_id, def); + } + } + } + fn resolve_struct(@mut self, id: node_id, generics: &Generics, @@ -3792,7 +3814,6 @@ pub impl Resolver { fn resolve_implementation(@mut self, id: node_id, - span: span, generics: &Generics, opt_trait_reference: Option<@trait_ref>, self_type: @Ty, @@ -3811,25 +3832,16 @@ pub impl Resolver { let original_trait_refs; match opt_trait_reference { Some(trait_reference) => { - let mut new_trait_refs = ~[]; - match self.resolve_path( - trait_reference.path, TypeNS, true, visitor) { - None => { - self.session.span_err(span, - ~"attempt to implement an \ - unknown trait"); - } - Some(def) => { - self.record_def(trait_reference.ref_id, def); + self.resolve_trait_reference(trait_reference, visitor); - // Record the current trait reference. - new_trait_refs.push(def_id_of_def(def)); - } - } // Record the current set of trait references. - let mut old = Some(new_trait_refs); - self.current_trait_refs <-> old; - original_trait_refs = Some(old); + let mut new_trait_refs = ~[]; + for self.def_map.find(&trait_reference.ref_id).each |&def| { + new_trait_refs.push(def_id_of_def(*def)); + } + original_trait_refs = Some(util::replace( + &mut self.current_trait_refs, + Some(new_trait_refs))); } None => { original_trait_refs = None; @@ -4952,7 +4964,7 @@ pub impl Resolver { match child_name_bindings.def_for_namespace(TypeNS) { Some(def) => { match def { - def_ty(trait_def_id) => { + def_trait(trait_def_id) => { self.add_trait_info_if_containing_method( &mut found_traits, trait_def_id, name); } @@ -4979,7 +4991,7 @@ pub impl Resolver { match target.bindings.def_for_namespace(TypeNS) { Some(def) => { match def { - def_ty(trait_def_id) => { + def_trait(trait_def_id) => { let added = self. add_trait_info_if_containing_method( &mut found_traits, diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index ec67c68f93cda..de14266573af9 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -148,7 +148,7 @@ pub fn trans(bcx: block, expr: @ast::expr) -> Callee { ast::def_self(*) => { datum_callee(bcx, ref_expr) } - ast::def_mod(*) | ast::def_foreign_mod(*) | + ast::def_mod(*) | ast::def_foreign_mod(*) | ast::def_trait(*) | ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) | ast::def_use(*) | ast::def_typaram_binder(*) | ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) | @@ -238,8 +238,7 @@ pub fn trans_fn_ref_with_vtables( // Modify the def_id if this is a default method; we want to be // monomorphizing the trait's code. - let (def_id, opt_impl_did) = - match tcx.provided_method_sources.find(&def_id) { + let (def_id, opt_impl_did) = match tcx.provided_method_sources.find(&def_id) { None => (def_id, None), Some(source) => (source.method_id, Some(source.impl_id)) }; diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index f0c17a6f80d7b..593d37c2ff8d1 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1062,9 +1062,6 @@ pub fn T_opaque_trait(cx: @CrateContext, store: ty::TraitStore) -> TypeRef { ty::RegionTraitStore(_) => { T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())]) } - ty::BareTraitStore => { - cx.sess.bug(~"can't make T_opaque_trait with bare trait store") - } } } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 5afdd1b027188..d4a1013e83c85 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1714,7 +1714,6 @@ fn trans_assign_op(bcx: block, return result_datum.copy_to_datum(bcx, DROP_EXISTING, dst_datum); } -// NOTE: Mode neccessary here? fn shorten(+x: ~str) -> ~str { if x.len() > 60 { x.substr(0, 60).to_owned() } else { x } } diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 1b27d21e6f464..d8c8301a83563 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -40,7 +40,6 @@ use core::libc::c_uint; use core::str; use std::time; use syntax::ast; -use syntax::parse::token::special_idents; pub fn trans_free(cx: block, v: ValueRef) -> block { let _icx = cx.insn_ctxt("trans_free"); @@ -400,11 +399,9 @@ pub fn call_tydesc_glue(++cx: block, v: ValueRef, t: ty::t, field: uint) pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) { let _icx = bcx.insn_ctxt("make_visit_glue"); let mut bcx = bcx; - let ty_visitor_name = special_idents::ty_visitor; - assert!(bcx.ccx().tcx.intrinsic_defs.contains_key(&ty_visitor_name)); - let (trait_id, ty) = *bcx.ccx().tcx.intrinsic_defs.get(&ty_visitor_name); - let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), ty))); - bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, trait_id); + let (visitor_trait, object_ty) = ty::visitor_object_ty(bcx.tcx()); + let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), object_ty))); + bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id); build_return(bcx); } @@ -554,8 +551,7 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { ty::ty_closure(_) => { closure::make_closure_glue(bcx, v0, t, drop_ty) } - ty::ty_trait(_, _, ty::BoxTraitStore) | - ty::ty_trait(_, _, ty::BareTraitStore) => { + ty::ty_trait(_, _, ty::BoxTraitStore) => { let llbox = Load(bcx, GEPi(bcx, v0, [0u, 1u])); decr_refcnt_maybe_free(bcx, llbox, ty::mk_opaque_box(ccx.tcx)) } @@ -621,8 +617,7 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) { ty::ty_closure(_) => { closure::make_closure_glue(bcx, v, t, take_ty) } - ty::ty_trait(_, _, ty::BoxTraitStore) | - ty::ty_trait(_, _, ty::BareTraitStore) => { + ty::ty_trait(_, _, ty::BoxTraitStore) => { let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u])); incr_refcnt_of_boxed(bcx, llbox); bcx diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index cb20e5bbd32c3..2ca19b9075423 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -87,8 +87,7 @@ pub fn maybe_instantiate_inline(ccx: @CrateContext, fn_id: ast::def_id, ccx.stats.n_inlines += 1; ccx.external.insert(fn_id, Some(mth.id)); let ty::ty_param_bounds_and_ty { - bounds: impl_bnds, - region_param: _, + generics: ty::Generics { bounds: impl_bnds, _ }, ty: _ } = ty::lookup_item_type(ccx.tcx, impl_did); if translate && diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index ed9000e7418a4..bbf53480a56fb 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -11,7 +11,6 @@ use core::prelude::*; use back::abi; -use driver; use lib::llvm::llvm; use lib::llvm::ValueRef; use lib; @@ -174,6 +173,7 @@ pub fn trans_method_callee(bcx: block, mentry: typeck::method_map_entry) -> Callee { let _icx = bcx.insn_ctxt("impl::trans_method_callee"); + let tcx = bcx.tcx(); debug!("trans_method_callee(callee_id=%?, self=%s, mentry=%?)", callee_id, bcx.expr_to_str(self), mentry); @@ -189,33 +189,33 @@ pub fn trans_method_callee(bcx: block, // Get the ID of the method we're calling. let method_name = - ty::trait_methods(bcx.tcx(), trait_id)[method_index].ident; - let method_id = method_with_name(bcx.ccx(), impl_def_id, - method_name); + ty::trait_method(tcx, trait_id, method_index).ident; + let method_id = + method_with_name(bcx.ccx(), impl_def_id, method_name); origin = typeck::method_static(method_id); } typeck::method_super(trait_id, method_index) => { // is the self type for this method call let self_ty = node_id_type(bcx, self.id); - let tcx = bcx.tcx(); // is the ID of the implementation of // trait for type let impl_id = ty::get_impl_id(tcx, trait_id, self_ty); // Get the supertrait's methods - let supertrait_methods = ty::trait_methods(tcx, trait_id); + let supertrait_method_def_ids = ty::trait_method_def_ids(tcx, trait_id); // Make sure to fail with a readable error message if // there's some internal error here - if !(method_index < supertrait_methods.len()) { + if !(method_index < supertrait_method_def_ids.len()) { tcx.sess.bug(~"trans_method_callee: supertrait method \ index is out of bounds"); } // Get the method name using the method index in the origin - let method_name = supertrait_methods[method_index].ident; + let method_name = + ty::method(tcx, supertrait_method_def_ids[method_index]).ident; // Now that we know the impl ID, we can look up the method // ID from its name origin = typeck::method_static(method_with_name(bcx.ccx(), - impl_id, - method_name)); + impl_id, + method_name)); } typeck::method_static(*) | typeck::method_param(*) | typeck::method_trait(*) => {} @@ -301,8 +301,8 @@ pub fn trans_static_method_callee(bcx: block, // found on the type parametesr T1...Tn to find the index of the // one we are interested in. let bound_index = { - let trait_polyty = ty::lookup_item_type(bcx.tcx(), trait_id); - ty::count_traits_and_supertraits(bcx.tcx(), *trait_polyty.bounds) + let trait_def = ty::lookup_trait_def(bcx.tcx(), trait_id); + ty::count_traits_and_supertraits(bcx.tcx(), *trait_def.generics.bounds) }; let mname = if method_id.crate == ast::local_crate { @@ -375,7 +375,8 @@ pub fn method_with_name(ccx: @CrateContext, impl_id: ast::def_id, } } -pub fn method_with_name_or_default(ccx: @CrateContext, impl_id: ast::def_id, +pub fn method_with_name_or_default(ccx: @CrateContext, + impl_id: ast::def_id, name: ast::ident) -> ast::def_id { if impl_id.crate == ast::local_crate { match *ccx.tcx.items.get(&impl_id.node) { @@ -448,7 +449,7 @@ pub fn trans_monomorphized_callee(bcx: block, return match vtbl { typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => { let ccx = bcx.ccx(); - let mname = ty::trait_methods(ccx.tcx, trait_id)[n_method].ident; + let mname = ty::trait_method(ccx.tcx, trait_id, n_method).ident; let mth_id = method_with_name_or_default( bcx.ccx(), impl_did, mname); @@ -550,8 +551,10 @@ pub fn combine_impl_and_methods_origins(bcx: block, // rcvr + method bounds. let ccx = bcx.ccx(), tcx = bcx.tcx(); let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did); - let ty::ty_param_bounds_and_ty {bounds: r_m_bounds, _} - = ty::lookup_item_type(tcx, mth_did); + let ty::ty_param_bounds_and_ty { + generics: ty::Generics {bounds: r_m_bounds, _}, + _ + } = ty::lookup_item_type(tcx, mth_did); let n_r_m_tps = r_m_bounds.len(); // rcvr + method tps let m_boundss = vec::slice(*r_m_bounds, n_r_m_tps - n_m_tps, n_r_m_tps); @@ -654,7 +657,6 @@ pub fn trans_trait_callee_from_llval(bcx: block, // payload. match store { ty::BoxTraitStore | - ty::BareTraitStore | ty::UniqTraitStore => { llself = GEPi(bcx, llbox, [0u, abi::box_field_body]); } @@ -677,7 +679,7 @@ pub fn trans_trait_callee_from_llval(bcx: block, // Pass a pointer to the box. match store { - ty::BoxTraitStore | ty::BareTraitStore => llself = llbox, + ty::BoxTraitStore => llself = llbox, _ => bcx.tcx().sess.bug(~"@self receiver with non-@Trait") } @@ -783,18 +785,14 @@ pub fn make_impl_vtable(ccx: @CrateContext, let tcx = ccx.tcx; // XXX: This should support multiple traits. - let trt_id = driver::session::expect( - tcx.sess, - ty::ty_to_def_id(ty::impl_traits(tcx, - impl_id, - ty::BoxTraitStore)[0]), - || ~"make_impl_vtable: non-trait-type implemented"); - - let has_tps = (*ty::lookup_item_type(ccx.tcx, impl_id).bounds).len() > 0u; - make_vtable(ccx, vec::map(*ty::trait_methods(tcx, trt_id), |im| { + let trt_id = ty::impl_trait_refs(tcx, impl_id)[0].def_id; + + let has_tps = ty::lookup_item_type(ccx.tcx, impl_id).generics.bounds.len() > 0u; + make_vtable(ccx, ty::trait_method_def_ids(tcx, trt_id).map(|method_def_id| { + let im = ty::method(tcx, *method_def_id); let fty = ty::subst_tps(tcx, substs, None, ty::mk_bare_fn(tcx, copy im.fty)); - if (*im.tps).len() > 0u || ty::type_has_self(fty) { + if im.generics.bounds.len() > 0u || ty::type_has_self(fty) { debug!("(making impl vtable) method has self or type params: %s", *tcx.sess.str_of(im.ident)); C_null(T_ptr(T_nil())) @@ -841,7 +839,7 @@ pub fn trans_trait_cast(bcx: block, let v_ty = expr_ty(bcx, val); match store { - ty::RegionTraitStore(_) | ty::BoxTraitStore | ty::BareTraitStore => { + ty::RegionTraitStore(_) | ty::BoxTraitStore => { let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]); // Just store the pointer into the pair. llboxdest = PointerCast(bcx, diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 89617ac5eb8c3..319f57fb75ce0 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -169,7 +169,7 @@ pub fn monomorphic_fn(ccx: @CrateContext, let psubsts = Some(@param_substs { tys: substs, vtables: vtables, - bounds: tpt.bounds, + bounds: tpt.generics.bounds, self_ty: impl_ty_opt }); @@ -291,7 +291,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt, ty::ty_trait(_, _, ref store) => { let sigil = match *store { ty::UniqTraitStore => ast::OwnedSigil, - ty::BoxTraitStore | ty::BareTraitStore => ast::ManagedSigil, + ty::BoxTraitStore => ast::ManagedSigil, ty::RegionTraitStore(_) => ast::BorrowedSigil, }; @@ -328,7 +328,7 @@ pub fn make_mono_id(ccx: @CrateContext, item: ast::def_id, substs: &[ty::t], +param_uses: Option<~[type_use::type_uses]>) -> mono_id { let precise_param_ids = match vtables { Some(vts) => { - let bounds = ty::lookup_item_type(ccx.tcx, item).bounds; + let bounds = ty::lookup_item_type(ccx.tcx, item).generics.bounds; let mut i = 0; vec::map2(*bounds, substs, |bounds, subst| { let mut v = ~[]; diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index a9869f15875c7..224981d6e759a 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -31,7 +31,7 @@ use syntax::ast; pub struct Reflector { visitor_val: ValueRef, - visitor_methods: @~[ty::method], + visitor_methods: @~[@ty::method], final_bcx: block, tydesc_ty: TypeRef, bcx: block diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 30b933061e215..c29029de351e3 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -25,8 +25,10 @@ use middle; use util::ppaux::{note_and_explain_region, bound_region_to_str}; use util::ppaux::{region_to_str, vstore_to_str}; use util::ppaux::{trait_store_to_str, ty_to_str, tys_to_str}; +use util::ppaux::{trait_ref_to_str}; use util::common::{indenter}; +use core; use core::cast; use core::cmp; use core::ops; @@ -44,6 +46,7 @@ use syntax::ast_util; use syntax::codemap::span; use syntax::codemap; use syntax::print::pprust; +use syntax::parse::token::special_idents; use syntax::{ast, ast_map}; use syntax::opt_vec::OptVec; use syntax::opt_vec; @@ -70,7 +73,8 @@ pub type param_bounds = @~[param_bound]; pub struct method { ident: ast::ident, - tps: @~[param_bounds], + generics: ty::Generics, + transformed_self_ty: Option, fty: BareFnTy, self_ty: ast::self_ty_, vis: ast::visibility, @@ -95,9 +99,8 @@ pub enum vstore { #[auto_encode] #[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub enum TraitStore { - BareTraitStore, // a plain trait without a sigil BoxTraitStore, // @Trait UniqTraitStore, // ~Trait RegionTraitStore(Region), // &Trait @@ -194,13 +197,13 @@ pub enum AutoRefKind { /// Convert from T to &T AutoPtr, - /// Convert from @[]/~[] to &[] (or str) + /// Convert from @[]/~[]/&[] to &[] (or str) AutoBorrowVec, - /// Convert from @[]/~[] to &&[] (or str) + /// Convert from @[]/~[]/&[] to &&[] (or str) AutoBorrowVecRef, - /// Convert from @fn()/~fn() to &fn() + /// Convert from @fn()/~fn()/&fn() to &fn() AutoBorrowFn } @@ -224,11 +227,6 @@ pub struct ProvidedMethodSource { impl_id: ast::def_id } -pub struct InstantiatedTraitRef { - def_id: ast::def_id, - tpt: ty_param_substs_and_ty -} - pub type ctxt = @ctxt_; struct ctxt_ { @@ -255,8 +253,21 @@ struct ctxt_ { // other items. node_type_substs: @mut HashMap, + // Maps from a method to the method "descriptor" + methods: @mut HashMap, + + // Maps from a trait def-id to a list of the def-ids of its methods + trait_method_def_ids: @mut HashMap, + + // A cache for the trait_methods() routine + trait_methods_cache: @mut HashMap, + + trait_refs: @mut HashMap, + trait_defs: @mut HashMap, + items: ast_map::map, intrinsic_defs: @mut HashMap, + intrinsic_traits: @mut HashMap, freevars: freevars::freevar_map, tcache: type_cache, rcache: creader_cache, @@ -266,7 +277,6 @@ struct ctxt_ { tc_cache: @mut HashMap, ast_ty_to_ty_cache: @mut HashMap, enum_var_cache: @mut HashMap, - trait_method_cache: @mut HashMap, ty_param_bounds: @mut HashMap, inferred_modes: @mut HashMap, adjustments: @mut HashMap, @@ -277,7 +287,7 @@ struct ctxt_ { // that implementation implements. provided_methods: ProvidedMethodsMap, provided_method_sources: @mut HashMap, - supertraits: @mut HashMap, + supertraits: @mut HashMap, // A mapping from the def ID of an enum or struct type to the def ID // of the method that implements its destructor. If the type is not @@ -527,6 +537,12 @@ pub enum sty { ty_unboxed_vec(mt), } +#[deriving(Eq, IterBytes)] +pub struct TraitRef { + def_id: def_id, + substs: substs +} + #[deriving(Eq)] pub enum IntVarValue { IntType(ast::int_ty), @@ -573,16 +589,17 @@ pub enum type_err { terr_self_substs, terr_integer_as_char, terr_int_mismatch(expected_found), - terr_float_mismatch(expected_found) + terr_float_mismatch(expected_found), + terr_traits(expected_found), } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub enum param_bound { bound_copy, bound_durable, bound_owned, bound_const, - bound_trait(t), + bound_trait(@TraitRef), } #[deriving(Eq)] @@ -651,19 +668,6 @@ impl cmp::Eq for InferRegion { } } -impl to_bytes::IterBytes for param_bound { - fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - match *self { - bound_copy => 0u8.iter_bytes(lsb0, f), - bound_durable => 1u8.iter_bytes(lsb0, f), - bound_owned => 2u8.iter_bytes(lsb0, f), - bound_const => 3u8.iter_bytes(lsb0, f), - bound_trait(ref t) => - to_bytes::iter_bytes_2(&4u8, t, lsb0, f) - } - } -} - pub trait Vid { fn to_uint(&self) -> uint; } @@ -750,6 +754,13 @@ impl to_bytes::IterBytes for RegionVid { } } +/// Information about the type/lifetime parametesr associated with an item. +/// Analogous to ast::Generics. +pub struct Generics { + bounds: @~[param_bounds], + region_param: Option, +} + /// A polytype. /// /// - `bounds`: The list of bounds for each type parameter. The length of the @@ -761,11 +772,16 @@ impl to_bytes::IterBytes for RegionVid { /// - `ty`: the base type. May have reference to the (unsubstituted) bound /// region `&self` or to (unsubstituted) ty_param types pub struct ty_param_bounds_and_ty { - bounds: @~[param_bounds], - region_param: Option, + generics: Generics, ty: t } +/// As `ty_param_bounds_and_ty` but for a trait ref. +pub struct TraitDef { + generics: Generics, + trait_ref: @ty::TraitRef, +} + pub struct ty_param_substs_and_ty { substs: ty::substs, ty: ty::t @@ -820,6 +836,9 @@ pub fn mk_ctxt(s: session::Session, region_paramd_items: region_paramd_items, node_types: @mut SmallIntMap::new(), node_type_substs: @mut HashMap::new(), + trait_refs: @mut HashMap::new(), + trait_defs: @mut HashMap::new(), + intrinsic_traits: @mut HashMap::new(), items: amap, intrinsic_defs: @mut HashMap::new(), freevars: freevars, @@ -831,7 +850,9 @@ pub fn mk_ctxt(s: session::Session, tc_cache: @mut HashMap::new(), ast_ty_to_ty_cache: @mut HashMap::new(), enum_var_cache: @mut HashMap::new(), - trait_method_cache: @mut HashMap::new(), + methods: @mut HashMap::new(), + trait_method_def_ids: @mut HashMap::new(), + trait_methods_cache: @mut HashMap::new(), ty_param_bounds: @mut HashMap::new(), inferred_modes: @mut HashMap::new(), adjustments: @mut HashMap::new(), @@ -1401,7 +1422,7 @@ pub fn param_bound_to_str(cx: ctxt, pb: ¶m_bound) -> ~str { bound_durable => ~"'static", bound_owned => ~"owned", bound_const => ~"const", - bound_trait(t) => ::util::ppaux::ty_to_str(cx, t) + bound_trait(t) => ::util::ppaux::trait_ref_to_str(cx, t) } } @@ -1455,13 +1476,26 @@ pub fn subst(cx: ctxt, } } +pub fn subst_in_trait_ref(cx: ctxt, + substs: &substs, + trait_ref: &ty::TraitRef) -> ty::TraitRef +{ + ty::TraitRef { + def_id: trait_ref.def_id, + substs: subst_in_substs(cx, substs, &trait_ref.substs) + } +} + // Performs substitutions on a set of substitutions (result = sup(sub)) to // yield a new set of substitutions. This is used in trait inheritance. -pub fn subst_substs(cx: ctxt, sup: &substs, sub: &substs) -> substs { +pub fn subst_in_substs(cx: ctxt, + substs: &substs, + in_substs: &substs) -> substs +{ substs { - self_r: sup.self_r, - self_ty: sup.self_ty.map(|typ| subst(cx, sub, *typ)), - tps: sup.tps.map(|typ| subst(cx, sub, *typ)) + self_r: in_substs.self_r, + self_ty: in_substs.self_ty.map(|&typ| subst(cx, substs, typ)), + tps: in_substs.tps.map(|&typ| subst(cx, substs, typ)) } } @@ -1477,6 +1511,11 @@ pub fn type_is_error(ty: t) -> bool { (get(ty).flags & (has_ty_err as uint)) != 0 } +pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool { + tref.substs.self_ty.any(|&t| type_is_error(t)) || + tref.substs.tps.any(|&t| type_is_error(t)) +} + pub fn type_is_ty_var(ty: t) -> bool { match get(ty).sty { ty_infer(TyVar(_)) => true, @@ -1921,8 +1960,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { TC_OWNED_CLOSURE } - ty_trait(_, _, BoxTraitStore) | - ty_trait(_, _, BareTraitStore) => { + ty_trait(_, _, BoxTraitStore) => { TC_MANAGED } @@ -2581,17 +2619,6 @@ impl to_bytes::IterBytes for vstore { } } -impl to_bytes::IterBytes for TraitStore { - fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - match *self { - BareTraitStore => 0u8.iter_bytes(lsb0, f), - UniqTraitStore => 1u8.iter_bytes(lsb0, f), - BoxTraitStore => 2u8.iter_bytes(lsb0, f), - RegionTraitStore(ref r) => to_bytes::iter_bytes_2(&3u8, r, lsb0, f), - } - } -} - impl to_bytes::IterBytes for substs { fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_3(&self.self_r, @@ -2704,6 +2731,16 @@ impl to_bytes::IterBytes for sty { } } +pub fn node_id_to_trait_ref(cx: ctxt, id: ast::node_id) -> @ty::TraitRef { + match cx.trait_refs.find(&id) { + Some(&t) => t, + None => cx.sess.bug( + fmt!("node_id_to_trait_ref: no trait ref for node `%s`", + ast_map::node_id_to_str(cx.items, id, + cx.sess.parse_sess.interner))) + } +} + pub fn node_id_to_type(cx: ctxt, id: ast::node_id) -> t { //io::println(fmt!("%?/%?", id, cx.node_types.len())); match cx.node_types.find(&(id as uint)) { @@ -2726,6 +2763,16 @@ fn node_id_has_type_params(cx: ctxt, id: ast::node_id) -> bool { cx.node_type_substs.contains_key(&id) } +pub fn ty_fn_sig(fty: t) -> FnSig { + match get(fty).sty { + ty_bare_fn(ref f) => copy f.sig, + ty_closure(ref f) => copy f.sig, + ref s => { + fail!(fmt!("ty_fn_sig() called on non-fn type: %?", s)) + } + } +} + // Type accessors for substructures of types pub fn ty_fn_args(fty: t) -> ~[arg] { match get(fty).sty { @@ -3004,7 +3051,7 @@ pub fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map, // n.b.: When we encode impl methods, the bounds // that we encode include both the impl bounds // and then the method bounds themselves... - ty::lookup_item_type(tcx, did).bounds + ty::lookup_item_type(tcx, did).generics.bounds } typeck::method_param(typeck::method_param { trait_id: trt_id, @@ -3015,10 +3062,9 @@ pub fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map, // ...trait methods bounds, in contrast, include only the // method bounds, so we must preprend the tps from the // trait itself. This ought to be harmonized. - let trt_bounds = - ty::lookup_item_type(tcx, trt_id).bounds; + let trt_bounds = ty::lookup_trait_def(tcx, trt_id).generics.bounds; @(vec::append(/*bad*/copy *trt_bounds, - *ty::trait_methods(tcx, trt_id)[n_mth].tps)) + *ty::trait_method(tcx, trt_id, n_mth).generics.bounds)) } } } @@ -3203,10 +3249,8 @@ pub fn field_idx_strict(tcx: ty::ctxt, id: ast::ident, fields: &[field]) fields.map(|f| tcx.sess.str_of(f.ident)))); } -pub fn method_idx(id: ast::ident, meths: &[method]) -> Option { - let mut i = 0u; - for meths.each |m| { if m.ident == id { return Some(i); } i += 1u; } - return None; +pub fn method_idx(id: ast::ident, meths: &[@method]) -> Option { + vec::position(meths, |m| m.ident == id) } /// Returns a vector containing the indices of all type parameters that appear @@ -3469,6 +3513,11 @@ pub fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str { ty_sort_str(cx, values.expected), ty_sort_str(cx, values.found)) } + terr_traits(values) => { + fmt!("expected trait %s but found trait %s", + item_path_str(cx, values.expected), + item_path_str(cx, values.found)) + } terr_self_substs => { ~"inconsistent self substitution" // XXX this is more of a bug } @@ -3527,10 +3576,6 @@ pub fn def_has_ty_params(def: ast::def) -> bool { } } -pub fn store_trait_methods(cx: ctxt, id: ast::node_id, ms: @~[method]) { - cx.trait_method_cache.insert(ast_util::local_def(id), ms); -} - pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] { if is_local(id) { match cx.items.find(&id.node) { @@ -3550,11 +3595,11 @@ pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] { } pub fn trait_supertraits(cx: ctxt, - id: ast::def_id) - -> @~[InstantiatedTraitRef] { + id: ast::def_id) -> @~[@TraitRef] +{ // Check the cache. match cx.supertraits.find(&id) { - Some(&instantiated_trait_info) => { return instantiated_trait_info; } + Some(&trait_refs) => { return trait_refs; } None => {} // Continue. } @@ -3563,63 +3608,73 @@ pub fn trait_supertraits(cx: ctxt, assert!(!is_local(id)); // Get the supertraits out of the metadata and create the - // InstantiatedTraitRef for each. - let mut result = ~[]; - for csearch::get_supertraits(cx, id).each |trait_type| { - match get(*trait_type).sty { - ty_trait(def_id, ref substs, _) => { - result.push(InstantiatedTraitRef { - def_id: def_id, - tpt: ty_param_substs_and_ty { - substs: (/*bad*/copy *substs), - ty: *trait_type - } - }); - } - _ => cx.sess.bug(~"trait_supertraits: trait ref wasn't a trait") - } - } - - // Unwrap and return the result. - return @result; + // TraitRef for each. + let result = @csearch::get_supertraits(cx, id); + cx.supertraits.insert(id, result); + return result; } -pub fn trait_methods(cx: ctxt, id: ast::def_id) -> @~[method] { - match cx.trait_method_cache.find(&id) { - // Local traits are supposed to have been added explicitly. - Some(&ms) => ms, - _ => { - // If the lookup in trait_method_cache fails, assume that the trait - // method we're trying to look up is in a different crate, and look - // for it there. - assert!(id.crate != ast::local_crate); - let result = csearch::get_trait_methods(cx, id); +fn lookup_locally_or_in_crate_store( + descr: &str, + def_id: ast::def_id, + map: &mut HashMap, + load_external: &fn() -> V) -> V +{ + /*! + * + * Helper for looking things up in the various maps + * that are populated during typeck::collect (e.g., + * `cx.methods`, `cx.tcache`, etc). All of these share + * the pattern that if the id is local, it should have + * been loaded into the map by the `typeck::collect` phase. + * If the def-id is external, then we have to go consult + * the crate loading code (and cache the result for the future). + */ + + match map.find(&def_id) { + Some(&v) => { return v; } + None => { } + } - // Store the trait method in the local trait_method_cache so that - // future lookups succeed. - cx.trait_method_cache.insert(id, result); - result - } + if def_id.crate == ast::local_crate { + fail!(fmt!("No def'n found for %? in tcx.%s", + def_id, descr)); } + let v = load_external(); + map.insert(def_id, v); + return v; } -/* - Could this return a list of (def_id, substs) pairs? - */ -pub fn impl_traits(cx: ctxt, id: ast::def_id, store: TraitStore) -> ~[t] { - fn storeify(cx: ctxt, ty: t, store: TraitStore) -> t { - match ty::get(ty).sty { - ty::ty_trait(did, ref substs, trait_store) => { - if store == trait_store { - ty - } else { - mk_trait(cx, did, (/*bad*/copy *substs), store) - } - } - _ => cx.sess.bug(~"impl_traits: not a trait") +pub fn trait_method(cx: ctxt, trait_did: ast::def_id, idx: uint) -> @method { + let method_def_id = ty::trait_method_def_ids(cx, trait_did)[idx]; + ty::method(cx, method_def_id) +} + +pub fn trait_methods(cx: ctxt, trait_did: ast::def_id) -> @~[@method] { + match cx.trait_methods_cache.find(&trait_did) { + Some(&methods) => methods, + None => { + let def_ids = ty::trait_method_def_ids(cx, trait_did); + let methods = @def_ids.map(|d| ty::method(cx, *d)); + cx.trait_methods_cache.insert(trait_did, methods); + methods } } +} + +pub fn method(cx: ctxt, id: ast::def_id) -> @method { + lookup_locally_or_in_crate_store( + "methods", id, cx.methods, + || @csearch::get_method(cx, id)) +} + +pub fn trait_method_def_ids(cx: ctxt, id: ast::def_id) -> @~[def_id] { + lookup_locally_or_in_crate_store( + "methods", id, cx.trait_method_def_ids, + || @csearch::get_trait_method_def_ids(cx.cstore, id)) +} +pub fn impl_trait_refs(cx: ctxt, id: ast::def_id) -> ~[@TraitRef] { if id.crate == ast::local_crate { debug!("(impl_traits) searching for trait impl %?", id); match cx.items.find(&id.node) { @@ -3627,17 +3682,15 @@ pub fn impl_traits(cx: ctxt, id: ast::def_id, store: TraitStore) -> ~[t] { node: ast::item_impl(_, opt_trait, _, _), _}, _)) => { - - do opt_trait.map_default(~[]) |trait_ref| { - ~[storeify(cx, node_id_to_type(cx, trait_ref.ref_id), - store)] + match opt_trait { + Some(t) => ~[ty::node_id_to_trait_ref(cx, t.ref_id)], + None => ~[] } } _ => ~[] } } else { - vec::map(csearch::get_impl_traits(cx, id), - |x| storeify(cx, *x, store)) + csearch::get_impl_traits(cx, id) } } @@ -3906,18 +3959,25 @@ pub fn enum_variant_with_id(cx: ctxt, pub fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty { - match cx.tcache.find(&did) { - Some(&tpt) => { - // The item is in this crate. The caller should have added it to the - // type cache already - return tpt; - } - None => { - assert!(did.crate != ast::local_crate); - let tyt = csearch::get_type(cx, did); - cx.tcache.insert(did, tyt); - return tyt; - } + lookup_locally_or_in_crate_store( + "tcache", did, cx.tcache, + || csearch::get_type(cx, did)) +} + +/// Given the did of a trait, returns its canonical trait ref. +pub fn lookup_trait_def(cx: ctxt, did: ast::def_id) -> @ty::TraitDef { + match cx.trait_defs.find(&did) { + Some(&trait_def) => { + // The item is in this crate. The caller should have added it to the + // type cache already + return trait_def; + } + None => { + assert!(did.crate != ast::local_crate); + let trait_def = @csearch::get_trait_def(cx, did); + cx.trait_defs.insert(did, trait_def); + return trait_def; + } } } @@ -4204,9 +4264,6 @@ pub fn normalize_ty(cx: ctxt, t: t) -> t { t }, - ty_trait(did, ref substs, BareTraitStore) => - mk_trait(cx, did, copy *substs, BoxTraitStore), - _ => t }; @@ -4272,12 +4329,11 @@ pub fn determine_inherited_purity(parent_purity: ast::purity, // list. pub fn iter_bound_traits_and_supertraits(tcx: ctxt, bounds: param_bounds, - f: &fn(t) -> bool) { + f: &fn(&TraitRef) -> bool) { let mut fin = false; for bounds.each |bound| { - - let bound_trait_ty = match *bound { + let bound_trait_ref = match *bound { ty::bound_trait(bound_t) => bound_t, ty::bound_copy | ty::bound_owned | @@ -4286,39 +4342,38 @@ pub fn iter_bound_traits_and_supertraits(tcx: ctxt, } }; - let mut supertrait_map = HashMap::new(); + let mut supertrait_set = HashMap::new(); let mut seen_def_ids = ~[]; let mut i = 0; - let trait_ty_id = ty_to_def_id(bound_trait_ty).expect( - ~"iter_trait_ty_supertraits got a non-trait type"); - let mut trait_ty = bound_trait_ty; + let trait_ty_id = bound_trait_ref.def_id; + let mut trait_ref = bound_trait_ref; - debug!("iter_bound_traits_and_supertraits: trait_ty = %s", - ty_to_str(tcx, trait_ty)); + debug!("iter_bound_traits_and_supertraits: trait_ref = %s", + trait_ref_to_str(tcx, trait_ref)); // Add the given trait ty to the hash map - supertrait_map.insert(trait_ty_id, trait_ty); + supertrait_set.insert(trait_ty_id, ()); seen_def_ids.push(trait_ty_id); - if f(trait_ty) { + if f(trait_ref) { // Add all the supertraits to the hash map, // executing on each of them - while i < supertrait_map.len() && !fin { + while i < supertrait_set.len() && !fin { let init_trait_id = seen_def_ids[i]; i += 1; - // Add supertraits to supertrait_map - let supertraits = trait_supertraits(tcx, init_trait_id); - for supertraits.each |supertrait| { - let super_t = supertrait.tpt.ty; - let d_id = ty_to_def_id(super_t).expect("supertrait \ - should be a trait ty"); - if !supertrait_map.contains_key(&d_id) { - supertrait_map.insert(d_id, super_t); - trait_ty = super_t; + + // Add supertraits to supertrait_set + let supertrait_refs = trait_supertraits(tcx, init_trait_id); + for supertrait_refs.each |&supertrait_ref| { + let d_id = supertrait_ref.def_id; + if !supertrait_set.contains_key(&d_id) { + // FIXME(#5527) Could have same trait multiple times + supertrait_set.insert(d_id, ()); + trait_ref = supertrait_ref; seen_def_ids.push(d_id); } - debug!("A super_t = %s", ty_to_str(tcx, trait_ty)); - if !f(trait_ty) { + debug!("A super_t = %s", trait_ref_to_str(tcx, trait_ref)); + if !f(trait_ref) { fin = true; } } @@ -4355,6 +4410,14 @@ pub fn get_impl_id(tcx: ctxt, trait_id: def_id, self_ty: t) -> def_id { } } +pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) { + let ty_visitor_name = special_idents::ty_visitor; + assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name)); + let trait_ref = *tcx.intrinsic_traits.get(&ty_visitor_name); + (trait_ref, + mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore)) +} + // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 4b4cb8572529c..209091ecd6643 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -14,14 +14,14 @@ * is parameterized by an instance of `AstConv` and a `region_scope`. * * The parameterization of `ast_ty_to_ty()` is because it behaves - * somewhat differently during the collect and check phases, particularly - * with respect to looking up the types of top-level items. In the - * collect phase, the crate context is used as the `AstConv` instance; - * in this phase, the `get_item_ty()` function triggers a recursive call - * to `ty_of_item()` (note that `ast_ty_to_ty()` will detect recursive - * types and report an error). In the check phase, when the @FnCtxt is - * used as the `AstConv`, `get_item_ty()` just looks up the item type in - * `tcx.tcache`. + * somewhat differently during the collect and check phases, + * particularly with respect to looking up the types of top-level + * items. In the collect phase, the crate context is used as the + * `AstConv` instance; in this phase, the `get_item_ty()` function + * triggers a recursive call to `ty_of_item()` (note that + * `ast_ty_to_ty()` will detect recursive types and report an error). + * In the check phase, when the @FnCtxt is used as the `AstConv`, + * `get_item_ty()` just looks up the item type in `tcx.tcache`. * * The `region_scope` trait controls how region references are * handled. It has two methods which are used to resolve anonymous @@ -76,6 +76,7 @@ use util::common::indenter; pub trait AstConv { fn tcx(&self) -> ty::ctxt; fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty; + fn get_trait_def(&self, id: ast::def_id) -> @ty::TraitDef; // what type should we use when a type is omitted? fn ty_infer(&self, span: span) -> ty::t; @@ -129,62 +130,96 @@ pub fn ast_region_to_region( get_region_reporting_err(self.tcx(), span, opt_lifetime, res) } -pub fn ast_path_to_substs_and_ty( - self: &AC, - rscope: &RS, - did: ast::def_id, - path: @ast::path) - -> ty_param_substs_and_ty { - let tcx = self.tcx(); - let ty::ty_param_bounds_and_ty { - bounds: decl_bounds, - region_param: decl_rp, - ty: decl_ty - } = self.get_item_ty(did); +fn ast_path_substs( + self: &AC, + rscope: &RS, + def_id: ast::def_id, + decl_generics: &ty::Generics, + path: @ast::path) -> ty::substs +{ + /*! + * + * Given a path `path` that refers to an item `I` with the + * declared generics `decl_generics`, returns an appropriate + * set of substitutions for this particular reference to `I`. + */ - debug!("ast_path_to_substs_and_ty: did=%? decl_rp=%?", - did, decl_rp); + let tcx = self.tcx(); // If the type is parameterized by the self region, then replace self // region with the current anon region binding (in other words, // whatever & would get replaced with). - let self_r = match (decl_rp, path.rp) { - (None, None) => { + let self_r = match (&decl_generics.region_param, &path.rp) { + (&None, &None) => { None } - (None, Some(_)) => { + (&None, &Some(_)) => { tcx.sess.span_err( path.span, fmt!("no region bound is allowed on `%s`, \ which is not declared as containing region pointers", - ty::item_path_str(tcx, did))); + ty::item_path_str(tcx, def_id))); None } - (Some(_), None) => { + (&Some(_), &None) => { let res = rscope.anon_region(path.span); let r = get_region_reporting_err(self.tcx(), path.span, None, res); Some(r) } - (Some(_), Some(_)) => { + (&Some(_), &Some(_)) => { Some(ast_region_to_region(self, rscope, path.span, path.rp)) } }; // Convert the type parameters supplied by the user. - if !vec::same_length(*decl_bounds, path.types) { + if !vec::same_length(*decl_generics.bounds, path.types) { self.tcx().sess.span_fatal( path.span, fmt!("wrong number of type arguments: expected %u but found %u", - (*decl_bounds).len(), path.types.len())); + decl_generics.bounds.len(), path.types.len())); } let tps = path.types.map(|a_t| ast_ty_to_ty(self, rscope, *a_t)); - let substs = substs {self_r:self_r, self_ty:None, tps:tps}; - let ty = ty::subst(tcx, &substs, decl_ty); + substs {self_r:self_r, self_ty:None, tps:tps} +} +pub fn ast_path_to_substs_and_ty( + self: &AC, + rscope: &RS, + did: ast::def_id, + path: @ast::path) -> ty_param_substs_and_ty +{ + let tcx = self.tcx(); + let ty::ty_param_bounds_and_ty { + generics: generics, + ty: decl_ty + } = self.get_item_ty(did); + + let substs = ast_path_substs(self, rscope, did, &generics, path); + let ty = ty::subst(tcx, &substs, decl_ty); ty_param_substs_and_ty { substs: substs, ty: ty } } +pub fn ast_path_to_trait_ref( + self: &AC, + rscope: &RS, + trait_def_id: ast::def_id, + path: @ast::path) -> @ty::TraitRef +{ + let trait_def = + self.get_trait_def(trait_def_id); + let substs = + ast_path_substs( + self, rscope, + trait_def.trait_ref.def_id, &trait_def.generics, + path); + let trait_ref = + @ty::TraitRef {def_id: trait_def_id, + substs: substs}; + return trait_ref; +} + + pub fn ast_path_to_ty( self: &AC, rscope: &RS, @@ -243,36 +278,29 @@ pub fn ast_ty_to_ty( check_path_args(tcx, path, NO_TPS | NO_REGIONS); return ty::mk_estr(tcx, vst); } - Some(&ast::def_ty(type_def_id)) => { - let result = ast_path_to_substs_and_ty( - self, rscope, - type_def_id, path); - match ty::get(result.ty).sty { - ty::ty_trait(trait_def_id, ref substs, _) => { - let trait_store = match vst { - ty::vstore_box => ty::BoxTraitStore, - ty::vstore_uniq => ty::UniqTraitStore, - ty::vstore_slice(r) => { - ty::RegionTraitStore(r) - } - ty::vstore_fixed(*) => { - tcx.sess.span_err( - path.span, - ~"@trait, ~trait or &trait \ - are the only supported \ - forms of casting-to-\ - trait"); - ty::BoxTraitStore - } - }; - return ty::mk_trait(tcx, - trait_def_id, - /*bad*/copy *substs, - trait_store); - + Some(&ast::def_trait(trait_def_id)) => { + let result = ast_path_to_trait_ref( + self, rscope, trait_def_id, path); + let trait_store = match vst { + ty::vstore_box => ty::BoxTraitStore, + ty::vstore_uniq => ty::UniqTraitStore, + ty::vstore_slice(r) => { + ty::RegionTraitStore(r) + } + ty::vstore_fixed(*) => { + tcx.sess.span_err( + path.span, + ~"@trait, ~trait or &trait \ + are the only supported \ + forms of casting-to-\ + trait"); + ty::BoxTraitStore } - _ => {} - } + }; + return ty::mk_trait(tcx, + result.def_id, + copy result.substs, + trait_store); } _ => {} } @@ -372,6 +400,15 @@ pub fn ast_ty_to_ty( Some(&d) => d }; match a_def { + ast::def_trait(_) => { + let path_str = path_to_str(path, tcx.sess.intr()); + tcx.sess.span_err( + ast_ty.span, + fmt!("reference to trait `%s` where a type is expected; \ + try `@%s`, `~%s`, or `&%s`", + path_str, path_str, path_str, path_str)); + ty::mk_err(tcx) + } ast::def_ty(did) | ast::def_struct(did) => { ast_path_to_ty(self, rscope, did, path).ty } @@ -540,6 +577,29 @@ pub fn bound_lifetimes( bound_lifetime_names } +struct SelfInfo { + untransformed_self_ty: ty::t, + self_transform: ast::self_ty +} + +pub fn ty_of_method( + self: &AC, + rscope: &RS, + purity: ast::purity, + lifetimes: &OptVec, + untransformed_self_ty: ty::t, + self_transform: ast::self_ty, + decl: &ast::fn_decl) -> (Option, ty::BareFnTy) +{ + let self_info = SelfInfo { + untransformed_self_ty: untransformed_self_ty, + self_transform: self_transform + }; + let (a, b) = ty_of_method_or_bare_fn( + self, rscope, purity, AbiSet::Rust(), lifetimes, Some(&self_info), decl); + (a.get(), b) +} + pub fn ty_of_bare_fn( self: &AC, rscope: &RS, @@ -547,6 +607,20 @@ pub fn ty_of_bare_fn( abi: AbiSet, lifetimes: &OptVec, decl: &ast::fn_decl) -> ty::BareFnTy +{ + let (_, b) = ty_of_method_or_bare_fn( + self, rscope, purity, abi, lifetimes, None, decl); + b +} + +fn ty_of_method_or_bare_fn( + self: &AC, + rscope: &RS, + purity: ast::purity, + abi: AbiSet, + lifetimes: &OptVec, + opt_self_info: Option<&SelfInfo>, + decl: &ast::fn_decl) -> (Option>, ty::BareFnTy) { debug!("ty_of_bare_fn"); @@ -555,18 +629,56 @@ pub fn ty_of_bare_fn( let bound_lifetime_names = bound_lifetimes(self, lifetimes); let rb = in_binding_rscope(rscope, RegionParamNames(copy bound_lifetime_names)); + let opt_transformed_self_ty = opt_self_info.map(|&self_info| { + transform_self_ty(self, &rb, self_info) + }); + let input_tys = decl.inputs.map(|a| ty_of_arg(self, &rb, *a, None)); + let output_ty = match decl.output.node { ast::ty_infer => self.ty_infer(decl.output.span), _ => ast_ty_to_ty(self, &rb, decl.output) }; - ty::BareFnTy { - purity: purity, - abis: abi, - sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names, - inputs: input_tys, - output: output_ty} + return (opt_transformed_self_ty, + ty::BareFnTy { + purity: purity, + abis: abi, + sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names, + inputs: input_tys, + output: output_ty} + }); + + fn transform_self_ty( + self: &AC, + rscope: &RS, + self_info: &SelfInfo) -> Option + { + match self_info.self_transform.node { + ast::sty_static => None, + ast::sty_value => { + Some(self_info.untransformed_self_ty) + } + ast::sty_region(lifetime, mutability) => { + let region = + ast_region_to_region(self, rscope, + self_info.self_transform.span, + lifetime); + Some(ty::mk_rptr(self.tcx(), region, + ty::mt {ty: self_info.untransformed_self_ty, + mutbl: mutability})) + } + ast::sty_box(mutability) => { + Some(ty::mk_box(self.tcx(), + ty::mt {ty: self_info.untransformed_self_ty, + mutbl: mutability})) + } + ast::sty_uniq(mutability) => { + Some(ty::mk_uniq(self.tcx(), + ty::mt {ty: self_info.untransformed_self_ty, + mutbl: mutability})) + } + } } } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index f2d0ef22970b4..605caba74a380 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -135,7 +135,7 @@ pub fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, ty::enum_variant_with_id(tcx, enm, var); let var_tpt = ty::lookup_item_type(tcx, var); vinfo.args.map(|t| { - if var_tpt.bounds.len() == expected_substs.tps.len() { + if var_tpt.generics.bounds.len() == expected_substs.tps.len() { ty::subst(tcx, expected_substs, *t) } else { diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 3b01f0e839ab9..fa3cb43d9abe0 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -92,6 +92,7 @@ use middle::typeck::check; use middle::typeck::infer; use middle::typeck::{method_map_entry, method_origin, method_param}; use middle::typeck::{method_self, method_static, method_trait, method_super}; +use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; use util::common::indenter; use util::ppaux::expr_repr; @@ -99,6 +100,7 @@ use core::hashmap::HashSet; use core::result; use core::uint; use core::vec; +use std::list::Nil; use syntax::ast::{def_id, sty_value, sty_region, sty_box}; use syntax::ast::{sty_uniq, sty_static, node_id, by_copy, by_ref}; use syntax::ast::{m_const, m_mutbl, m_imm}; @@ -121,7 +123,7 @@ pub fn lookup( fcx: @mut FnCtxt, // In a call `a.b::(...)`: - expr: @ast::expr, // The expression `a.b`. + expr: @ast::expr, // The expression `a.b(...)`. self_expr: @ast::expr, // The expression `a`. callee_id: node_id, // Where to store `a.b`'s type m_name: ast::ident, // The ident `b`. @@ -174,13 +176,7 @@ pub struct LookupContext<'self> { pub struct Candidate { rcvr_ty: ty::t, rcvr_substs: ty::substs, - explicit_self: ast::self_ty_, - - // FIXME #3446---these two fields should be easily derived from - // origin, yet are not - num_method_tps: uint, - self_mode: ast::rmode, - + method_ty: @ty::method, origin: method_origin, } @@ -386,7 +382,7 @@ pub impl<'self> LookupContext<'self> { let bounds = tcx.ty_param_bounds.get(¶m_ty.def_id.node); for bounds.each |bound| { - let bound_trait_ty = match *bound { + let bound_trait_ref = match *bound { ty::bound_trait(bound_t) => bound_t, ty::bound_copy | ty::bound_owned | @@ -395,22 +391,10 @@ pub impl<'self> LookupContext<'self> { } }; - - let bound_substs = match ty::get(bound_trait_ty).sty { - ty::ty_trait(_, ref substs, _) => (/*bad*/copy *substs), - _ => { - self.bug(fmt!("add_candidates_from_param: \ - non-trait bound %s", - self.ty_to_str(bound_trait_ty))); - } - }; - - // Loop over the trait and all of its supertraits. let mut worklist = ~[]; - let init_trait_ty = bound_trait_ty; - let init_substs = bound_substs; + let init_trait_ref = bound_trait_ref; // Replace any appearance of `self` with the type of the // generic parameter itself. Note that this is the only @@ -421,29 +405,26 @@ pub impl<'self> LookupContext<'self> { // to self are not permitted). let init_substs = substs { self_ty: Some(rcvr_ty), - ..init_substs + ..copy bound_trait_ref.substs }; - worklist.push((init_trait_ty, init_substs)); + worklist.push((init_trait_ref.def_id, init_substs)); let mut i = 0; while i < worklist.len() { - let (init_trait_ty, init_substs) = /*bad*/copy worklist[i]; + let (init_trait_id, init_substs) = /*bad*/copy worklist[i]; i += 1; - let init_trait_id = ty::ty_to_def_id(init_trait_ty).get(); - // Add all the supertraits of this trait to the worklist. - let supertraits = ty::trait_supertraits(tcx, - init_trait_id); - for supertraits.each |supertrait| { + let supertraits = ty::trait_supertraits(tcx, init_trait_id); + for supertraits.each |supertrait_ref| { debug!("adding supertrait: %?", - supertrait.def_id); + supertrait_ref.def_id); - let new_substs = ty::subst_substs( + let new_substs = ty::subst_in_substs( tcx, - &supertrait.tpt.substs, - &init_substs); + &init_substs, + &supertrait_ref.substs); // Again replacing the self type let new_substs = substs { @@ -451,7 +432,7 @@ pub impl<'self> LookupContext<'self> { ..new_substs }; - worklist.push((supertrait.tpt.ty, new_substs)); + worklist.push((supertrait_ref.def_id, new_substs)); } @@ -472,7 +453,7 @@ pub impl<'self> LookupContext<'self> { } } }; - let method = &trait_methods[pos]; + let method = trait_methods[pos]; let (rcvr_ty, rcvr_substs) = self.create_rcvr_ty_and_substs_for_method( @@ -484,9 +465,7 @@ pub impl<'self> LookupContext<'self> { let cand = Candidate { rcvr_ty: rcvr_ty, rcvr_substs: rcvr_substs, - explicit_self: method.self_ty, - num_method_tps: method.tps.len(), - self_mode: get_mode_from_self_type(method.self_ty), + method_ty: method, origin: method_param( method_param { trait_id: init_trait_id, @@ -518,7 +497,7 @@ pub impl<'self> LookupContext<'self> { Some(i) => i, None => { return; } // no method with the right name }; - let method = &ms[index]; + let method = ms[index]; /* FIXME(#3157) we should transform the vstore in accordance with the self type @@ -552,9 +531,7 @@ pub impl<'self> LookupContext<'self> { self.inherent_candidates.push(Candidate { rcvr_ty: rcvr_ty, rcvr_substs: rcvr_substs, - explicit_self: method.self_ty, - num_method_tps: method.tps.len(), - self_mode: get_mode_from_self_type(method.self_ty), + method_ty: method, origin: method_trait(did, index, store) }); } @@ -563,63 +540,65 @@ pub impl<'self> LookupContext<'self> { self_ty: ty::t, did: def_id, substs: &ty::substs) { + struct MethodInfo { + method_ty: @ty::method, + trait_def_id: ast::def_id, + index: uint + } + let tcx = self.tcx(); // First, try self methods - let mut method = None; + let mut method_info: Option = None; let methods = ty::trait_methods(tcx, did); - let mut index = None; - let mut trait_did = None; match vec::position(*methods, |m| m.ident == self.m_name) { Some(i) => { - index = Some(i); - trait_did = Some(did); - method = Some((methods[i].self_ty, methods[i].tps.len())); + method_info = Some(MethodInfo { + method_ty: methods[i], + index: i, + trait_def_id: did + }); } None => () } // No method found yet? Check each supertrait - if method.is_none() { + if method_info.is_none() { for ty::trait_supertraits(tcx, did).each() |trait_ref| { let supertrait_methods = ty::trait_methods(tcx, trait_ref.def_id); match vec::position(*supertrait_methods, |m| m.ident == self.m_name) { Some(i) => { - index = Some(i); - trait_did = Some(trait_ref.def_id); - method = Some((supertrait_methods[i].self_ty, - supertrait_methods[i].tps.len())); + method_info = Some(MethodInfo { + method_ty: supertrait_methods[i], + index: i, + trait_def_id: trait_ref.def_id + }); break; } None => () } } } - match (method, index, trait_did) { - (Some((method_self_ty, method_num_tps)), - Some(index), Some(trait_did)) => { - + match method_info { + Some(ref info) => { // We've found a method -- return it - let rcvr_substs = substs { self_ty: Some(self_ty), + let rcvr_substs = substs {self_ty: Some(self_ty), ..copy *substs }; let (rcvr_ty, rcvr_substs) = self.create_rcvr_ty_and_substs_for_method( - method_self_ty, + info.method_ty.self_ty, self_ty, rcvr_substs, TransformTypeNormally); - let origin = if trait_did == did { - method_self(trait_did, index) - } - else { - method_super(trait_did, index) + let origin = if did == info.trait_def_id { + method_self(info.trait_def_id, info.index) + } else { + method_super(info.trait_def_id, info.index) }; self.inherent_candidates.push(Candidate { rcvr_ty: rcvr_ty, rcvr_substs: rcvr_substs, - explicit_self: method_self_ty, - num_method_tps: method_num_tps, - self_mode: get_mode_from_self_type(method_self_ty), + method_ty: info.method_ty, origin: origin }); } @@ -651,7 +630,7 @@ pub impl<'self> LookupContext<'self> { } }; - let method = &impl_info.methods[idx]; + let method = ty::method(self.tcx(), impl_info.methods[idx].did); // determine the `self` of the impl with fresh // variables for each parameter: @@ -667,7 +646,7 @@ pub impl<'self> LookupContext<'self> { let (impl_ty, impl_substs) = self.create_rcvr_ty_and_substs_for_method( - method.self_type, + method.self_ty, impl_ty, impl_substs, TransformTypeNormally); @@ -675,10 +654,8 @@ pub impl<'self> LookupContext<'self> { candidates.push(Candidate { rcvr_ty: impl_ty, rcvr_substs: impl_substs, - explicit_self: method.self_type, - num_method_tps: method.n_tps, - self_mode: get_mode_from_self_type(method.self_type), - origin: method_static(method.did) + method_ty: method, + origin: method_static(method.def_id) }); } @@ -699,6 +676,9 @@ pub impl<'self> LookupContext<'self> { debug!("(pushing candidates from provided methods) adding \ candidate"); + let method = ty::method(self.tcx(), + provided_method_info.method_info.did); + // XXX: Needs to support generics. let dummy_substs = substs { self_r: None, @@ -707,7 +687,7 @@ pub impl<'self> LookupContext<'self> { }; let (impl_ty, impl_substs) = self.create_rcvr_ty_and_substs_for_method( - provided_method_info.method_info.self_type, + method.self_ty, self_ty, dummy_substs, TransformTypeNormally); @@ -715,10 +695,7 @@ pub impl<'self> LookupContext<'self> { candidates.push(Candidate { rcvr_ty: impl_ty, rcvr_substs: impl_substs, - explicit_self: provided_method_info.method_info.self_type, - num_method_tps: provided_method_info.method_info.n_tps, - self_mode: get_mode_from_self_type( - provided_method_info.method_info.self_type), + method_ty: method, origin: method_static(provided_method_info.method_info.did) }); } @@ -1092,10 +1069,16 @@ pub impl<'self> LookupContext<'self> { fn confirm_candidate(&self, self_ty: ty::t, candidate: &Candidate) - -> method_map_entry { + -> method_map_entry + { let tcx = self.tcx(); let fty = self.fn_ty_from_origin(&candidate.origin); + debug!("confirm_candidate(expr=%s, candidate=%s, fty=%s)", + expr_repr(tcx, self.expr), + self.cand_to_str(candidate), + self.ty_to_str(fty)); + self.enforce_trait_instance_limitations(fty, candidate); self.enforce_drop_trait_limitations(candidate); @@ -1118,20 +1101,21 @@ pub impl<'self> LookupContext<'self> { // If they were not explicitly supplied, just construct fresh // type variables. let num_supplied_tps = self.supplied_tps.len(); + let num_method_tps = candidate.method_ty.generics.bounds.len(); let m_substs = { if num_supplied_tps == 0u { - self.fcx.infcx().next_ty_vars(candidate.num_method_tps) - } else if candidate.num_method_tps == 0u { + self.fcx.infcx().next_ty_vars(num_method_tps) + } else if num_method_tps == 0u { tcx.sess.span_err( self.expr.span, ~"this method does not take type parameters"); - self.fcx.infcx().next_ty_vars(candidate.num_method_tps) - } else if num_supplied_tps != candidate.num_method_tps { + self.fcx.infcx().next_ty_vars(num_method_tps) + } else if num_supplied_tps != num_method_tps { tcx.sess.span_err( self.expr.span, ~"incorrect number of type \ parameters given for this method"); - self.fcx.infcx().next_ty_vars(candidate.num_method_tps) + self.fcx.infcx().next_ty_vars(num_method_tps) } else { self.supplied_tps.to_vec() } @@ -1145,13 +1129,41 @@ pub impl<'self> LookupContext<'self> { ../*bad*/copy candidate.rcvr_substs }; - self.fcx.write_ty_substs(self.callee_id, fty, all_substs); + // Compute the method type with type parameters substituted + debug!("fty=%s all_substs=%s", + self.ty_to_str(fty), + ty::substs_to_str(tcx, &all_substs)); + let fty = ty::subst(tcx, &all_substs, fty); + debug!("after subst, fty=%s", self.ty_to_str(fty)); + + // Replace any bound regions that appear in the function + // signature with region variables + let bare_fn_ty = match ty::get(fty).sty { + ty::ty_bare_fn(ref f) => copy *f, + ref s => { + tcx.sess.span_bug( + self.expr.span, + fmt!("Invoking method with non-bare-fn ty: %?", s)); + } + }; + let (_, _, fn_sig) = + replace_bound_regions_in_fn_sig( + tcx, @Nil, None, &bare_fn_ty.sig, + |_br| self.fcx.infcx().next_region_var( + self.expr.span, self.expr.id)); + let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {sig: fn_sig, ..bare_fn_ty}); + debug!("after replacing bound regions, fty=%s", self.ty_to_str(fty)); + + let self_mode = get_mode_from_self_type(candidate.method_ty.self_ty); + + self.fcx.write_ty(self.callee_id, fty); + self.fcx.write_substs(self.callee_id, all_substs); method_map_entry { self_arg: arg { - mode: ast::expl(candidate.self_mode), + mode: ast::expl(self_mode), ty: candidate.rcvr_ty, }, - explicit_self: candidate.explicit_self, + explicit_self: candidate.method_ty.self_ty, origin: candidate.origin, } } @@ -1183,7 +1195,7 @@ pub impl<'self> LookupContext<'self> { self-type through a boxed trait"); } - if candidate.num_method_tps > 0 { + if candidate.method_ty.generics.bounds.len() > 0 { self.tcx().sess.span_err( self.expr.span, ~"cannot call a generic method through a boxed trait"); @@ -1300,10 +1312,9 @@ pub impl<'self> LookupContext<'self> { } fn cand_to_str(&self, cand: &Candidate) -> ~str { - fmt!("Candidate(rcvr_ty=%s, rcvr_substs=%s, self_mode=%?, origin=%?)", + fmt!("Candidate(rcvr_ty=%s, rcvr_substs=%s, origin=%?)", self.ty_to_str(cand.rcvr_ty), ty::substs_to_str(self.tcx(), &cand.rcvr_substs), - cand.self_mode, cand.origin) } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index eba207f978b6e..c3ec2d14d83d0 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -610,7 +610,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { } else { for m.items.each |item| { let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id)); - if !tpt.bounds.is_empty() { + if !tpt.generics.bounds.is_empty() { ccx.tcx.sess.span_err( item.span, fmt!("foreign items may not have type parameters")); @@ -629,6 +629,10 @@ impl AstConv for FnCtxt { ty::lookup_item_type(self.tcx(), id) } + fn get_trait_def(&self, id: ast::def_id) -> @ty::TraitDef { + ty::lookup_trait_def(self.tcx(), id) + } + fn ty_infer(&self, _span: span) -> ty::t { self.infcx().next_ty_var() } @@ -1064,7 +1068,7 @@ pub fn impl_self_ty(vcx: &VtableContext, let (n_tps, region_param, raw_ty) = { let ity = ty::lookup_item_type(tcx, did); - (vec::len(*ity.bounds), ity.region_param, ity.ty) + (ity.generics.bounds.len(), ity.generics.region_param, ity.ty) }; let self_r = if region_param.is_some() { @@ -1122,103 +1126,84 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, unifier: &fn()) { debug!(">> typechecking %s", fcx.expr_to_str(expr)); - // A generic function to factor out common logic from call and - // overloaded operations - fn check_call_inner( + fn check_method_argument_types( fcx: @mut FnCtxt, sp: span, - call_expr_id: ast::node_id, - in_fty: ty::t, + method_fn_ty: ty::t, callee_expr: @ast::expr, args: &[@ast::expr], sugar: ast::CallSugar, deref_args: DerefArgs) -> ty::t { - let tcx = fcx.ccx.tcx; - - // Replace all region parameters in the arguments and return - // type with fresh region variables. - - debug!("check_call_inner: before universal quant., in_fty=%s", - fcx.infcx().ty_to_str(in_fty)); - - let formal_tys; - - // FIXME(#3678) For now, do not permit calls to C abi functions. - match structure_of(fcx, sp, in_fty) { - ty::ty_bare_fn(ty::BareFnTy {abis, _}) => { - if !abis.is_rust() { - tcx.sess.span_err( + if ty::type_is_error(method_fn_ty) { + let err_inputs = err_args(fcx.tcx(), args.len()); + check_argument_types(fcx, sp, err_inputs, callee_expr, + args, sugar, deref_args); + method_fn_ty + } else { + match ty::get(method_fn_ty).sty { + ty::ty_bare_fn(ref fty) => { + check_argument_types(fcx, sp, fty.sig.inputs, callee_expr, + args, sugar, deref_args); + fty.sig.output + } + _ => { + fcx.tcx().sess.span_bug( sp, - fmt!("Calls to C ABI functions are not (yet) \ - supported; be patient, dear user")); + fmt!("Method without bare fn type")); } } - _ => {} } + } - // This is subtle: we expect `fty` to be a function type, which - // normally introduce a level of binding. In this case, we want to - // process the types bound by the function but not by any nested - // functions. Therefore, we match one level of structure. - let ret_ty = match structure_of(fcx, sp, in_fty) { - ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) | - ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => { - let (_, _, sig) = - replace_bound_regions_in_fn_sig( - tcx, @Nil, None, sig, - |_br| fcx.infcx().next_region_var( - sp, call_expr_id)); - - let supplied_arg_count = args.len(); - - // Grab the argument types, supplying fresh type variables - // if the wrong number of arguments were supplied - let expected_arg_count = sig.inputs.len(); - formal_tys = if expected_arg_count == supplied_arg_count { - sig.inputs.map(|a| a.ty) - } else { - let suffix = match sugar { - ast::NoSugar => "", - ast::DoSugar => " (including the closure passed by \ - the `do` keyword)", - ast::ForSugar => " (including the closure passed by \ - the `for` keyword)" - }; - let msg = fmt!("this function takes %u parameter%s but \ - %u parameter%s supplied%s", - expected_arg_count, - if expected_arg_count == 1 {""} - else {"s"}, - supplied_arg_count, - if supplied_arg_count == 1 {" was"} - else {"s were"}, - suffix); - - tcx.sess.span_err(sp, msg); - - vec::from_fn(supplied_arg_count, |_| ty::mk_err(tcx)) - }; - - sig.output - } + fn check_argument_types( + fcx: @mut FnCtxt, + sp: span, + fn_inputs: &[ty::arg], + callee_expr: @ast::expr, + args: &[@ast::expr], + sugar: ast::CallSugar, + deref_args: DerefArgs) + { + /*! + * + * Generic function that factors out common logic from + * function calls, method calls and overloaded operators. + */ - _ => { - fcx.type_error_message(sp, |actual| { - fmt!("expected function or foreign function but \ - found `%s`", actual) }, in_fty, None); + let tcx = fcx.ccx.tcx; - // check each arg against "error", in order to set up - // all the node type bindings - formal_tys = args.map(|_x| ty::mk_err(tcx)); - ty::mk_err(tcx) - } + // Grab the argument types, supplying fresh type variables + // if the wrong number of arguments were supplied + let supplied_arg_count = args.len(); + let expected_arg_count = fn_inputs.len(); + let formal_tys = if expected_arg_count == supplied_arg_count { + fn_inputs.map(|a| a.ty) + } else { + let suffix = match sugar { + ast::NoSugar => "", + ast::DoSugar => " (including the closure passed by \ + the `do` keyword)", + ast::ForSugar => " (including the closure passed by \ + the `for` keyword)" + }; + let msg = fmt!("this function takes %u parameter%s but \ + %u parameter%s supplied%s", + expected_arg_count, + if expected_arg_count == 1 {""} + else {"s"}, + supplied_arg_count, + if supplied_arg_count == 1 {" was"} + else {"s were"}, + suffix); + + tcx.sess.span_err(sp, msg); + + vec::from_elem(supplied_arg_count, ty::mk_err(tcx)) }; - debug!("check_call_inner: after universal quant., \ - formal_tys=%? ret_ty=%s", - formal_tys.map(|t| fcx.infcx().ty_to_str(*t)), - fcx.infcx().ty_to_str(ret_ty)); + debug!("check_argument_types: formal_tys=%?", + formal_tys.map(|t| fcx.infcx().ty_to_str(*t))); // Check the arguments. // We do this in a pretty awful way: first we typecheck any arguments @@ -1268,8 +1253,11 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } } + } - ret_ty + fn err_args(tcx: ty::ctxt, len: uint) -> ~[ty::arg] { + vec::from_fn(len, |_| ty::arg {mode: ast::expl(ast::by_copy), + ty: ty::mk_err(tcx)}) } // A generic function for checking assignment expressions @@ -1284,43 +1272,63 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // The callee checks for bot / err, we don't need to } - // A generic function for doing all of the checking for call or - // method expressions - fn check_call_or_method(fcx: @mut FnCtxt, - sp: span, - call_expr_id: ast::node_id, - fn_ty: ty::t, - expr: @ast::expr, - args: &[@ast::expr], - sugar: ast::CallSugar) - { - - // Call the generic checker. - let ret_ty = check_call_inner(fcx, sp, call_expr_id, - fn_ty, expr, args, sugar, - DontDerefArgs); - // Pull the return type out of the type of the function. - fcx.write_ty(call_expr_id, ret_ty); - // Callee checks for bot and err, no need for that - } - // A generic function for doing all of the checking for call expressions fn check_call(fcx: @mut FnCtxt, - sp: span, - call_expr_id: ast::node_id, + call_expr: @ast::expr, f: @ast::expr, args: &[@ast::expr], sugar: ast::CallSugar) { // Index expressions need to be handled separately, to inform them // that they appear in call position. - let mut _bot = check_expr(fcx, f); - check_call_or_method(fcx, - sp, - call_expr_id, - fcx.expr_ty(f), - f, - args, - sugar) + check_expr(fcx, f); + + + // Extract the function signature from `in_fty`. + let fn_ty = fcx.expr_ty(f); + let fn_sty = structure_of(fcx, f.span, fn_ty); + + // FIXME(#3678) For now, do not permit calls to C abi functions. + match fn_sty { + ty::ty_bare_fn(ty::BareFnTy {abis, _}) => { + if !abis.is_rust() { + fcx.tcx().sess.span_err( + call_expr.span, + fmt!("Calls to C ABI functions are not (yet) \ + supported; be patient, dear user")); + } + } + _ => {} + } + + let fn_sig = match fn_sty { + ty::ty_bare_fn(ty::BareFnTy {sig: sig, _}) | + ty::ty_closure(ty::ClosureTy {sig: sig, _}) => sig, + _ => { + fcx.type_error_message(call_expr.span, |actual| { + fmt!("expected function but \ + found `%s`", actual) }, fn_ty, None); + + // check each arg against "error", in order to set up + // all the node type bindings + FnSig {bound_lifetime_names: opt_vec::Empty, + inputs: err_args(fcx.tcx(), args.len()), + output: ty::mk_err(fcx.tcx())} + } + }; + + // Replace any bound regions that appear in the function + // signature with region variables + let (_, _, fn_sig) = + replace_bound_regions_in_fn_sig( + fcx.tcx(), @Nil, None, &fn_sig, + |_br| fcx.infcx().next_region_var(call_expr.span, call_expr.id)); + + // Call the generic checker. + check_argument_types(fcx, call_expr.span, fn_sig.inputs, f, + args, sugar, DontDerefArgs); + + // Pull the return type out of the type of the function. + fcx.write_ty(call_expr.id, fn_sig.output); } // Checks a method call. @@ -1332,6 +1340,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, tps: &[@ast::Ty], sugar: ast::CallSugar) { check_expr(fcx, rcvr); + // no need to check for bot/err -- callee does that let expr_t = structurally_resolved_type(fcx, expr.span, @@ -1369,13 +1378,14 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } - check_call_or_method(fcx, - expr.span, - expr.id, - fcx.node_ty(expr.callee_id), - expr, - args, - sugar) + // Call the generic checker. + let fn_ty = fcx.node_ty(expr.callee_id); + let ret_ty = check_method_argument_types(fcx, expr.span, + fn_ty, expr, args, sugar, + DontDerefArgs); + + // Pull the return type out of the type of the function. + fcx.write_ty(expr.id, ret_ty); } // A generic function for checking the then and else in an if @@ -1423,10 +1433,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let method_ty = fcx.node_ty(op_ex.callee_id); let method_map = fcx.inh.method_map; method_map.insert(op_ex.id, *origin); - check_call_inner(fcx, op_ex.span, - op_ex.id, method_ty, - op_ex, args, - ast::NoSugar, deref_args) + check_method_argument_types(fcx, op_ex.span, + method_ty, op_ex, args, + ast::NoSugar, deref_args) } _ => { let tcx = fcx.tcx(); @@ -1434,9 +1443,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Check the args anyway // so we get all the error messages let expected_ty = ty::mk_err(tcx); - check_call_inner(fcx, op_ex.span, op_ex.id, - expected_ty, op_ex, args, - ast::NoSugar, deref_args); + check_method_argument_types(fcx, op_ex.span, + expected_ty, op_ex, args, + ast::NoSugar, deref_args); ty::mk_err(tcx) } } @@ -1884,8 +1893,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } else { let item_type = ty::lookup_item_type(tcx, class_id); - type_parameter_count = (*item_type.bounds).len(); - region_parameterized = item_type.region_param; + type_parameter_count = item_type.generics.bounds.len(); + region_parameterized = item_type.generics.region_param; raw_type = item_type.ty; } @@ -1972,8 +1981,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } else { let item_type = ty::lookup_item_type(tcx, enum_id); - type_parameter_count = (*item_type.bounds).len(); - region_parameterized = item_type.region_param; + type_parameter_count = item_type.generics.bounds.len(); + region_parameterized = item_type.generics.region_param; raw_type = item_type.ty; } @@ -2121,12 +2130,12 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, match expr.node { ast::expr_vstore(ev, vst) => { let typ = match ev.node { - ast::expr_lit(@codemap::spanned { node: ast::lit_str(s), _ }) => { - let tt = ast_expr_vstore_to_vstore(fcx, ev, s.len(), vst); + ast::expr_lit(@codemap::spanned { node: ast::lit_str(_), _ }) => { + let tt = ast_expr_vstore_to_vstore(fcx, ev, vst); ty::mk_estr(tcx, tt) } ast::expr_vec(ref args, mutbl) => { - let tt = ast_expr_vstore_to_vstore(fcx, ev, args.len(), vst); + let tt = ast_expr_vstore_to_vstore(fcx, ev, vst); let mutability; let mut any_error = false; let mut any_bot = false; @@ -2158,9 +2167,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } ast::expr_repeat(element, count_expr, mutbl) => { - let count = ty::eval_repeat_count(tcx, count_expr); + let _ = ty::eval_repeat_count(tcx, count_expr); check_expr_with_hint(fcx, count_expr, ty::mk_uint(tcx)); - let tt = ast_expr_vstore_to_vstore(fcx, ev, count, vst); + let tt = ast_expr_vstore_to_vstore(fcx, ev, vst); let mutability = match vst { ast::expr_vstore_mut_box | ast::expr_vstore_mut_slice => { ast::m_mutbl @@ -2546,7 +2555,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fcx.write_ty(id, fcx.node_ty(b.node.id)); } ast::expr_call(f, ref args, sugar) => { - check_call(fcx, expr.span, expr.id, f, *args, sugar); + check_call(fcx, expr, f, *args, sugar); let f_ty = fcx.expr_ty(f); let (args_bot, args_err) = args.foldl((false, false), |&(rest_bot, rest_err), a| { @@ -3143,8 +3152,10 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, ast::def_fn(_, ast::extern_fn) => { // extern functions are just u8 pointers return ty_param_bounds_and_ty { - bounds: @~[], - region_param: None, + generics: ty::Generics { + bounds: @~[], + region_param: None + }, ty: ty::mk_ptr( fcx.ccx.tcx, ty::mt { @@ -3169,7 +3180,10 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, ast::def_upvar(_, inner, _, _) => { return ty_param_bounds_and_ty_for_def(fcx, sp, *inner); } - ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty_param(*)=> { + ast::def_trait(_) | + ast::def_ty(_) | + ast::def_prim_ty(_) | + ast::def_ty_param(*)=> { fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found type"); } ast::def_mod(*) | ast::def_foreign_mod(*) => { @@ -3204,14 +3218,18 @@ pub fn instantiate_path(fcx: @mut FnCtxt, region_lb: ty::Region) { debug!(">>> instantiate_path"); - let ty_param_count = vec::len(*tpt.bounds); + let ty_param_count = tpt.generics.bounds.len(); let ty_substs_len = vec::len(pth.types); + debug!("ty_param_count=%? ty_substs_len=%?", + ty_param_count, + ty_substs_len); + // determine the region bound, using the value given by the user // (if any) and otherwise using a fresh region variable let self_r = match pth.rp { Some(_) => { // user supplied a lifetime parameter... - match tpt.region_param { + match tpt.generics.region_param { None => { // ...but the type is not lifetime parameterized! fcx.ccx.tcx.sess.span_err (span, ~"this item is not region-parameterized"); @@ -3224,7 +3242,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt, } None => { // no lifetime parameter supplied, insert default fcx.region_var_if_parameterized( - tpt.region_param, span, region_lb) + tpt.generics.region_param, span, region_lb) } }; @@ -3302,7 +3320,6 @@ pub fn type_is_c_like_enum(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool { pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt, e: @ast::expr, - _n: uint, v: ast::expr_vstore) -> ty::vstore { match v { @@ -3423,28 +3440,13 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { } ~"visit_tydesc" => { let tydesc_name = special_idents::tydesc; - let ty_visitor_name = tcx.sess.ident_of(~"TyVisitor"); assert!(tcx.intrinsic_defs.contains_key(&tydesc_name)); - assert!(ccx.tcx.intrinsic_defs.contains_key(&ty_visitor_name)); let (_, tydesc_ty) = *tcx.intrinsic_defs.get(&tydesc_name); - let (_, visitor_trait) = *tcx.intrinsic_defs.get(&ty_visitor_name); - - let visitor_trait = match ty::get(visitor_trait).sty { - ty::ty_trait(trait_def_id, ref trait_substs, _) => { - ty::mk_trait(tcx, - trait_def_id, - copy *trait_substs, - ty::BoxTraitStore) - } - _ => { - tcx.sess.span_bug(it.span, ~"TyVisitor wasn't a trait?!") - } - }; - + let (_, visitor_object_ty) = ty::visitor_object_ty(tcx); let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {ty: tydesc_ty, mutbl: ast::m_imm}); (0u, ~[arg(ast::by_copy, td_ptr), - arg(ast::by_ref, visitor_trait)], ty::mk_nil(tcx)) + arg(ast::by_ref, visitor_object_ty)], ty::mk_nil(tcx)) } ~"frame_address" => { let fty = ty::mk_closure(ccx.tcx, ty::ClosureTy { @@ -3690,7 +3692,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { output: output} }); let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); - let i_n_tps = (*i_ty.bounds).len(); + let i_n_tps = i_ty.generics.bounds.len(); if i_n_tps != n_tps { tcx.sess.span_err(it.span, fmt!("intrinsic has wrong number \ of type parameters: found %u, \ diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index dfc5f218d67d0..833dbff89a0fc 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -494,8 +494,8 @@ pub mod guarantor { * inferencer would not know of this dependency and thus it might * infer the lifetime of L2 to be greater than L1 (issue #3148). * - * There are a number of troublesome scenarios in the test - * `region-dependent-addr-of.rs`, but here is one example: + * There are a number of troublesome scenarios in the tests + * `region-dependent-*.rs`, but here is one example: * * struct Foo { i: int } * struct Bar { foo: Foo } @@ -583,8 +583,35 @@ pub mod guarantor { let mut expr_ct = categorize_unadjusted(rcx, expr); expr_ct = apply_autoderefs( rcx, expr, autoderefs, expr_ct); - for expr_ct.cat.guarantor.each |g| { - infallibly_mk_subr(rcx, true, expr.span, autoref.region, *g); + + match autoref.kind { + ty::AutoPtr => { + // In this case, we are implicitly adding an `&`. + maybe_make_subregion(rcx, expr, autoref.region, + expr_ct.cat.guarantor); + } + + ty::AutoBorrowVec | + ty::AutoBorrowVecRef | + ty::AutoBorrowFn => { + // In each of these cases, what is being borrowed is + // not the (autoderef'd) expr itself but rather the + // contents of the autoderef'd expression (i.e., what + // the pointer points at). + maybe_make_subregion(rcx, expr, autoref.region, + guarantor_of_deref(&expr_ct.cat)); + } + } + + fn maybe_make_subregion( + rcx: @mut Rcx, + expr: @ast::expr, + sub_region: ty::Region, + sup_region: Option) + { + for sup_region.each |r| { + infallibly_mk_subr(rcx, true, expr.span, sub_region, *r); + } } } @@ -813,19 +840,31 @@ pub mod guarantor { fn pointer_categorize(ty: ty::t) -> PointerCategorization { match ty::get(ty).sty { - ty::ty_rptr(r, _) | ty::ty_evec(_, ty::vstore_slice(r)) | + ty::ty_rptr(r, _) | + ty::ty_evec(_, ty::vstore_slice(r)) | ty::ty_estr(ty::vstore_slice(r)) => { BorrowedPointer(r) } - ty::ty_uniq(*) | ty::ty_estr(ty::vstore_uniq) | + ty::ty_uniq(*) | + ty::ty_estr(ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_uniq) => { OwnedPointer } - ty::ty_box(*) | ty::ty_ptr(*) | + ty::ty_box(*) | + ty::ty_ptr(*) | ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => { OtherPointer } + ty::ty_closure(ref closure_ty) => { + match closure_ty.sigil { + ast::BorrowedSigil => BorrowedPointer(closure_ty.region), + ast::OwnedSigil => OwnedPointer, + + // NOTE This is...not quite right. Deduce a test etc. + ast::ManagedSigil => OtherPointer, + } + } _ => { NotPointer } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 51f54d21ec4af..c30765baf37b3 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -70,7 +70,7 @@ pub impl VtableContext { fn tcx(&const self) -> ty::ctxt { self.ccx.tcx } } -pub fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool { +fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool { vec::any(tps, |bs| { bs.any(|b| { match b { &ty::bound_trait(_) => true, _ => false } @@ -78,11 +78,11 @@ pub fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool { }) } -pub fn lookup_vtables(vcx: &VtableContext, - location_info: &LocationInfo, - bounds: @~[ty::param_bounds], - substs: &ty::substs, - is_early: bool) -> vtable_res { +fn lookup_vtables(vcx: &VtableContext, + location_info: &LocationInfo, + bounds: @~[ty::param_bounds], + substs: &ty::substs, + is_early: bool) -> vtable_res { debug!("lookup_vtables(location_info=%?, # bounds=%?, \ substs=%s", @@ -95,30 +95,30 @@ pub fn lookup_vtables(vcx: &VtableContext, let mut result = ~[], i = 0u; for substs.tps.each |ty| { for ty::iter_bound_traits_and_supertraits( - tcx, bounds[i]) |trait_ty| + tcx, bounds[i]) |trait_ref| { debug!("about to subst: %?, %?", - ppaux::ty_to_str(tcx, trait_ty), + ppaux::trait_ref_to_str(tcx, trait_ref), ty::substs_to_str(tcx, substs)); let new_substs = substs { self_ty: Some(*ty), ../*bad*/copy *substs }; - let trait_ty = ty::subst(tcx, &new_substs, trait_ty); + let trait_ref = ty::subst_in_trait_ref(tcx, &new_substs, trait_ref); debug!("after subst: %?", - ppaux::ty_to_str(tcx, trait_ty)); + vcx.infcx.trait_ref_to_str(&trait_ref)); - match lookup_vtable(vcx, location_info, *ty, trait_ty, is_early) { + match lookup_vtable(vcx, location_info, *ty, &trait_ref, is_early) { Some(vtable) => result.push(vtable), None => { vcx.tcx().sess.span_fatal( location_info.span, fmt!("failed to find an implementation of \ trait %s for %s", - ppaux::ty_to_str(vcx.tcx(), trait_ty), - ppaux::ty_to_str(vcx.tcx(), *ty))); + vcx.infcx.trait_ref_to_str(&trait_ref), + vcx.infcx.ty_to_str(*ty))); } } } @@ -136,9 +136,9 @@ pub fn lookup_vtables(vcx: &VtableContext, @result } -pub fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo, - id: ast::def_id, +substs: ty::substs, - is_early: bool) -> Option { +fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo, + id: ast::def_id, +substs: ty::substs, + is_early: bool) -> Option { let tcx = vcx.tcx(); // use a dummy type just to package up the substs that need fixing up let t = ty::mk_trait(tcx, @@ -152,31 +152,58 @@ pub fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo, } } -pub fn relate_trait_tys(vcx: &VtableContext, location_info: &LocationInfo, - exp_trait_ty: ty::t, act_trait_ty: ty::t) { - demand_suptype(vcx, location_info.span, exp_trait_ty, act_trait_ty) +fn relate_trait_refs(vcx: &VtableContext, + location_info: &LocationInfo, + act_trait_ref: &ty::TraitRef, + exp_trait_ref: &ty::TraitRef) +{ + /*! + * + * Checks that an implementation of `act_trait_ref` is suitable + * for use where `exp_trait_ref` is required and reports an + * error otherwise. + */ + + match infer::mk_sub_trait_refs(vcx.infcx, false, location_info.span, + act_trait_ref, exp_trait_ref) + { + result::Ok(()) => {} // Ok. + result::Err(ref err) => { + let r_act_trait_ref = + vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(act_trait_ref); + let r_exp_trait_ref = + vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(exp_trait_ref); + if !ty::trait_ref_contains_error(&r_act_trait_ref) && + !ty::trait_ref_contains_error(&r_exp_trait_ref) + { + let tcx = vcx.tcx(); + tcx.sess.span_err( + location_info.span, + fmt!("expected %s, but found %s (%s)", + ppaux::trait_ref_to_str(tcx, &r_exp_trait_ref), + ppaux::trait_ref_to_str(tcx, &r_act_trait_ref), + ty::type_err_to_str(tcx, err))); + } + } + } } // Look up the vtable to use when treating an item of type `t` as if it has // type `trait_ty` -pub fn lookup_vtable(vcx: &VtableContext, - location_info: &LocationInfo, - ty: ty::t, - trait_ty: ty::t, - is_early: bool) - -> Option { - debug!("lookup_vtable(ty=%s, trait_ty=%s)", - vcx.infcx.ty_to_str(ty), vcx.infcx.ty_to_str(trait_ty)); +fn lookup_vtable(vcx: &VtableContext, + location_info: &LocationInfo, + ty: ty::t, + trait_ref: &ty::TraitRef, + is_early: bool) + -> Option +{ + debug!("lookup_vtable(ty=%s, trait_ref=%s)", + vcx.infcx.ty_to_str(ty), + vcx.infcx.trait_ref_to_str(trait_ref)); let _i = indenter(); let tcx = vcx.tcx(); - let (trait_id, trait_substs, trait_store) = match ty::get(trait_ty).sty { - ty::ty_trait(did, ref substs, store) => - (did, (/*bad*/copy *substs), store), - _ => tcx.sess.impossible_case(location_info.span, - "lookup_vtable: \ - don't know how to handle a non-trait") - }; + let ty = match fixup_ty(vcx, location_info, ty, is_early) { Some(ty) => ty, None => { @@ -194,37 +221,20 @@ pub fn lookup_vtable(vcx: &VtableContext, let mut n_bound = 0; let bounds = *tcx.ty_param_bounds.get(&did.node); for ty::iter_bound_traits_and_supertraits( - tcx, bounds) |ity| { + tcx, bounds) |bound_trait_ref| + { debug!("checking bounds trait %?", - vcx.infcx.ty_to_str(ity)); - - match ty::get(ity).sty { - ty::ty_trait(idid, ref isubsts, _) => { - if trait_id == idid { - debug!("(checking vtable) @0 \ - relating ty to trait \ - ty with did %?", - idid); - - // Convert `ity` so that it has the right vstore. - let ity = ty::mk_trait(vcx.tcx(), - idid, - copy *isubsts, - trait_store); - - relate_trait_tys(vcx, location_info, - trait_ty, ity); - let vtable = vtable_param(n, n_bound); - debug!("found param vtable: %?", - vtable); - return Some(vtable); - } - } - _ => tcx.sess.impossible_case( - location_info.span, - "lookup_vtable: in loop, \ - don't know how to handle a \ - non-trait ity") + vcx.infcx.trait_ref_to_str(bound_trait_ref)); + + if bound_trait_ref.def_id == trait_ref.def_id { + relate_trait_refs(vcx, + location_info, + bound_trait_ref, + trait_ref); + let vtable = vtable_param(n, n_bound); + debug!("found param vtable: %?", + vtable); + return Some(vtable); } n_bound += 1; @@ -236,18 +246,19 @@ pub fn lookup_vtable(vcx: &VtableContext, let mut impls_seen = HashSet::new(); - match vcx.ccx.coherence_info.extension_methods.find(&trait_id) { + match vcx.ccx.coherence_info.extension_methods.find(&trait_ref.def_id) { None => { // Nothing found. Continue. } Some(implementations) => { let implementations: &mut ~[@Impl] = *implementations; + // implementations is the list of all impls in scope for - // trait_ty. (Usually, there's just one.) + // trait_ref. (Usually, there's just one.) for uint::range(0, implementations.len()) |i| { let im = implementations[i]; - // im is one specific impl of trait_ty. + // im is one specific impl of trait_ref. // First, ensure we haven't processed this impl yet. if impls_seen.contains(&im.did) { @@ -269,22 +280,15 @@ pub fn lookup_vtable(vcx: &VtableContext, // ~[baz, bar, quux] // // For each of the traits foo implements, if - // it's the same trait as trait_ty, we need to - // unify it with trait_ty in order to get all + // it's the same trait as trait_ref, we need to + // unify it with trait_ref in order to get all // the ty vars sorted out. - for vec::each(ty::impl_traits(tcx, - im.did, - trait_store)) |of_ty| { - match ty::get(*of_ty).sty { - ty::ty_trait(id, _, _) => { - // Not the trait we're looking for - if id != trait_id { loop; } - } - _ => { /* ok */ } - } + for ty::impl_trait_refs(tcx, im.did).each |&of_trait_ref| + { + if of_trait_ref.def_id != trait_ref.def_id { loop; } - // At this point, we know that of_ty is - // the same trait as trait_ty, but + // At this point, we know that of_trait_ref is + // the same trait as trait_ref, but // possibly applied to different substs. // // Next, we check whether the "for" ty in @@ -318,39 +322,36 @@ pub fn lookup_vtable(vcx: &VtableContext, vcx.infcx.ty_to_str(for_ty), tys_to_str(vcx.tcx(), substs.tps)); - // Next, we unify trait_ty -- the type - // that we want to cast to -- with of_ty + // Next, we unify trait_ref -- the type + // that we want to cast to -- with of_trait_ref // -- the trait that im implements. At // this point, we require that they be // unifiable with each other -- that's - // what relate_trait_tys does. + // what relate_trait_refs does. // // For example, in the above example, - // of_ty would be some_trait, so we - // would be unifying trait_ty (for some + // of_trait_ref would be some_trait, so we + // would be unifying trait_ref (for some // value of U) with some_trait. This // would fail if T and U weren't // compatible. debug!("(checking vtable) @2 relating trait \ - ty %s to of_ty %s", - vcx.infcx.ty_to_str(trait_ty), - vcx.infcx.ty_to_str(*of_ty)); - let of_ty = ty::subst(tcx, &substs, *of_ty); - relate_trait_tys(vcx, location_info, trait_ty, - of_ty); - - // Recall that trait_ty -- the trait type - // we're casting to -- is the trait with - // id trait_id applied to the substs - // trait_substs. Now we extract out the - // types themselves from trait_substs. + ty %s to of_trait_ref %s", + vcx.infcx.trait_ref_to_str(trait_ref), + vcx.infcx.trait_ref_to_str(of_trait_ref)); - let trait_tps = /*bad*/copy trait_substs.tps; + let of_trait_ref = + ty::subst_in_trait_ref(tcx, &substs, of_trait_ref); + relate_trait_refs( + vcx, location_info, + &of_trait_ref, trait_ref); - debug!("Casting to a trait ty whose substs \ - (trait_tps) are %s", - tys_to_str(vcx.tcx(), trait_tps)); + // Recall that trait_ref -- the trait type + // we're casting to -- is the trait with + // id trait_ref.def_id applied to the substs + // trait_ref.substs. Now we extract out the + // types themselves from trait_ref.substs. // Recall that substs is the impl self // type's list of substitutions. That is, @@ -362,7 +363,7 @@ pub fn lookup_vtable(vcx: &VtableContext, let substs_f = match fixup_substs(vcx, location_info, - trait_id, + trait_ref.def_id, substs, is_early) { Some(ref substs) => (/*bad*/copy *substs), @@ -377,7 +378,7 @@ pub fn lookup_vtable(vcx: &VtableContext, they will be unified with the bounds for \ the target ty, %s", tys_to_str(vcx.tcx(), substs_f.tps), - tys_to_str(vcx.tcx(), trait_tps)); + vcx.infcx.trait_ref_to_str(trait_ref)); // Next, we unify the fixed-up // substitutions for the impl self ty with @@ -386,14 +387,13 @@ pub fn lookup_vtable(vcx: &VtableContext, // to. connect_trait_tps requires these // lists of types to unify pairwise. - let im_bs = ty::lookup_item_type(tcx, - im.did).bounds; + let im_bs = + ty::lookup_item_type(tcx, im.did).generics.bounds; connect_trait_tps(vcx, location_info, - /*bad*/copy substs_f.tps, - trait_tps, - im.did, - trait_store); + &substs_f, + trait_ref, + im.did); let subres = lookup_vtables( vcx, location_info, im_bs, &substs_f, is_early); @@ -430,10 +430,10 @@ pub fn lookup_vtable(vcx: &VtableContext, return None; } -pub fn fixup_ty(vcx: &VtableContext, - location_info: &LocationInfo, - ty: ty::t, - is_early: bool) -> Option { +fn fixup_ty(vcx: &VtableContext, + location_info: &LocationInfo, + ty: ty::t, + is_early: bool) -> Option { let tcx = vcx.tcx(); match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) { Ok(new_type) => Some(new_type), @@ -450,45 +450,23 @@ pub fn fixup_ty(vcx: &VtableContext, } } -// Version of demand::suptype() that takes a vtable context instead of a -// function context. -pub fn demand_suptype(vcx: &VtableContext, sp: span, e: ty::t, a: ty::t) { - // NB: Order of actual, expected is reversed. - match infer::mk_subty(vcx.infcx, false, sp, a, e) { - result::Ok(()) => {} // Ok. - result::Err(ref err) => { - vcx.infcx.report_mismatched_types(sp, e, a, err); - } - } -} - -pub fn connect_trait_tps(vcx: &VtableContext, - location_info: &LocationInfo, - impl_tys: ~[ty::t], - trait_tys: ~[ty::t], - impl_did: ast::def_id, - store: ty::TraitStore) { +fn connect_trait_tps(vcx: &VtableContext, + location_info: &LocationInfo, + impl_substs: &ty::substs, + trait_ref: &ty::TraitRef, + impl_did: ast::def_id) +{ let tcx = vcx.tcx(); // XXX: This should work for multiple traits. - let ity = ty::impl_traits(tcx, impl_did, store)[0]; - let trait_ty = ty::subst_tps(tcx, impl_tys, None, ity); - debug!("(connect trait tps) trait type is %?, impl did is %?", - ty::get(trait_ty).sty, impl_did); - match ty::get(trait_ty).sty { - ty::ty_trait(_, ref substs, _) => { - for vec::each2((*substs).tps, trait_tys) |a, b| { - demand_suptype(vcx, location_info.span, *a, *b); - } - } - _ => tcx.sess.impossible_case(location_info.span, "connect_trait_tps: \ - don't know how to handle a non-trait ty") - } + let impl_trait_ref = ty::impl_trait_refs(tcx, impl_did)[0]; + let impl_trait_ref = ty::subst_in_trait_ref(tcx, impl_substs, impl_trait_ref); + relate_trait_refs(vcx, location_info, trait_ref, &impl_trait_ref); } -pub fn insert_vtables(fcx: @mut FnCtxt, - callee_id: ast::node_id, - vtables: vtable_res) { +fn insert_vtables(fcx: @mut FnCtxt, + callee_id: ast::node_id, + vtables: vtable_res) { debug!("insert_vtables(callee_id=%d, vtables=%?)", callee_id, vtables.map(|v| v.to_str(fcx.tcx()))); fcx.inh.vtable_map.insert(callee_id, vtables); @@ -517,15 +495,15 @@ pub fn early_resolve_expr(ex: @ast::expr, let item_ty = ty::lookup_item_type(cx.tcx, did); debug!("early resolve expr: def %? %?, %?, %?", ex.id, did, def, fcx.infcx().ty_to_str(item_ty.ty)); - if has_trait_bounds(/*bad*/copy *item_ty.bounds) { - for item_ty.bounds.each |bounds| { + if has_trait_bounds(/*bad*/copy *item_ty.generics.bounds) { + for item_ty.generics.bounds.each |bounds| { debug!("early_resolve_expr: looking up vtables for bound \ %s", ty::param_bounds_to_str(fcx.tcx(), *bounds)); } let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex), - item_ty.bounds, substs, is_early); + item_ty.generics.bounds, substs, is_early); if !is_early { insert_vtables(fcx, ex.id, vtbls); } @@ -564,7 +542,7 @@ pub fn early_resolve_expr(ex: @ast::expr, ast::expr_cast(src, _) => { let target_ty = fcx.expr_ty(ex); match ty::get(target_ty).sty { - ty::ty_trait(_, _, store) => { + ty::ty_trait(target_def_id, ref target_substs, store) => { // Look up vtables for the type we're casting to, // passing in the source and target type. The source // must be a pointer type suitable to the object sigil, @@ -573,7 +551,6 @@ pub fn early_resolve_expr(ex: @ast::expr, fcx.expr_ty(src)); match (&ty::get(ty).sty, store) { (&ty::ty_box(mt), ty::BoxTraitStore) | - // XXX: Bare trait store is deprecated. (&ty::ty_uniq(mt), ty::UniqTraitStore) | (&ty::ty_rptr(_, mt), ty::RegionTraitStore(*)) => { let location_info = @@ -582,11 +559,15 @@ pub fn early_resolve_expr(ex: @ast::expr, ccx: fcx.ccx, infcx: fcx.infcx() }; + let target_trait_ref = ty::TraitRef { + def_id: target_def_id, + substs: copy *target_substs + }; let vtable_opt = lookup_vtable(&vcx, location_info, mt.ty, - target_ty, + &target_trait_ref, is_early); match vtable_opt { Some(vtable) => { @@ -622,11 +603,12 @@ pub fn early_resolve_expr(ex: @ast::expr, } } - (_, ty::BareTraitStore) => { + (_, ty::UniqTraitStore) => { fcx.ccx.tcx.sess.span_err( ex.span, - ~"a sigil (`@`, `~`, or `&`) must be specified \ - when casting to a trait"); + fmt!("can only cast an ~-pointer \ + to a ~-object, not a %s", + ty::ty_sort_str(fcx.tcx(), ty))); } (_, ty::BoxTraitStore) => { @@ -637,14 +619,6 @@ pub fn early_resolve_expr(ex: @ast::expr, ty::ty_sort_str(fcx.tcx(), ty))); } - (_, ty::UniqTraitStore) => { - fcx.ccx.tcx.sess.span_err( - ex.span, - fmt!("can only cast an ~-pointer \ - to a ~-object, not a %s", - ty::ty_sort_str(fcx.tcx(), ty))); - } - (_, ty::RegionTraitStore(_)) => { fcx.ccx.tcx.sess.span_err( ex.span, @@ -661,9 +635,9 @@ pub fn early_resolve_expr(ex: @ast::expr, } } -pub fn resolve_expr(ex: @ast::expr, - &&fcx: @mut FnCtxt, - v: visit::vt<@mut FnCtxt>) { +fn resolve_expr(ex: @ast::expr, + &&fcx: @mut FnCtxt, + v: visit::vt<@mut FnCtxt>) { early_resolve_expr(ex, fcx, false); visit::visit_expr(ex, fcx, v); } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 466cb8ed54f2b..b0e5ecee01ebb 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -38,7 +38,7 @@ use middle::typeck::infer::combine::Combine; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::{new_infer_ctxt, resolve_ivar}; use middle::typeck::infer::{resolve_nested_tvar, resolve_type}; -use syntax::ast::{crate, def_id, def_mod, def_ty}; +use syntax::ast::{crate, def_id, def_mod, def_trait}; use syntax::ast::{item, item_impl, item_mod, local_crate, method, trait_ref}; use syntax::ast; use syntax::ast_map::node_item; @@ -333,10 +333,16 @@ pub impl CoherenceChecker { let new_id = parse::next_node_id(tcx.sess.parse_sess); let new_did = local_def(new_id); + let new_method_ty = @ty::method { + def_id: new_did, + ..copy *trait_method + }; + // XXX: Perform substitutions. let new_polytype = ty::lookup_item_type(tcx, trait_method.def_id); tcx.tcache.insert(new_did, new_polytype); + tcx.methods.insert(new_did, new_method_ty); // Pair the new synthesized ID up with the // ID of the method. @@ -352,7 +358,7 @@ pub impl CoherenceChecker { @ProvidedMethodInfo { method_info: @MethodInfo { did: new_did, - n_tps: trait_method.tps.len(), + n_tps: trait_method.generics.bounds.len(), ident: trait_method.ident, self_type: trait_method.self_ty }, @@ -498,7 +504,7 @@ pub impl CoherenceChecker { fn each_provided_trait_method(&self, trait_did: ast::def_id, - f: &fn(x: &ty::method) -> bool) { + f: &fn(x: @ty::method) -> bool) { // Make a list of all the names of the provided methods. // XXX: This is horrible. let mut provided_method_idents = HashSet::new(); @@ -507,7 +513,7 @@ pub impl CoherenceChecker { provided_method_idents.insert(*ident); } - for ty::trait_methods(tcx, trait_did).each |method| { + for ty::trait_methods(tcx, trait_did).each |&method| { if provided_method_idents.contains(&method.ident) { if !f(method) { break; @@ -536,10 +542,10 @@ pub impl CoherenceChecker { -> UniversalQuantificationResult { // NDM--this span is bogus. let self_region = - polytype.region_param.map( + polytype.generics.region_param.map( |_r| self.inference_context.next_region_var_nb(dummy_sp())); - let bounds_count = polytype.bounds.len(); + let bounds_count = polytype.generics.bounds.len(); let type_parameters = self.inference_context.next_ty_vars(bounds_count); @@ -559,7 +565,7 @@ pub impl CoherenceChecker { UniversalQuantificationResult { monotype: monotype, type_variables: type_parameters, - bounds: polytype.bounds + bounds: polytype.generics.bounds } } @@ -858,17 +864,8 @@ pub impl CoherenceChecker { } // Record all the trait methods. - for associated_traits.each |trait_type| { - match get(*trait_type).sty { - ty_trait(trait_id, _, _) => { - self.add_trait_method(trait_id, *implementation); - } - _ => { - self.crate_context.tcx.sess.bug(~"trait type \ - returned is not a \ - trait"); - } - } + for associated_traits.each |trait_ref| { + self.add_trait_method(trait_ref.def_id, *implementation); } // Add the implementation to the mapping from @@ -917,7 +914,7 @@ pub impl CoherenceChecker { @ProvidedMethodInfo { method_info: @MethodInfo { did: new_did, - n_tps: trait_method_info.ty.tps.len(), + n_tps: trait_method_info.ty.generics.bounds.len(), ident: trait_method_info.ty.ident, self_type: trait_method_info.ty.self_ty }, @@ -947,16 +944,8 @@ pub impl CoherenceChecker { crate_store, def_id); } - dl_def(def_ty(def_id)) => { - let tcx = self.crate_context.tcx; - let polytype = csearch::get_type(tcx, def_id); - match ty::get(polytype.ty).sty { - ty::ty_trait(*) => { - self.add_default_methods_for_external_trait( - def_id); - } - _ => {} - } + dl_def(def_trait(def_id)) => { + self.add_default_methods_for_external_trait(def_id); } dl_def(_) | dl_impl(_) | dl_field => { // Skip this. diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index f1d743e79e58a..a9d54716cd8a8 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -33,8 +33,7 @@ are represented as `ty_param()` instances. use core::prelude::*; use metadata::csearch; -use middle::ty::InstantiatedTraitRef; -use middle::ty::{substs, ty_param_bounds_and_ty, ty_param_substs_and_ty}; +use middle::ty::{substs, ty_param_bounds_and_ty}; use middle::ty; use middle::typeck::astconv::{AstConv, ty_of_arg}; use middle::typeck::astconv::{ast_ty_to_ty}; @@ -42,8 +41,7 @@ use middle::typeck::astconv; use middle::typeck::infer; use middle::typeck::rscope::*; use middle::typeck::rscope; -use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx, - write_tpt_to_tcx}; +use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; use util::common::{indenter, pluralize}; use util::ppaux; @@ -53,7 +51,6 @@ use syntax::ast::{RegionTyParamBound, TraitTyParamBound}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::{local_def, split_trait_methods}; -use syntax::ast_util::{trait_method_to_ty_method}; use syntax::ast_util; use syntax::codemap::span; use syntax::codemap; @@ -84,12 +81,10 @@ pub fn collect_item_types(ccx: @mut CrateCtxt, crate: @ast::crate) { match intrinsic_item.node { ast::item_trait(*) => { - let ty = ty::mk_trait(ccx.tcx, - def_id, - substs, - ty::BareTraitStore); - ccx.tcx.intrinsic_defs.insert - (intrinsic_item.ident, (def_id, ty)); + let tref = @ty::TraitRef {def_id: def_id, + substs: substs}; + ccx.tcx.intrinsic_traits.insert + (intrinsic_item.ident, tref); } ast::item_enum(*) => { @@ -153,6 +148,10 @@ impl AstConv for CrateCtxt { } } + fn get_trait_def(&self, id: ast::def_id) -> @ty::TraitDef { + get_trait_def(self, id) + } + fn ty_infer(&self, span: span) -> ty::t { self.tcx.sess.span_bug(span, ~"found `ty_infer` in unexpected place"); @@ -187,8 +186,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, ast::struct_variant_kind(struct_def) => { let tpt = ty_param_bounds_and_ty { - bounds: ty_param_bounds(ccx, generics), - region_param: rp, + generics: ty_generics(ccx, rp, generics), ty: enum_ty }; @@ -209,8 +207,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, None => {} Some(result_ty) => { let tpt = ty_param_bounds_and_ty { - bounds: ty_param_bounds(ccx, generics), - region_param: rp, + generics: ty_generics(ccx, rp, generics), ty: result_ty }; tcx.tcache.insert(local_def(variant.node.id), tpt); @@ -221,23 +218,62 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, } pub fn ensure_trait_methods(ccx: &CrateCtxt, - id: ast::node_id, - trait_ty: ty::t) { - fn store_methods(ccx: &CrateCtxt, - id: ast::node_id, - stuff: &[T], - f: &fn(v: &T) -> ty::method) { - ty::store_trait_methods(ccx.tcx, id, @stuff.map(f)); + trait_id: ast::node_id) +{ + let tcx = ccx.tcx; + let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|&x| *x); + match *tcx.items.get(&trait_id) { + ast_map::node_item(@ast::item { + node: ast::item_trait(ref generics, _, ref ms), + _ + }, _) => { + let trait_ty_generics = ty_generics(ccx, region_paramd, generics); + + // For each method, construct a suitable ty::method and + // store it into the `tcx.methods` table: + for ms.each |m| { + let ty_method = @match m { + &ast::required(ref m) => { + ty_method_of_trait_method( + ccx, trait_id, region_paramd, generics, + &m.id, &m.ident, &m.self_ty, + &m.generics, &m.purity, &m.decl) + } + + &ast::provided(ref m) => { + ty_method_of_trait_method( + ccx, trait_id, region_paramd, generics, + &m.id, &m.ident, &m.self_ty, + &m.generics, &m.purity, &m.decl) + } + }; + + if ty_method.self_ty == ast::sty_static { + make_static_method_ty(ccx, trait_id, ty_method, + &trait_ty_generics); + } + + tcx.methods.insert(ty_method.def_id, ty_method); + } + + // Add an entry mapping + let method_def_ids = @ms.map(|m| { + match m { + &ast::required(ref ty_method) => local_def(ty_method.id), + &ast::provided(ref method) => local_def(method.id) + } + }); + + let trait_def_id = local_def(trait_id); + tcx.trait_method_def_ids.insert(trait_def_id, method_def_ids); + } + _ => { /* Ignore things that aren't traits */ } } fn make_static_method_ty(ccx: &CrateCtxt, - am: &ast::ty_method, - rp: Option, - m: ty::method, - // Take this as an argument b/c we may check - // the impl before the trait. - trait_ty: ty::t, - trait_bounds: @~[ty::param_bounds]) { + trait_id: ast::node_id, + m: &ty::method, + trait_ty_generics: &ty::Generics) { // We need to create a typaram that replaces self. This param goes // *in between* the typarams from the trait and those from the // method (since its bound can depend on the trait? or @@ -248,12 +284,13 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, let dummy_defid = ast::def_id {crate: 0, node: 0}; - let non_shifted_trait_tps = do vec::from_fn(trait_bounds.len()) |i| { + let num_trait_bounds = trait_ty_generics.bounds.len(); + let non_shifted_trait_tps = do vec::from_fn(num_trait_bounds) |i| { ty::mk_param(ccx.tcx, i, dummy_defid) }; - let self_param = ty::mk_param(ccx.tcx, trait_bounds.len(), + let self_param = ty::mk_param(ccx.tcx, num_trait_bounds, dummy_defid); - let shifted_method_tps = do vec::from_fn(m.tps.len()) |i| { + let shifted_method_tps = do vec::from_fn(m.generics.bounds.len()) |i| { ty::mk_param(ccx.tcx, i + 1, dummy_defid) }; @@ -265,50 +302,48 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, let ty = ty::subst(ccx.tcx, &substs, ty::mk_bare_fn(ccx.tcx, copy m.fty)); - let bounds = @(*trait_bounds + ~[@~[ty::bound_trait(trait_ty)]] - + *m.tps); - ccx.tcx.tcache.insert(local_def(am.id), + let trait_def = get_trait_def(ccx, local_def(trait_id)); + let trait_ref = trait_def.trait_ref; + let mut new_bounds = ~[]; + new_bounds.push_all(*trait_ty_generics.bounds); + new_bounds.push(@~[ty::bound_trait(trait_ref)]); + new_bounds.push_all(*m.generics.bounds); + ccx.tcx.tcache.insert(m.def_id, ty_param_bounds_and_ty { - bounds: bounds, - region_param: rp, - ty: ty}); + generics: ty::Generics { + bounds: @new_bounds, + region_param: trait_ty_generics.region_param + }, + ty: ty + }); } - - let tcx = ccx.tcx; - let region_paramd = tcx.region_paramd_items.find(&id).map_consume(|x| *x); - match *tcx.items.get(&id) { - ast_map::node_item(@ast::item { - node: ast::item_trait(ref generics, _, ref ms), - _ - }, _) => { - store_methods::(ccx, id, *ms, |m| { - let def_id; - match *m { - ast::required(ref ty_method) => { - def_id = local_def((*ty_method).id) - } - ast::provided(method) => def_id = local_def(method.id) - } - - let trait_bounds = ty_param_bounds(ccx, generics); - let ty_m = trait_method_to_ty_method(m); - let method_ty = ty_of_ty_method( - ccx, - &ty_m, - region_paramd, - def_id, - generics - ); - if ty_m.self_ty.node == ast::sty_static { - make_static_method_ty(ccx, &ty_m, region_paramd, - method_ty, trait_ty, - trait_bounds); - } - method_ty - }); - } - _ => { /* Ignore things that aren't traits */ } + fn ty_method_of_trait_method(self: &CrateCtxt, + trait_id: ast::node_id, + trait_rp: Option, + trait_generics: &ast::Generics, + m_id: &ast::node_id, + m_ident: &ast::ident, + m_self_ty: &ast::self_ty, + m_generics: &ast::Generics, + m_purity: &ast::purity, + m_decl: &ast::fn_decl) -> ty::method + { + let trait_self_ty = ty::mk_self(self.tcx, local_def(trait_id)); + let rscope = MethodRscope::new(m_self_ty.node, trait_rp, trait_generics); + let (transformed_self_ty, fty) = + astconv::ty_of_method(self, &rscope, *m_purity, &m_generics.lifetimes, + trait_self_ty, *m_self_ty, m_decl); + ty::method { + ident: *m_ident, + generics: ty_generics(self, None, m_generics), + transformed_self_ty: transformed_self_ty, + fty: fty, + self_ty: m_self_ty.node, + // assume public, because this is only invoked on trait methods + vis: ast::public, + def_id: local_def(*m_id) + } } } @@ -316,25 +351,28 @@ pub fn ensure_supertraits(ccx: &CrateCtxt, id: ast::node_id, sp: codemap::span, rp: Option, - trait_refs: &[@ast::trait_ref], - generics: &ast::Generics) { + ast_trait_refs: &[@ast::trait_ref], + generics: &ast::Generics) +{ let tcx = ccx.tcx; if tcx.supertraits.contains_key(&local_def(id)) { return; } - let mut instantiated = ~[]; - for trait_refs.each |trait_ref| { - let (did, tpt) = instantiate_trait_ref(ccx, *trait_ref, rp, generics); - if instantiated.any(|other_trait: &InstantiatedTraitRef| - { other_trait.def_id == did }) { + let mut ty_trait_refs: ~[@ty::TraitRef] = ~[]; + for ast_trait_refs.each |&ast_trait_ref| { + let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, rp, generics); + + // FIXME(#5527) Could have same trait multiple times + if ty_trait_refs.any(|other_trait| other_trait.def_id == trait_ref.def_id) { // This means a trait inherited from the same supertrait more // than once. tcx.sess.span_err(sp, ~"Duplicate supertrait in trait \ declaration"); - return; + break; + } else { + ty_trait_refs.push(trait_ref); } - instantiated.push(InstantiatedTraitRef { def_id: did, tpt: tpt }); } - tcx.supertraits.insert(local_def(id), @instantiated); + tcx.supertraits.insert(local_def(id), @ty_trait_refs); } /** @@ -388,15 +426,15 @@ pub fn compare_impl_method(tcx: ty::ctxt, } } - if impl_m.tps.len() != trait_m.tps.len() { + if impl_m.generics.bounds.len() != trait_m.generics.bounds.len() { tcx.sess.span_err( cm.span, fmt!("method `%s` has %u type %s, but its trait \ declaration has %u type %s", - *tcx.sess.str_of(trait_m.ident), impl_m.tps.len(), - pluralize(impl_m.tps.len(), ~"parameter"), - trait_m.tps.len(), - pluralize(trait_m.tps.len(), ~"parameter"))); + *tcx.sess.str_of(trait_m.ident), impl_m.generics.bounds.len(), + pluralize(impl_m.generics.bounds.len(), ~"parameter"), + trait_m.generics.bounds.len(), + pluralize(trait_m.generics.bounds.len(), ~"parameter"))); return; } @@ -414,9 +452,9 @@ pub fn compare_impl_method(tcx: ty::ctxt, // FIXME(#2687)---we should be checking that the bounds of the // trait imply the bounds of the subtype, but it appears // we are...not checking this. - for trait_m.tps.eachi() |i, trait_param_bounds| { + for trait_m.generics.bounds.eachi() |i, trait_param_bounds| { // For each of the corresponding impl ty param's bounds... - let impl_param_bounds = impl_m.tps[i]; + let impl_param_bounds = impl_m.generics.bounds[i]; // Make sure the bounds lists have the same length // Would be nice to use the ty param names in the error message, // but we don't have easy access to them here @@ -456,7 +494,7 @@ pub fn compare_impl_method(tcx: ty::ctxt, }; debug!("impl_fty: %s", ppaux::ty_to_str(tcx, impl_fty)); let trait_fty = { - let dummy_tps = do vec::from_fn((*trait_m.tps).len()) |i| { + let dummy_tps = do vec::from_fn(trait_m.generics.bounds.len()) |i| { // hack: we don't know the def id of the impl tp, but it // is not important for unification ty::mk_param(tcx, i + impl_tps, ast::def_id {crate: 0, node: 0}) @@ -501,40 +539,26 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, rp: Option, selfty: ty::t, a_trait_ty: @ast::trait_ref, - impl_ms: &[ConvertedMethod]) { - + impl_ms: &[ConvertedMethod]) +{ let tcx = ccx.tcx; - let (did, tpt) = instantiate_trait_ref(ccx, a_trait_ty, rp, generics); - - if did.crate == ast::local_crate { - // NB: This is subtle. We need to do this on the type of the trait - // item *itself*, not on the type that includes the parameter - // substitutions provided by the programmer at this particular - // trait ref. Otherwise, we will potentially overwrite the types of - // the methods within the trait with bogus results. (See issue #3903.) - - match tcx.items.find(&did.node) { - Some(&ast_map::node_item(item, _)) => { - let tpt = ty_of_item(ccx, item); - ensure_trait_methods(ccx, did.node, tpt.ty); - } - _ => { - tcx.sess.bug(~"trait ref didn't resolve to trait"); - } - } + let trait_ref = instantiate_trait_ref(ccx, a_trait_ty, rp, generics); + + if trait_ref.def_id.crate == ast::local_crate { + ensure_trait_methods(ccx, trait_ref.def_id.node); } // Check that each method we impl is a method on the trait // Trait methods we don't implement must be default methods, but if not // we'll catch it in coherence - let trait_ms = ty::trait_methods(tcx, did); + let trait_ms = ty::trait_methods(tcx, trait_ref.def_id); for impl_ms.each |impl_m| { match trait_ms.find(|trait_m| trait_m.ident == impl_m.mty.ident) { - Some(ref trait_m) => { + Some(trait_m) => { let num_impl_tps = generics.ty_params.len(); compare_impl_method( ccx.tcx, num_impl_tps, impl_m, trait_m, - &tpt.substs, selfty); + &trait_ref.substs, selfty); } None => { // This method is not part of the trait @@ -560,14 +584,16 @@ pub fn convert_field(ccx: &CrateCtxt, /* add the field to the tcache */ ccx.tcx.tcache.insert(local_def(v.node.id), ty::ty_param_bounds_and_ty { - bounds: bounds, - region_param: rp, + generics: ty::Generics { + bounds: bounds, + region_param: rp + }, ty: tt }); } pub struct ConvertedMethod { - mty: ty::method, + mty: @ty::method, id: ast::node_id, span: span, body_id: ast::node_id @@ -575,29 +601,74 @@ pub struct ConvertedMethod { pub fn convert_methods(ccx: &CrateCtxt, ms: &[@ast::method], - rp: Option, - rcvr_bounds: @~[ty::param_bounds], - rcvr_generics: &ast::Generics) - -> ~[ConvertedMethod] { - + untransformed_rcvr_ty: ty::t, + rcvr_ty_generics: &ty::Generics, + rcvr_ast_generics: &ast::Generics, + rcvr_visibility: ast::visibility) + -> ~[ConvertedMethod] +{ let tcx = ccx.tcx; - do vec::map(ms) |m| { - let bounds = ty_param_bounds(ccx, &m.generics); - let mty = ty_of_method(ccx, *m, rp, rcvr_generics, &m.generics); - let fty = ty::mk_bare_fn(tcx, copy mty.fty); + return vec::map(ms, |m| { + let m_ty_generics = + ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics); + let mty = + @ty_of_method(ccx, *m, rcvr_ty_generics.region_param, + untransformed_rcvr_ty, + rcvr_ast_generics, rcvr_visibility, + &m.generics); + let fty = + ty::mk_bare_fn(tcx, copy mty.fty); tcx.tcache.insert( local_def(m.id), // n.b.: the type of a method is parameterized by both // the tps on the receiver and those on the method itself ty_param_bounds_and_ty { - bounds: @(vec::append(/*bad*/copy *rcvr_bounds, *bounds)), - region_param: rp, + generics: ty::Generics { + bounds: @(vec::append(copy *rcvr_ty_generics.bounds, + *m_ty_generics.bounds)), + region_param: rcvr_ty_generics.region_param + }, ty: fty }); write_ty_to_tcx(tcx, m.id, fty); + tcx.methods.insert(mty.def_id, mty); ConvertedMethod {mty: mty, id: m.id, span: m.span, body_id: m.body.node.id} + }); + + fn ty_of_method(ccx: &CrateCtxt, + m: @ast::method, + rp: Option, + untransformed_rcvr_ty: ty::t, + rcvr_generics: &ast::Generics, + rcvr_visibility: ast::visibility, + method_generics: &ast::Generics) -> ty::method + { + let rscope = MethodRscope::new(m.self_ty.node, + rp, + rcvr_generics); + let (transformed_self_ty, fty) = + astconv::ty_of_method(ccx, &rscope, m.purity, + &method_generics.lifetimes, + untransformed_rcvr_ty, + m.self_ty, &m.decl); + + // if the method specifies a visibility, use that, otherwise + // inherit the visibility from the impl (so `foo` in `pub impl + // { fn foo(); }` is public, but private in `priv impl { fn + // foo(); }`). + let method_vis = m.vis.inherit_from(rcvr_visibility); + + ty::method { + ident: m.ident, + generics: ty_generics(ccx, None, &m.generics), + transformed_self_ty: transformed_self_ty, + fty: fty, + self_ty: m.self_ty.node, + vis: method_vis, + def_id: local_def(m.id) + } } } @@ -633,36 +704,49 @@ pub fn convert(ccx: &CrateCtxt, it: @ast::item) { generics, rp); } - ast::item_impl(ref generics, trait_ref, selfty, ref ms) => { - let i_bounds = ty_param_bounds(ccx, generics); + ast::item_impl(ref generics, opt_trait_ref, selfty, ref ms) => { + let i_ty_generics = ty_generics(ccx, rp, generics); let region_parameterization = RegionParameterization::from_variance_and_generics(rp, generics); let selfty = ccx.to_ty(&type_rscope(region_parameterization), selfty); write_ty_to_tcx(tcx, it.id, selfty); tcx.tcache.insert(local_def(it.id), ty_param_bounds_and_ty { - bounds: i_bounds, - region_param: rp, - ty: selfty}); + generics: i_ty_generics, + ty: selfty}); + + // If there is a trait reference, treat the methods as always public. + // This is to work around some incorrect behavior in privacy checking: + // when the method belongs to a trait, it should acquire the privacy + // from the trait, not the impl. Forcing the visibility to be public + // makes things sorta work. + let parent_visibility = if opt_trait_ref.is_some() { + ast::public + } else { + it.vis + }; - // XXX: Bad copy of `ms` below. - let cms = convert_methods(ccx, *ms, rp, i_bounds, generics); - for trait_ref.each |t| { + let cms = convert_methods(ccx, *ms, selfty, + &i_ty_generics, generics, + parent_visibility); + for opt_trait_ref.each |t| { check_methods_against_trait(ccx, generics, rp, selfty, *t, cms); } } ast::item_trait(ref generics, ref supertraits, ref trait_methods) => { - let tpt = ty_of_item(ccx, it); - debug!("item_trait(it.id=%d, tpt.ty=%s)", - it.id, ppaux::ty_to_str(tcx, tpt.ty)); - write_ty_to_tcx(tcx, it.id, tpt.ty); - ensure_trait_methods(ccx, it.id, tpt.ty); - ensure_supertraits(ccx, it.id, it.span, rp, *supertraits, generics); - - let (_, provided_methods) = - split_trait_methods(*trait_methods); - let (bounds, _) = mk_substs(ccx, generics, rp); - let _ = convert_methods(ccx, provided_methods, rp, bounds, generics); + let trait_def = trait_def_of_item(ccx, it); + tcx.trait_defs.insert(local_def(it.id), trait_def); + ensure_trait_methods(ccx, it.id); + ensure_supertraits(ccx, it.id, it.span, rp, *supertraits, generics); + + let (_, provided_methods) = + split_trait_methods(*trait_methods); + let (ty_generics, _) = mk_substs(ccx, generics, rp); + let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id)); + let _ = convert_methods(ccx, provided_methods, + untransformed_rcvr_ty, + &ty_generics, generics, + it.vis); } ast::item_struct(struct_def, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "structure"); @@ -714,14 +798,16 @@ pub fn convert_struct(ccx: &CrateCtxt, write_ty_to_tcx(tcx, dtor.node.id, t_dtor); tcx.tcache.insert(local_def(dtor.node.id), ty_param_bounds_and_ty { - bounds: tpt.bounds, - region_param: rp, - ty: t_dtor}); + generics: ty::Generics { + bounds: tpt.generics.bounds, + region_param: rp + }, + ty: t_dtor}); }; // Write the type of each of the members for struct_def.fields.each |f| { - convert_field(ccx, rp, tpt.bounds, *f, generics); + convert_field(ccx, rp, tpt.generics.bounds, *f, generics); } let (_, substs) = mk_substs(ccx, generics, rp); let selfty = ty::mk_struct(tcx, local_def(id), substs); @@ -744,8 +830,7 @@ pub fn convert_struct(ccx: &CrateCtxt, let ctor_fn_ty = ty::mk_ctor_fn(tcx, inputs, selfty); write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); tcx.tcache.insert(local_def(ctor_id), ty_param_bounds_and_ty { - bounds: tpt.bounds, - region_param: tpt.region_param, + generics: tpt.generics, ty: ctor_fn_ty }); } @@ -762,85 +847,75 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: @ast::foreign_item) { ccx.tcx.tcache.insert(local_def(i.id), tpt); } -pub fn ty_of_method(ccx: &CrateCtxt, - m: @ast::method, - rp: Option, - rcvr_generics: &ast::Generics, - method_generics: &ast::Generics) - -> ty::method { - let rscope = MethodRscope::new(m.self_ty.node, - rp, - rcvr_generics); - ty::method { - ident: m.ident, - tps: ty_param_bounds(ccx, &m.generics), - fty: astconv::ty_of_bare_fn(ccx, - &rscope, - m.purity, - AbiSet::Rust(), - &method_generics.lifetimes, - &m.decl), - self_ty: m.self_ty.node, - vis: m.vis, - def_id: local_def(m.id) - } -} - -pub fn ty_of_ty_method(self: &CrateCtxt, - m: &ast::ty_method, - rp: Option, - id: ast::def_id, - generics: &ast::Generics) - -> ty::method { - let rscope = MethodRscope::new(m.self_ty.node, rp, generics); - ty::method { - ident: m.ident, - tps: ty_param_bounds(self, &m.generics), - fty: astconv::ty_of_bare_fn(self, - &rscope, - m.purity, - AbiSet::Rust(), - &m.generics.lifetimes, - &m.decl), - // assume public, because this is only invoked on trait methods - self_ty: m.self_ty.node, - vis: ast::public, - def_id: id - } -} - -/* - Instantiates the path for the given trait reference, assuming that - it's bound to a valid trait type. Returns the def_id for the defining - trait. Fails if the type is a type other than an trait type. - */ pub fn instantiate_trait_ref(ccx: &CrateCtxt, - t: @ast::trait_ref, + ast_trait_ref: @ast::trait_ref, rp: Option, - generics: &ast::Generics) - -> (ast::def_id, ty_param_substs_and_ty) { - - let sp = t.path.span, err = ~"can only implement trait types", - sess = ccx.tcx.sess; + generics: &ast::Generics) -> @ty::TraitRef +{ + /*! + * Instantiates the path for the given trait reference, assuming that + * it's bound to a valid trait type. Returns the def_id for the defining + * trait. Fails if the type is a type other than an trait type. + */ let rp = RegionParameterization::from_variance_and_generics(rp, generics); let rscope = type_rscope(rp); - match lookup_def_tcx(ccx.tcx, t.path.span, t.ref_id) { - ast::def_ty(t_id) => { - let tpt = astconv::ast_path_to_ty(ccx, &rscope, t_id, t.path); + match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) { + ast::def_trait(trait_did) => { + let trait_ref = + astconv::ast_path_to_trait_ref( + ccx, &rscope, trait_did, ast_trait_ref.path); + ccx.tcx.trait_refs.insert( + ast_trait_ref.ref_id, trait_ref); + return trait_ref; + } + _ => { + ccx.tcx.sess.span_fatal( + ast_trait_ref.path.span, + fmt!("%s is not a trait", + path_to_str(ast_trait_ref.path, + ccx.tcx.sess.intr()))); + } + } +} - write_tpt_to_tcx(ccx.tcx, t.ref_id, &tpt); +fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::def_id) -> @ty::TraitDef { + if trait_id.crate != ast::local_crate { + ty::lookup_trait_def(ccx.tcx, trait_id) + } else { + match ccx.tcx.items.get(&trait_id.node) { + &ast_map::node_item(item, _) => trait_def_of_item(ccx, item), + _ => ccx.tcx.sess.bug(fmt!("get_trait_def(%d): not an item", + trait_id.node)) + } + } +} - match ty::get(tpt.ty).sty { - ty::ty_trait(*) => { - (t_id, tpt) - } - _ => sess.span_fatal(sp, err), +pub fn trait_def_of_item(ccx: &CrateCtxt, it: @ast::item) -> @ty::TraitDef { + let def_id = local_def(it.id); + let tcx = ccx.tcx; + match tcx.trait_defs.find(&def_id) { + Some(&def) => return def, + _ => {} + } + let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + match it.node { + ast::item_trait(ref generics, _, _) => { + let (ty_generics, substs) = mk_substs(ccx, generics, rp); + let trait_ref = @ty::TraitRef {def_id: def_id, + substs: substs}; + let trait_def = @ty::TraitDef {generics: ty_generics, + trait_ref: trait_ref}; + tcx.trait_defs.insert(def_id, trait_def); + return trait_def; + } + ref s => { + tcx.sess.span_bug( + it.span, + fmt!("trait_def_of_item invoked on %?", s)); } - } - _ => sess.span_fatal(sp, err) } } @@ -861,7 +936,8 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) return tpt; } ast::item_fn(ref decl, purity, _, ref generics, _) => { - let bounds = ty_param_bounds(ccx, generics); + assert!(rp.is_none()); + let ty_generics = ty_generics(ccx, None, generics); let tofd = astconv::ty_of_bare_fn(ccx, &empty_rscope, purity, @@ -869,8 +945,10 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) &generics.lifetimes, decl); let tpt = ty_param_bounds_and_ty { - bounds: bounds, - region_param: None, + generics: ty::Generics { + bounds: ty_generics.bounds, + region_param: None + }, ty: ty::mk_bare_fn(ccx.tcx, tofd) }; debug!("type of %s (id %d) is %s", @@ -901,8 +979,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) } }; ty_param_bounds_and_ty { - bounds: ty_param_bounds(ccx, generics), - region_param: rp, + generics: ty_generics(ccx, rp, generics), ty: ty } }; @@ -912,37 +989,26 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) } ast::item_enum(_, ref generics) => { // Create a new generic polytype. - let (bounds, substs) = mk_substs(ccx, generics, rp); + let (ty_generics, substs) = mk_substs(ccx, generics, rp); let t = ty::mk_enum(tcx, local_def(it.id), substs); let tpt = ty_param_bounds_and_ty { - bounds: bounds, - region_param: rp, + generics: ty_generics, ty: t }; tcx.tcache.insert(local_def(it.id), tpt); return tpt; } - ast::item_trait(ref generics, _, _) => { - let (bounds, substs) = mk_substs(ccx, generics, rp); - let t = ty::mk_trait(tcx, - local_def(it.id), - substs, - ty::BareTraitStore); - let tpt = ty_param_bounds_and_ty { - bounds: bounds, - region_param: rp, - ty: t - }; - tcx.tcache.insert(local_def(it.id), tpt); - return tpt; + ast::item_trait(*) => { + tcx.sess.span_bug( + it.span, + fmt!("Invoked ty_of_item on trait")); } ast::item_struct(_, ref generics) => { - let (bounds, substs) = mk_substs(ccx, generics, rp); + let (ty_generics, substs) = mk_substs(ccx, generics, rp); let t = ty::mk_struct(tcx, local_def(it.id), substs); let tpt = ty_param_bounds_and_ty { - bounds: bounds, - region_param: rp, - ty: t + generics: ty_generics, + ty: t }; tcx.tcache.insert(local_def(it.id), tpt); return tpt; @@ -964,76 +1030,82 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, it: @ast::foreign_item) } ast::foreign_item_const(t) => { ty::ty_param_bounds_and_ty { - bounds: @~[], - region_param: None, + generics: ty::Generics { + bounds: @~[], + region_param: None, + }, ty: ast_ty_to_ty(ccx, &empty_rscope, t) } } } } -// Translate the AST's notion of ty param bounds (which are an enum consisting -// of a newtyped Ty or a region) to ty's notion of ty param bounds, which can -// either be user-defined traits, or one of the four built-in traits (formerly -// known as kinds): Const, Copy, Durable, and Send. -pub fn compute_bounds(ccx: &CrateCtxt, - ast_bounds: @OptVec) - -> ty::param_bounds { - @ast_bounds.flat_map_to_vec(|b| { - match b { - &TraitTyParamBound(b) => { - let li = &ccx.tcx.lang_items; - let ity = ast_ty_to_ty(ccx, &empty_rscope, b); - match ty::get(ity).sty { - ty::ty_trait(did, _, _) => { - if did == li.owned_trait() { - ~[ty::bound_owned] - } else if did == li.copy_trait() { - ~[ty::bound_copy] - } else if did == li.const_trait() { - ~[ty::bound_const] - } else if did == li.durable_trait() { - ~[ty::bound_durable] - } else { - // Must be a user-defined trait - ~[ty::bound_trait(ity)] - } - } - _ => { - ccx.tcx.sess.span_err( - (*b).span, ~"type parameter bounds must be \ - trait types"); - ~[] - } +pub fn ty_generics(ccx: &CrateCtxt, + rp: Option, + generics: &ast::Generics) -> ty::Generics { + return ty::Generics { + region_param: rp, + bounds: @generics.ty_params.map_to_vec(|param| { + match ccx.tcx.ty_param_bounds.find(¶m.id) { + Some(&bs) => bs, + None => { + let bounds = compute_bounds(ccx, rp, generics, param.bounds); + ccx.tcx.ty_param_bounds.insert(param.id, bounds); + bounds } } - &RegionTyParamBound => ~[ty::bound_durable] - } - }) -} + }) + }; -pub fn ty_param_bounds(ccx: &CrateCtxt, - generics: &ast::Generics) - -> @~[ty::param_bounds] { - @do generics.ty_params.map_to_vec |param| { - match ccx.tcx.ty_param_bounds.find(¶m.id) { - Some(&bs) => bs, - None => { - let bounds = compute_bounds(ccx, param.bounds); - ccx.tcx.ty_param_bounds.insert(param.id, bounds); - bounds - } - } + fn compute_bounds( + ccx: &CrateCtxt, + rp: Option, + generics: &ast::Generics, + ast_bounds: @OptVec) -> ty::param_bounds + { + /*! + * + * Translate the AST's notion of ty param bounds (which are an + * enum consisting of a newtyped Ty or a region) to ty's + * notion of ty param bounds, which can either be user-defined + * traits, or one of the four built-in traits (formerly known + * as kinds): Const, Copy, Durable, and Send. + */ + + @ast_bounds.flat_map_to_vec(|b| { + match b { + &TraitTyParamBound(b) => { + let li = &ccx.tcx.lang_items; + let trait_ref = instantiate_trait_ref(ccx, b, rp, generics); + if trait_ref.def_id == li.owned_trait() { + ~[ty::bound_owned] + } else if trait_ref.def_id == li.copy_trait() { + ~[ty::bound_copy] + } else if trait_ref.def_id == li.const_trait() { + ~[ty::bound_const] + } else if trait_ref.def_id == li.durable_trait() { + ~[ty::bound_durable] + } else { + // Must be a user-defined trait + ~[ty::bound_trait(trait_ref)] + } + } + + &RegionTyParamBound => { + ~[ty::bound_durable] + } + } + }) } } pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, decl: &ast::fn_decl, def_id: ast::def_id, - generics: &ast::Generics) + ast_generics: &ast::Generics) -> ty::ty_param_bounds_and_ty { - let bounds = ty_param_bounds(ccx, generics); - let region_param_names = RegionParamNames::from_generics(generics); + let ty_generics = ty_generics(ccx, None, ast_generics); + let region_param_names = RegionParamNames::from_generics(ast_generics); let rb = in_binding_rscope(&empty_rscope, region_param_names); let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, &rb, *a, None) ); let output_ty = ast_ty_to_ty(ccx, &rb, decl.output); @@ -1048,33 +1120,24 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, output: output_ty} }); let tpt = ty_param_bounds_and_ty { - bounds: bounds, - region_param: None, + generics: ty_generics, ty: t_fn }; ccx.tcx.tcache.insert(def_id, tpt); return tpt; } -pub fn mk_generics(ccx: &CrateCtxt, generics: &ast::Generics) - -> (@~[ty::param_bounds], ~[ty::t]) -{ - let mut i = 0u; - let bounds = ty_param_bounds(ccx, generics); - (bounds, - generics.ty_params.map_to_vec(|atp| { - let t = ty::mk_param(ccx.tcx, i, local_def(atp.id)); - i += 1u; - t - })) -} - pub fn mk_substs(ccx: &CrateCtxt, - generics: &ast::Generics, - rp: Option) - -> (@~[ty::param_bounds], ty::substs) + ast_generics: &ast::Generics, + rp: Option) -> (ty::Generics, ty::substs) { - let (bounds, params) = mk_generics(ccx, generics); + let mut i = 0; + let ty_generics = ty_generics(ccx, rp, ast_generics); + let params = ast_generics.ty_params.map_to_vec(|atp| { + let t = ty::mk_param(ccx.tcx, i, local_def(atp.id)); + i += 1u; + t + }); let self_r = rscope::bound_self_region(rp); - (bounds, substs { self_r: self_r, self_ty: None, tps: params }) + (ty_generics, substs {self_r: self_r, self_ty: None, tps: params}) } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index add70b21e39a4..69c7b1d616b0a 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -90,7 +90,7 @@ pub trait Combine { fn tps(&self, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]>; fn self_tys(&self, a: Option, b: Option) -> cres>; - fn substs(&self, did: ast::def_id, as_: &ty::substs, + fn substs(&self, generics: &ty::Generics, as_: &ty::substs, bs: &ty::substs) -> cres; fn bare_fn_tys(&self, a: &ty::BareFnTy, b: &ty::BareFnTy) -> cres; @@ -114,6 +114,7 @@ pub trait Combine { a: ty::TraitStore, b: ty::TraitStore) -> cres; + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres; } pub struct CombineFields { @@ -192,32 +193,31 @@ pub fn eq_opt_regions( } pub fn super_substs( - self: &C, did: ast::def_id, + self: &C, generics: &ty::Generics, a: &ty::substs, b: &ty::substs) -> cres { fn relate_region_param( self: &C, - did: ast::def_id, + generics: &ty::Generics, a: Option, b: Option) -> cres> { - let polyty = ty::lookup_item_type(self.infcx().tcx, did); - match (polyty.region_param, a, b) { - (None, None, None) => { + match (&generics.region_param, &a, &b) { + (&None, &None, &None) => { Ok(None) } - (Some(ty::rv_invariant), Some(a), Some(b)) => { + (&Some(ty::rv_invariant), &Some(a), &Some(b)) => { do eq_regions(self, a, b).then { Ok(Some(a)) } } - (Some(ty::rv_covariant), Some(a), Some(b)) => { + (&Some(ty::rv_covariant), &Some(a), &Some(b)) => { do self.regions(a, b).chain |r| { Ok(Some(r)) } } - (Some(ty::rv_contravariant), Some(a), Some(b)) => { + (&Some(ty::rv_contravariant), &Some(a), &Some(b)) => { do self.contraregions(a, b).chain |r| { Ok(Some(r)) } @@ -233,14 +233,14 @@ pub fn super_substs( b had opt_region %s with variance %?", a.inf_str(self.infcx()), b.inf_str(self.infcx()), - polyty.region_param)); + generics.region_param)); } } } do self.tps(a.tps, b.tps).chain |tps| { do self.self_tys(a.self_ty, b.self_ty).chain |self_ty| { - do relate_region_param(self, did, + do relate_region_param(self, generics, a.self_r, b.self_r).chain |self_r| { Ok(substs { @@ -520,26 +520,29 @@ pub fn super_tys( (ty::ty_enum(a_id, ref a_substs), ty::ty_enum(b_id, ref b_substs)) if a_id == b_id => { - do self.substs(a_id, a_substs, b_substs).chain |substs| { - Ok(ty::mk_enum(tcx, a_id, substs)) - } + let type_def = ty::lookup_item_type(tcx, a_id); + do self.substs(&type_def.generics, a_substs, b_substs).chain |substs| { + Ok(ty::mk_enum(tcx, a_id, substs)) + } } (ty::ty_trait(a_id, ref a_substs, a_store), ty::ty_trait(b_id, ref b_substs, b_store)) if a_id == b_id => { - do self.substs(a_id, a_substs, b_substs).chain |substs| { - do self.trait_stores(ty::terr_trait, a_store, b_store).chain |s| { - Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s)) - } - } + let trait_def = ty::lookup_trait_def(tcx, a_id); + do self.substs(&trait_def.generics, a_substs, b_substs).chain |substs| { + do self.trait_stores(ty::terr_trait, a_store, b_store).chain |s| { + Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s)) + } + } } (ty::ty_struct(a_id, ref a_substs), ty::ty_struct(b_id, ref b_substs)) if a_id == b_id => { - do self.substs(a_id, a_substs, b_substs).chain |substs| { - Ok(ty::mk_struct(tcx, a_id, substs)) - } + let type_def = ty::lookup_item_type(tcx, a_id); + do self.substs(&type_def.generics, a_substs, b_substs).chain |substs| { + Ok(ty::mk_struct(tcx, a_id, substs)) + } } (ty::ty_box(ref a_mt), ty::ty_box(ref b_mt)) => { @@ -634,3 +637,25 @@ pub fn super_tys( Ok(ty::mk_mach_float(tcx, val)) } } + +pub fn super_trait_refs( + self: &C, a: &ty::TraitRef, b: &ty::TraitRef) -> cres +{ + // Different traits cannot be related + + // - NOTE in the future, expand out subtraits! + + if a.def_id != b.def_id { + Err(ty::terr_traits( + expected_found(self, a.def_id, b.def_id))) + } else { + let tcx = self.infcx().tcx; + let trait_def = ty::lookup_trait_def(tcx, a.def_id); + let substs = if_ok!(self.substs(&trait_def.generics, &a.substs, &b.substs)); + Ok(ty::TraitRef { + def_id: a.def_id, + substs: substs + }) + } +} + diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 9c8c8997ae087..43f2b0eaf7229 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -299,10 +299,11 @@ impl Combine for Glb { super_closure_tys(self, a, b) } - fn substs(&self, did: ast::def_id, + fn substs(&self, + generics: &ty::Generics, as_: &ty::substs, bs: &ty::substs) -> cres { - super_substs(self, did, as_, bs) + super_substs(self, generics, as_, bs) } fn tps(&self, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> { @@ -313,5 +314,9 @@ impl Combine for Glb { -> cres> { super_self_tys(self, a, b) } + + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres { + super_trait_refs(self, a, b) + } } diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 5a705c31c1239..7cf4d25c67024 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -244,10 +244,11 @@ impl Combine for Lub { super_args(self, a, b) } - fn substs(&self, did: ast::def_id, + fn substs(&self, + generics: &ty::Generics, as_: &ty::substs, bs: &ty::substs) -> cres { - super_substs(self, did, as_, bs) + super_substs(self, generics, as_, bs) } fn tps(&self, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> { @@ -258,4 +259,8 @@ impl Combine for Lub { -> cres> { super_self_tys(self, a, b) } + + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres { + super_trait_refs(self, a, b) + } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index d8093d571a111..58de0122c8c9b 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -265,7 +265,7 @@ use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::unify::{ValsAndBindings, Root}; use middle::typeck::isr_alist; use util::common::indent; -use util::ppaux::{bound_region_to_str, ty_to_str}; +use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str}; use core::cmp::Eq; use core::result::{Result, Ok, Err}; @@ -419,6 +419,23 @@ pub fn mk_eqty(cx: @mut InferCtxt, }.to_ures() } +pub fn mk_sub_trait_refs(cx: @mut InferCtxt, + a_is_expected: bool, + span: span, + a: &ty::TraitRef, + b: &ty::TraitRef) + -> ures +{ + debug!("mk_sub_trait_refs(%s <: %s)", + a.inf_str(cx), b.inf_str(cx)); + do indent { + do cx.commit { + let suber = cx.sub(a_is_expected, span); + suber.trait_refs(a, b) + } + }.to_ures() +} + pub fn mk_coercety(cx: @mut InferCtxt, a_is_expected: bool, span: span, @@ -700,6 +717,11 @@ pub impl InferCtxt { self.resolve_type_vars_if_possible(t)) } + fn trait_ref_to_str(@mut self, t: &ty::TraitRef) -> ~str { + let t = self.resolve_type_vars_in_trait_ref_if_possible(t); + trait_ref_to_str(self.tcx, &t) + } + fn resolve_type_vars_if_possible(@mut self, typ: ty::t) -> ty::t { match resolve_type(self, typ, resolve_nested_tvar | resolve_ivar) { result::Ok(new_type) => new_type, @@ -707,6 +729,31 @@ pub impl InferCtxt { } } + fn resolve_type_vars_in_trait_ref_if_possible(@mut self, + trait_ref: &ty::TraitRef) + -> ty::TraitRef + { + // make up a dummy type just to reuse/abuse the resolve machinery + let dummy0 = ty::mk_trait(self.tcx, + trait_ref.def_id, + copy trait_ref.substs, + ty::UniqTraitStore); + let dummy1 = self.resolve_type_vars_if_possible(dummy0); + match ty::get(dummy1).sty { + ty::ty_trait(ref def_id, ref substs, _) => { + ty::TraitRef {def_id: *def_id, + substs: copy *substs} + } + _ => { + self.tcx.sess.bug( + fmt!("resolve_type_vars_if_possible() yielded %s \ + when supplied with %s", + self.ty_to_str(dummy0), + self.ty_to_str(dummy1))); + } + } + } + fn type_error_message(@mut self, sp: span, mk_msg: &fn(~str) -> ~str, actual_ty: ty::t, err: Option<&ty::type_err>) { let actual_ty = self.resolve_type_vars_if_possible(actual_ty); diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 161905c12e5dd..2e1be2c380f8f 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -256,10 +256,11 @@ impl Combine for Sub { super_args(self, a, b) } - fn substs(&self, did: ast::def_id, + fn substs(&self, + generics: &ty::Generics, as_: &ty::substs, bs: &ty::substs) -> cres { - super_substs(self, did, as_, bs) + super_substs(self, generics, as_, bs) } fn tps(&self, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> { @@ -270,5 +271,9 @@ impl Combine for Sub { -> cres> { super_self_tys(self, a, b) } + + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres { + super_trait_refs(self, a, b) + } } diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs index 559d29e66efba..d4959961f12ce 100644 --- a/src/librustc/middle/typeck/infer/to_str.rs +++ b/src/librustc/middle/typeck/infer/to_str.rs @@ -16,7 +16,7 @@ use middle::ty; use middle::typeck::infer::{Bound, Bounds}; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::unify::{Redirect, Root, VarValue}; -use util::ppaux::{mt_to_str, ty_to_str}; +use util::ppaux::{mt_to_str, ty_to_str, trait_ref_to_str}; use syntax::ast; @@ -91,3 +91,9 @@ impl InferStr for ast::float_ty { self.to_str() } } + +impl InferStr for ty::TraitRef { + fn inf_str(&self, cx: &InferCtxt) -> ~str { + trait_ref_to_str(cx.tcx, self) + } +} diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index d829b0d2a0d51..d3502adb33ab8 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -222,8 +222,8 @@ pub fn lookup_def_ccx(ccx: @mut CrateCtxt, sp: span, id: ast::node_id) pub fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty { - bounds: @~[], - region_param: None, + generics: ty::Generics {bounds: @~[], + region_param: None}, ty: t } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index afbf3f485d0ae..cdeb12b80f448 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -239,7 +239,6 @@ pub fn vstore_to_str(cx: ctxt, vs: ty::vstore) -> ~str { pub fn trait_store_to_str(cx: ctxt, s: ty::TraitStore) -> ~str { match s { - ty::BareTraitStore => ~"", ty::UniqTraitStore => ~"~", ty::BoxTraitStore => ~"@", ty::RegionTraitStore(r) => region_to_str_space(cx, "&", r) @@ -285,6 +284,12 @@ pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str { ty_to_str(cx, typ.output)) } +pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str { + let path = ty::item_path(cx, trait_ref.def_id); + let base = ast_map::path_to_str(path, cx.sess.intr()); + parameterized(cx, base, trait_ref.substs.self_r, trait_ref.substs.tps) +} + pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { fn fn_input_to_str(cx: ctxt, input: ty::arg) -> ~str { let ty::arg {mode: mode, ty: ty} = input; @@ -443,7 +448,7 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { str::from_bytes(~[('a' as u8) + (id as u8)])) } } - ty_self(*) => ~"self", + ty_self(*) => ~"Self", ty_enum(did, ref substs) | ty_struct(did, ref substs) => { let path = ty::item_path(cx, did); let base = ast_map::path_to_str(path, cx.sess.intr()); diff --git a/src/librustdoc/prune_private_pass.rs b/src/librustdoc/prune_private_pass.rs index a1f8fdb75d9ea..08008ab2bcae0 100644 --- a/src/librustdoc/prune_private_pass.rs +++ b/src/librustdoc/prune_private_pass.rs @@ -117,7 +117,7 @@ fn fold_mod( !doc.methods.is_empty() } else { // This is a trait implementation, make it visible - // NOTE: This is not quite right since this could be an impl + // NB: This is not quite right since this could be an impl // of a private trait. We can't know that without running // resolve though. true diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2e7ae4c537a8c..ec77b54a85371 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -144,7 +144,7 @@ pub static crate_node_id: node_id = 0; // the "special" built-in traits (see middle::lang_items) and // detects Copy, Send, Owned, and Const. pub enum TyParamBound { - TraitTyParamBound(@Ty), + TraitTyParamBound(@trait_ref), RegionTyParamBound } @@ -194,6 +194,7 @@ pub enum def { def_local(node_id, bool /* is_mutbl */), def_variant(def_id /* enum */, def_id /* variant */), def_ty(def_id), + def_trait(def_id), def_prim_ty(prim_ty), def_ty_param(def_id, uint), def_binding(node_id, binding_mode), @@ -1185,6 +1186,15 @@ pub struct trait_ref { #[deriving(Eq)] pub enum visibility { public, private, inherited } +impl visibility { + fn inherit_from(&self, parent_visibility: visibility) -> visibility { + match self { + &inherited => parent_visibility, + &public | &private => *self + } + } +} + #[auto_encode] #[auto_decode] #[deriving(Eq)] diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 208ed1e35fe1a..c7227fa17687c 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -61,7 +61,7 @@ pub fn def_id_of_def(d: def) -> def_id { def_fn(id, _) | def_static_method(id, _, _) | def_mod(id) | def_foreign_mod(id) | def_const(id) | def_variant(_, id) | def_ty(id) | def_ty_param(id, _) | - def_use(id) | def_struct(id) => { + def_use(id) | def_struct(id) | def_trait(id) => { id } def_arg(id, _, _) | def_local(id, _) | def_self(id, _) | def_self_ty(id) diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index d25792355a718..97bc89248acf2 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -222,15 +222,14 @@ pub fn expand_auto_decode( priv impl @ext_ctxt { fn bind_path( &self, - span: span, + _span: span, ident: ast::ident, path: @ast::path, bounds: @OptVec ) -> ast::TyParam { - let bound = ast::TraitTyParamBound(@ast::Ty { - id: self.next_id(), - node: ast::ty_path(path, self.next_id()), - span: span, + let bound = ast::TraitTyParamBound(@ast::trait_ref { + ref_id: self.next_id(), + path: path }); ast::TyParam { @@ -466,10 +465,9 @@ fn mk_impl( // All the type parameters need to bound to the trait. let mut impl_tps = opt_vec::with(ty_param); for generics.ty_params.each |tp| { - let t_bound = ast::TraitTyParamBound(@ast::Ty { - id: cx.next_id(), - node: ast::ty_path(path, cx.next_id()), - span: span, + let t_bound = ast::TraitTyParamBound(@ast::trait_ref { + path: path, + ref_id: cx.next_id(), }); impl_tps.push(ast::TyParam { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 9499f95f0e76f..43f0c9edcb964 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -337,6 +337,17 @@ pub fn mk_ty_path_global(cx: @ext_ctxt, let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span }; ty } +pub fn mk_trait_ref_global(cx: @ext_ctxt, + span: span, + +idents: ~[ ast::ident ]) + -> @ast::trait_ref +{ + let path = build::mk_raw_path_global(span, idents); + @ast::trait_ref { + path: path, + ref_id: cx.next_id() + } +} pub fn mk_simple_ty_path(cx: @ext_ctxt, span: span, ident: ast::ident) diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 18ebceaeb4396..ccd9a33757dd5 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -177,9 +177,9 @@ pub fn create_derived_impl(cx: @ext_ctxt, // Create the type parameters. let impl_ty_params = generics.ty_params.map(|ty_param| { - let bound = build::mk_ty_path_global(cx, - span, - trait_path.map(|x| *x)); + let bound = build::mk_trait_ref_global(cx, + span, + trait_path.map(|x| *x)); let bounds = @opt_vec::with(TraitTyParamBound(bound)); build::mk_ty_param(cx, ty_param.ident, bounds) }); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 0a473b1cebeaf..5aa51c262e174 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -134,7 +134,7 @@ pub fn fold_fn_decl(decl: &ast::fn_decl, fld: @ast_fold) -> ast::fn_decl { fn fold_ty_param_bound(tpb: &TyParamBound, fld: @ast_fold) -> TyParamBound { match *tpb { - TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_ty(ty)), + TraitTyParamBound(ty) => TraitTyParamBound(fold_trait_ref(ty, fld)), RegionTyParamBound => RegionTyParamBound } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1d780c9b80698..3a3597828cd24 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2750,8 +2750,8 @@ pub impl Parser { self.bump(); } token::MOD_SEP | token::IDENT(*) => { - let maybe_bound = match *self.token { - token::MOD_SEP => None, + let obsolete_bound = match *self.token { + token::MOD_SEP => false, token::IDENT(copy sid, _) => { match *self.id_to_str(sid) { ~"send" | @@ -2761,27 +2761,18 @@ pub impl Parser { self.obsolete( *self.span, ObsoleteLowerCaseKindBounds); - - // Bogus value, but doesn't matter, since - // is an error - Some(TraitTyParamBound( - self.mk_ty_path(sid))) + self.bump(); + true } - _ => None + _ => false } } _ => fail!() }; - match maybe_bound { - Some(bound) => { - self.bump(); - result.push(bound); - } - None => { - let ty = self.parse_ty(true); - result.push(TraitTyParamBound(ty)); - } + if !obsolete_bound { + let tref = self.parse_trait_ref(); + result.push(TraitTyParamBound(tref)); } } _ => break, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0c79cbca039a6..20fc99baf2179 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -562,7 +562,7 @@ pub fn print_item(s: @ps, &&item: @ast::item) { match opt_trait { Some(t) => { - print_path(s, t.path, false); + print_trait_ref(s, t); space(s.s); word_space(s, ~"for"); } @@ -619,6 +619,10 @@ pub fn print_item(s: @ps, &&item: @ast::item) { (s.ann.post)(ann_node); } +fn print_trait_ref(s: @ps, t: &ast::trait_ref) { + print_path(s, t.path, false); +} + pub fn print_enum_def(s: @ps, enum_definition: ast::enum_def, generics: &ast::Generics, ident: ast::ident, span: codemap::span, visibility: ast::visibility) { @@ -1744,7 +1748,7 @@ pub fn print_bounds(s: @ps, bounds: @OptVec) { } match *bound { - TraitTyParamBound(ty) => print_type(s, ty), + TraitTyParamBound(tref) => print_trait_ref(s, tref), RegionTyParamBound => word(s.s, ~"'static"), } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a994f2b5b2280..b20c5eeee1f04 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -147,6 +147,10 @@ pub fn visit_local(loc: @local, e: E, v: vt) { } } +fn visit_trait_ref(tref: @ast::trait_ref, e: E, v: vt) { + visit_path(tref.path, e, v); +} + pub fn visit_item(i: @item, e: E, v: vt) { match i.node { item_const(t, ex) => { @@ -189,9 +193,9 @@ pub fn visit_item(i: @item, e: E, v: vt) { } item_impl(ref tps, ref traits, ty, ref methods) => { (v.visit_generics)(tps, e, v); - for traits.each |p| { - visit_path(p.path, e, v); - } + for traits.each |&p| { + visit_trait_ref(p, e, v); + } (v.visit_ty)(ty, e, v); for methods.each |m| { visit_method_helper(*m, e, v) @@ -327,8 +331,8 @@ pub fn visit_ty_param_bounds(bounds: @OptVec, e: E, v: vt) { for bounds.each |bound| { match *bound { - TraitTyParamBound(ty) => (v.visit_ty)(ty, e, v), - RegionTyParamBound => () + TraitTyParamBound(ty) => visit_trait_ref(ty, e, v), + RegionTyParamBound => {} } } } diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp index 2b86db6defe09..32723cf31bc6f 100644 --- a/src/rt/rust_log.cpp +++ b/src/rt/rust_log.cpp @@ -314,7 +314,7 @@ void update_log_settings(void* crate_map, char* settings) { n_dirs, &n_matches); if (n_matches < n_dirs) { - // NOTE: Android compiler is complaining about format specifiers here + // NB: Android compiler is complaining about format specifiers here // and I don't understand why /*printf("warning: got %" PRIdPTR " RUST_LOG specs, " "enabled %" PRIdPTR " flags.", diff --git a/src/test/compile-fail/extern-no-call.rs b/src/test/compile-fail/extern-no-call.rs index 8c6deb3481674..58649f3209bb1 100644 --- a/src/test/compile-fail/extern-no-call.rs +++ b/src/test/compile-fail/extern-no-call.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:expected function or foreign function but found `*u8` +// error-pattern:expected function but found `*u8` extern fn f() { } diff --git a/src/test/compile-fail/issue-2330.rs b/src/test/compile-fail/issue-2330.rs index d8acbf2893aa5..6152e82294d1b 100644 --- a/src/test/compile-fail/issue-2330.rs +++ b/src/test/compile-fail/issue-2330.rs @@ -15,7 +15,7 @@ trait channel { } // `chan` is not a trait, it's an enum -impl chan for int { //~ ERROR can only implement trait types +impl chan for int { //~ ERROR chan is not a trait fn send(&self, v: int) { fail!() } } diff --git a/src/test/compile-fail/issue-3563.rs b/src/test/compile-fail/issue-3563.rs index 0388f0fd29083..d56cb0d51d234 100644 --- a/src/test/compile-fail/issue-3563.rs +++ b/src/test/compile-fail/issue-3563.rs @@ -10,7 +10,7 @@ trait A { fn a(&self) { - || self.b() //~ ERROR type `&'self self` does not implement any method in scope named `b` + || self.b() //~ ERROR type `&'self Self` does not implement any method in scope named `b` } } fn main() {} diff --git a/src/test/compile-fail/selftype-traittype.rs b/src/test/compile-fail/selftype-traittype.rs index 467154244b760..220573660c5b0 100644 --- a/src/test/compile-fail/selftype-traittype.rs +++ b/src/test/compile-fail/selftype-traittype.rs @@ -12,7 +12,7 @@ trait add { fn plus(&self, x: Self) -> Self; } -fn do_add(x: add, y: add) -> add { +fn do_add(x: @add, y: @add) -> @add { x.plus(y) //~ ERROR cannot call a method whose type contains a self-type through a boxed trait } diff --git a/src/test/run-pass/issue-3702.rs b/src/test/run-pass/issue-3702.rs index eaa2ac4c4baf2..7c2f8cf98cb8a 100644 --- a/src/test/run-pass/issue-3702.rs +++ b/src/test/run-pass/issue-3702.rs @@ -13,7 +13,7 @@ pub fn main() { fn to_str(&self) -> ~str; } - fn to_string(t: Text) { + fn to_string(t: @Text) { io::println(t.to_str()); } diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index 565c06fb8c890..a27599e6ed00a 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -417,9 +417,9 @@ impl TyVisitor for ptr_visit_adaptor { } fn visit_trait(&self) -> bool { - self.align_to::(); + self.align_to::<@TyVisitor>(); if ! self.inner.visit_trait() { return false; } - self.bump_past::(); + self.bump_past::<@TyVisitor>(); true } diff --git a/src/test/run-pass/region-dependent-addr-of.rs b/src/test/run-pass/region-dependent-addr-of.rs index 42784200b6639..dd33f7f1e309b 100644 --- a/src/test/run-pass/region-dependent-addr-of.rs +++ b/src/test/run-pass/region-dependent-addr-of.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test lifetimes are linked properly when we create dependent region pointers. +// Issue #3148. + struct A { value: B } diff --git a/src/test/run-pass/region-dependent-autofn.rs b/src/test/run-pass/region-dependent-autofn.rs new file mode 100644 index 0000000000000..82d4115d66d9f --- /dev/null +++ b/src/test/run-pass/region-dependent-autofn.rs @@ -0,0 +1,22 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test lifetimes are linked properly when we autoslice a vector. +// Issue #3148. + +fn subslice<'r>(v: &'r fn()) -> &'r fn() { v } + +fn both<'r>(v: &'r fn()) -> &'r fn() { + subslice(subslice(v)) +} + +fn main() { + both(main); +} diff --git a/src/test/run-pass/region-dependent-autoslice.rs b/src/test/run-pass/region-dependent-autoslice.rs new file mode 100644 index 0000000000000..10c2988fc9f26 --- /dev/null +++ b/src/test/run-pass/region-dependent-autoslice.rs @@ -0,0 +1,23 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test lifetimes are linked properly when we autoslice a vector. +// Issue #3148. + +fn subslice1<'r>(v: &'r [uint]) -> &'r [uint] { v } + +fn both<'r>(v: &'r [uint]) -> &'r [uint] { + subslice1(subslice1(v)) +} + +fn main() { + let v = ~[1,2,3]; + both(v); +} diff --git a/src/test/run-pass/regions-expl-self.rs b/src/test/run-pass/regions-expl-self.rs index 05f0994c7655d..174b9a206ccdf 100644 --- a/src/test/run-pass/regions-expl-self.rs +++ b/src/test/run-pass/regions-expl-self.rs @@ -15,7 +15,7 @@ struct Foo { } pub impl Foo { - fn foo(&'a self) {} + fn foo<'a>(&'a self) {} } pub fn main() {} \ No newline at end of file