diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index b34829bf47fc..c2d0251b23cc 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -116,12 +116,12 @@ impl fold::ast_fold for StandardLibraryInjector { segments: ~[ ast::PathSegment { identifier: self.sess.ident_of("std"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, ast::PathSegment { identifier: self.sess.ident_of("prelude"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, ], diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 9541a03aff25..b6ae41833777 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -343,7 +343,7 @@ fn path_node(ids: ~[ast::Ident]) -> ast::Path { global: false, segments: ids.move_iter().map(|identifier| ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }).collect() } @@ -355,7 +355,7 @@ fn path_node_global(ids: ~[ast::Ident]) -> ast::Path { global: true, segments: ids.move_iter().map(|identifier| ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }).collect() } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index ba27b5a5f41b..f2f200affe80 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -53,8 +53,10 @@ use syntax::diagnostic; pub mod middle { pub mod trans; pub mod ty; + pub mod ty_fold; pub mod subst; pub mod resolve; + pub mod resolve_lifetime; pub mod typeck; pub mod check_loop; pub mod check_match; diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 6294b6cb6e31..05d40bbb6aea 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -193,6 +193,11 @@ pub static tag_path_elt_pretty_name: uint = 0x87; pub static tag_path_elt_pretty_name_ident: uint = 0x88; pub static tag_path_elt_pretty_name_extra: uint = 0x89; +pub static tag_region_param_def: uint = 0x100; +pub static tag_region_param_def_ident: uint = 0x101; +pub static tag_region_param_def_def_id: uint = 0x102; + + pub struct LinkMeta { name: @str, vers: @str, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 48fe21b33439..436b4c3df6be 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -199,12 +199,6 @@ pub fn get_trait_def(tcx: ty::ctxt, def: ast::DefId) -> ty::TraitDef { decoder::get_trait_def(cdata, def.node, tcx) } -pub fn get_region_param(cstore: @mut metadata::cstore::CStore, - def: ast::DefId) -> Option { - let cdata = cstore::get_crate_data(cstore, def.crate); - return decoder::get_region_param(cdata, def.node); -} - pub fn get_field_type(tcx: ty::ctxt, class_id: ast::DefId, def: ast::DefId) -> ty::ty_param_bounds_and_ty { let cstore = tcx.cstore; @@ -224,7 +218,7 @@ pub fn get_field_type(tcx: ty::ctxt, class_id: ast::DefId, let ty = decoder::item_type(def, the_field, tcx, cdata); ty::ty_param_bounds_and_ty { generics: ty::Generics {type_param_defs: @~[], - region_param: None}, + region_param_defs: @[]}, ty: ty } } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 56abaa27cce2..3b4e29c97c01 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -25,7 +25,7 @@ use middle::ty; use middle::typeck; use middle::astencode::vtable_decoder_helpers; - +use std::at_vec; use std::u64; use std::rt::io; use std::rt::io::extensions::u64_from_be_bytes; @@ -252,9 +252,11 @@ fn item_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: Cmd) -> ty::TraitRef { doc_trait_ref(tp, tcx, cdata) } -fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: Cmd, +fn item_ty_param_defs(item: ebml::Doc, + tcx: ty::ctxt, + cdata: Cmd, tag: uint) - -> @~[ty::TypeParameterDef] { + -> @~[ty::TypeParameterDef] { let mut bounds = ~[]; do reader::tagged_docs(item, tag) |p| { let bd = parse_type_param_def_data( @@ -266,10 +268,23 @@ fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: Cmd, @bounds } -fn item_ty_region_param(item: ebml::Doc) -> Option { - do reader::maybe_get_doc(item, tag_region_param).map |doc| { - let mut decoder = reader::Decoder(doc); - Decodable::decode(&mut decoder) +fn item_region_param_defs(item_doc: ebml::Doc, + tcx: ty::ctxt, + cdata: Cmd) + -> @[ty::RegionParameterDef] { + do at_vec::build(None) |push| { + do reader::tagged_docs(item_doc, tag_region_param_def) |rp_doc| { + let ident_str_doc = reader::get_doc(rp_doc, + tag_region_param_def_ident); + let ident = item_name(tcx.sess.intr(), ident_str_doc); + let def_id_doc = reader::get_doc(rp_doc, + tag_region_param_def_def_id); + let def_id = reader::with_doc_data(def_id_doc, parse_def_id); + let def_id = translate_def_id(cdata, def_id); + push(ty::RegionParameterDef { ident: ident, + def_id: def_id }); + true + }; } } @@ -393,7 +408,7 @@ pub fn get_trait_def(cdata: Cmd, let item_doc = lookup_item(item_id, cdata.data); let tp_defs = item_ty_param_defs(item_doc, tcx, cdata, tag_items_data_item_ty_param_bounds); - let rp = item_ty_region_param(item_doc); + let rp_defs = item_region_param_defs(item_doc, tcx, cdata); let mut bounds = ty::EmptyBuiltinBounds(); // Collect the builtin bounds from the encoded supertraits. // FIXME(#8559): They should be encoded directly. @@ -407,7 +422,7 @@ pub fn get_trait_def(cdata: Cmd, }; ty::TraitDef { generics: ty::Generics {type_param_defs: tp_defs, - region_param: rp}, + region_param_defs: rp_defs}, bounds: bounds, trait_ref: @item_trait_ref(item_doc, tcx, cdata) } @@ -417,33 +432,27 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt) -> ty::ty_param_bounds_and_ty { let item = lookup_item(id, cdata.data); + let t = item_type(ast::DefId { crate: cdata.cnum, node: id }, item, tcx, cdata); - let tp_defs = if family_has_type_params(item_family(item)) { - item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds) - } else { @~[] }; - let rp = item_ty_region_param(item); + + let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds); + let rp_defs = item_region_param_defs(item, tcx, cdata); + ty::ty_param_bounds_and_ty { generics: ty::Generics {type_param_defs: tp_defs, - region_param: rp}, + region_param_defs: rp_defs}, ty: t } } -pub fn get_region_param(cdata: Cmd, id: ast::NodeId) - -> Option { - - let item = lookup_item(id, cdata.data); - return item_ty_region_param(item); -} - pub fn get_type_param_count(data: @~[u8], id: ast::NodeId) -> uint { item_ty_param_count(lookup_item(id, data)) } pub fn get_impl_trait(cdata: Cmd, - id: ast::NodeId, - tcx: ty::ctxt) -> Option<@ty::TraitRef> + id: ast::NodeId, + tcx: ty::ctxt) -> Option<@ty::TraitRef> { let item_doc = lookup_item(id, cdata.data); do reader::maybe_get_doc(item_doc, tag_item_trait_ref).map |tp| { @@ -1044,6 +1053,7 @@ pub fn get_method(intr: @ident_interner, cdata: Cmd, id: ast::NodeId, let name = item_name(intr, method_doc); let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata, tag_item_method_tps); + let rp_defs = item_region_param_defs(method_doc, tcx, cdata); 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); @@ -1054,7 +1064,7 @@ pub fn get_method(intr: @ident_interner, cdata: Cmd, id: ast::NodeId, name, ty::Generics { type_param_defs: type_param_defs, - region_param: None + region_param_defs: rp_defs, }, transformed_self_ty, fty, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 1ad7e416342f..76c49da5861e 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -121,17 +121,6 @@ pub fn encode_def_id(ebml_w: &mut writer::Encoder, id: DefId) { ebml_w.wr_tagged_str(tag_def_id, def_to_str(id)); } -fn encode_region_param(ecx: &EncodeContext, - ebml_w: &mut writer::Encoder, - it: @ast::item) { - let opt_rp = ecx.tcx.region_paramd_items.find(&it.id); - for rp in opt_rp.iter() { - ebml_w.start_tag(tag_region_param); - rp.encode(ebml_w); - ebml_w.end_tag(); - } -} - #[deriving(Clone)] struct entry { val: T, @@ -205,11 +194,29 @@ fn encode_ty_type_param_defs(ebml_w: &mut writer::Encoder, } } +fn encode_region_param_defs(ebml_w: &mut writer::Encoder, + ecx: &EncodeContext, + params: @[ty::RegionParameterDef]) { + for param in params.iter() { + ebml_w.start_tag(tag_region_param_def); + + ebml_w.start_tag(tag_region_param_def_ident); + encode_name(ecx, ebml_w, param.ident); + ebml_w.end_tag(); + + ebml_w.wr_tagged_str(tag_region_param_def_def_id, + def_to_str(param.def_id)); + + ebml_w.end_tag(); + } +} + fn encode_bounds_and_type(ebml_w: &mut writer::Encoder, ecx: &EncodeContext, tpt: &ty::ty_param_bounds_and_ty) { encode_ty_type_param_defs(ebml_w, ecx, tpt.generics.type_param_defs, tag_items_data_item_ty_param_bounds); + encode_region_param_defs(ebml_w, ecx, tpt.generics.region_param_defs); encode_type(ecx, ebml_w, tpt.ty); } @@ -976,7 +983,6 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id)); encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); encode_visibility(ebml_w, vis); ebml_w.end_tag(); } @@ -994,7 +1000,6 @@ fn encode_info_for_item(ecx: &EncodeContext, } (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); // Encode inherent implementations for this enumeration. encode_inherent_implementations(ecx, ebml_w, def_id); @@ -1030,7 +1035,6 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); encode_visibility(ebml_w, vis); /* Encode def_ids for each field and method @@ -1075,7 +1079,6 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); encode_family(ebml_w, 'i'); - encode_region_param(ecx, ebml_w, item); encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id)); encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); @@ -1135,7 +1138,6 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); encode_family(ebml_w, 'I'); - encode_region_param(ecx, ebml_w, item); let trait_def = ty::lookup_trait_def(tcx, def_id); encode_ty_type_param_defs(ebml_w, ecx, trait_def.generics.type_param_defs, diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index b365e7a48795..1636205c76d6 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -48,7 +48,10 @@ pub enum DefIdSource { TypeWithId, // Identifies a type parameter (`fn foo() { ... }`). - TypeParameter + TypeParameter, + + // Identifies a region parameter (`fn foo<'X>() { ... }`). + RegionParameter, } type conv_did<'self> = &'self fn(source: DefIdSource, ast::DefId) -> ast::DefId; @@ -143,7 +146,7 @@ fn parse_path(st: &mut PState) -> @ast::Path { segments: idents.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -165,7 +168,7 @@ fn parse_sigil(st: &mut PState) -> ast::Sigil { } } -fn parse_vstore(st: &mut PState) -> ty::vstore { +fn parse_vstore(st: &mut PState, conv: conv_did) -> ty::vstore { assert_eq!(next(st), '/'); let c = peek(st); @@ -178,22 +181,22 @@ fn parse_vstore(st: &mut PState) -> ty::vstore { match next(st) { '~' => ty::vstore_uniq, '@' => ty::vstore_box, - '&' => ty::vstore_slice(parse_region(st)), + '&' => ty::vstore_slice(parse_region(st, conv)), c => st.tcx.sess.bug(format!("parse_vstore(): bad input '{}'", c)) } } -fn parse_trait_store(st: &mut PState) -> ty::TraitStore { +fn parse_trait_store(st: &mut PState, conv: conv_did) -> ty::TraitStore { match next(st) { '~' => ty::UniqTraitStore, '@' => ty::BoxTraitStore, - '&' => ty::RegionTraitStore(parse_region(st)), + '&' => ty::RegionTraitStore(parse_region(st, conv)), c => st.tcx.sess.bug(format!("parse_trait_store(): bad input '{}'", c)) } } fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs { - let regions = parse_region_substs(st); + let regions = parse_region_substs(st, |x,y| conv(x,y)); let self_ty = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)) ); @@ -209,13 +212,13 @@ fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs { }; } -fn parse_region_substs(st: &mut PState) -> ty::RegionSubsts { +fn parse_region_substs(st: &mut PState, conv: conv_did) -> ty::RegionSubsts { match next(st) { 'e' => ty::ErasedRegions, 'n' => { let mut regions = opt_vec::Empty; while peek(st) != '.' { - let r = parse_region(st); + let r = parse_region(st, |x,y| conv(x,y)); regions.push(r); } assert_eq!(next(st), '.'); @@ -225,34 +228,51 @@ fn parse_region_substs(st: &mut PState) -> ty::RegionSubsts { } } -fn parse_bound_region(st: &mut PState) -> ty::bound_region { +fn parse_bound_region(st: &mut PState, conv: conv_did) -> ty::bound_region { match next(st) { - 's' => ty::br_self, - 'a' => { - let id = parse_uint(st); - assert_eq!(next(st), '|'); - ty::br_anon(id) - } - '[' => ty::br_named(st.tcx.sess.ident_of(parse_str(st, ']'))), - 'c' => { - let id = parse_uint(st) as int; - assert_eq!(next(st), '|'); - ty::br_cap_avoid(id, @parse_bound_region(st)) - }, - _ => fail!("parse_bound_region: bad input") + 'a' => { + let id = parse_uint(st); + assert_eq!(next(st), '|'); + ty::br_anon(id) + } + '[' => { + let def = parse_def(st, RegionParameter, |x,y| conv(x,y)); + let ident = st.tcx.sess.ident_of(parse_str(st, ']')); + ty::br_named(def, ident) + } + 'f' => { + let id = parse_uint(st); + assert_eq!(next(st), '|'); + ty::br_fresh(id) + } + _ => fail!("parse_bound_region: bad input") } } -fn parse_region(st: &mut PState) -> ty::Region { +fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { match next(st) { 'b' => { - ty::re_bound(parse_bound_region(st)) + assert_eq!(next(st), '['); + let id = parse_uint(st) as int; + assert_eq!(next(st), '|'); + let br = parse_bound_region(st, |x,y| conv(x,y)); + assert_eq!(next(st), ']'); + ty::re_fn_bound(id, br) + } + 'B' => { + assert_eq!(next(st), '['); + let node_id = parse_uint(st) as int; + assert_eq!(next(st), '|'); + let index = parse_uint(st); + assert_eq!(next(st), '|'); + let nm = st.tcx.sess.ident_of(parse_str(st, ']')); + ty::re_type_bound(node_id, index, nm) } 'f' => { assert_eq!(next(st), '['); let id = parse_uint(st) as int; assert_eq!(next(st), '|'); - let br = parse_bound_region(st); + let br = parse_bound_region(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); ty::re_free(ty::FreeRegion {scope_id: id, bound_region: br}) @@ -331,14 +351,14 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { assert_eq!(next(st), '['); let def = parse_def(st, NominalType, |x,y| conv(x,y)); let substs = parse_substs(st, |x,y| conv(x,y)); - let store = parse_trait_store(st); + let store = parse_trait_store(st, |x,y| conv(x,y)); let mt = parse_mutability(st); let bounds = parse_bounds(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_trait(st.tcx, def, substs, store, mt, bounds.builtin_bounds); } 'p' => { - let did = parse_def(st, TypeParameter, conv); + let did = parse_def(st, TypeParameter, |x,y| conv(x,y)); debug!("parsed ty_param: did={:?}", did); return ty::mk_param(st.tcx, parse_uint(st), did); } @@ -356,12 +376,12 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { } 'U' => return ty::mk_unboxed_vec(st.tcx, parse_mt(st, conv)), 'V' => { - let mt = parse_mt(st, conv); - let v = parse_vstore(st); + let mt = parse_mt(st, |x,y| conv(x,y)); + let v = parse_vstore(st, |x,y| conv(x,y)); return ty::mk_evec(st.tcx, mt, v); } 'v' => { - let v = parse_vstore(st); + let v = parse_vstore(st, |x,y| conv(x,y)); return ty::mk_estr(st.tcx, v); } 'T' => { @@ -495,7 +515,7 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy { let sigil = parse_sigil(st); let purity = parse_purity(next(st)); let onceness = parse_onceness(next(st)); - let region = parse_region(st); + let region = parse_region(st, |x,y| conv(x,y)); let bounds = parse_bounds(st, |x,y| conv(x,y)); let sig = parse_sig(st, |x,y| conv(x,y)); ty::ClosureTy { @@ -511,7 +531,7 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy { fn parse_bare_fn_ty(st: &mut PState, conv: conv_did) -> ty::BareFnTy { let purity = parse_purity(next(st)); let abi = parse_abi_set(st); - let sig = parse_sig(st, conv); + let sig = parse_sig(st, |x,y| conv(x,y)); ty::BareFnTy { purity: purity, abis: abi, @@ -521,22 +541,22 @@ fn parse_bare_fn_ty(st: &mut PState, conv: conv_did) -> ty::BareFnTy { fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig { assert_eq!(next(st), '['); + let id = parse_uint(st) as int; + assert_eq!(next(st), '|'); let mut inputs = ~[]; while peek(st) != ']' { inputs.push(parse_ty(st, |x,y| conv(x,y))); } st.pos += 1u; // eat the ']' - let variadic = if peek(st) == 'A' { - st.pos += 1; // eat the 'A' - true - } else { false }; - let ret_ty = parse_ty(st, conv); - ty::FnSig { - bound_lifetime_names: opt_vec::Empty, // FIXME(#4846) - inputs: inputs, - output: ret_ty, - variadic: variadic - } + let variadic = match next(st) { + 'V' => true, + 'N' => false, + }; + let ret_ty = parse_ty(st, |x,y| conv(x,y)); + ty::FnSig {binder_id: id, + inputs: inputs, + output: ret_ty, + variadic: variadic} } // Rust metadata parsing diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 5397bf0e768d..af28162dbfd5 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -155,18 +155,31 @@ fn enc_region_substs(w: @mut MemWriter, cx: @ctxt, substs: &ty::RegionSubsts) { fn enc_region(w: @mut MemWriter, cx: @ctxt, r: ty::Region) { match r { - ty::re_bound(br) => { - mywrite!(w, "b"); + ty::re_fn_bound(id, br) => { + mywrite!(w, "b[{}|", id); enc_bound_region(w, cx, br); + mywrite!(w, "]"); + } + ty::re_type_bound(node_id, index, ident) => { + mywrite!(w, "B[{}|{}|{}]", + node_id, + index, + cx.tcx.sess.str_of(ident)); } ty::re_free(ref fr) => { mywrite!(w, "f[{}|", fr.scope_id); enc_bound_region(w, cx, fr.bound_region); mywrite!(w, "]"); } - ty::re_scope(nid) => mywrite!(w, "s{}|", nid), - ty::re_static => mywrite!(w, "t"), - ty::re_empty => mywrite!(w, "e"), + ty::re_scope(nid) => { + mywrite!(w, "s{}|", nid); + } + ty::re_static => { + mywrite!(w, "t"); + } + ty::re_empty => { + mywrite!(w, "e"); + } ty::re_infer(_) => { // these should not crop up after typeck cx.diag.handler().bug("Cannot encode region variables"); @@ -176,14 +189,17 @@ fn enc_region(w: @mut MemWriter, cx: @ctxt, r: ty::Region) { fn enc_bound_region(w: @mut MemWriter, cx: @ctxt, br: ty::bound_region) { match br { - ty::br_self => mywrite!(w, "s"), - ty::br_anon(idx) => mywrite!(w, "a{}|", idx), - ty::br_named(s) => mywrite!(w, "[{}]", cx.tcx.sess.str_of(s)), - ty::br_cap_avoid(id, br) => { - mywrite!(w, "c{}|", id); - enc_bound_region(w, cx, *br); + ty::br_anon(idx) => { + mywrite!(w, "a{}|", idx); + } + ty::br_named(d, s) => { + mywrite!(w, "[{}|{}]", + (cx.ds)(d), + cx.tcx.sess.str_of(s)); + } + ty::br_fresh(id) => { + mywrite!(w, "f{}|", id); } - ty::br_fresh(id) => mywrite!(w, "{}", id), } } @@ -366,13 +382,15 @@ fn enc_closure_ty(w: @mut MemWriter, cx: @ctxt, ft: &ty::ClosureTy) { } fn enc_fn_sig(w: @mut MemWriter, cx: @ctxt, fsig: &ty::FnSig) { - mywrite!(w, "["); + mywrite!(w, "[{}|", fsig.binder_id); for ty in fsig.inputs.iter() { enc_ty(w, cx, *ty); } mywrite!(w, "]"); if fsig.variadic { - mywrite!(w, "A"); + mywrite!(w, "V"); + } else { + mywrite!(w, "N"); } enc_ty(w, cx, fsig.output); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index cb8c7b3262fb..e60b9382be49 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -15,7 +15,8 @@ use driver::session::Session; use e = metadata::encoder; use metadata::decoder; use metadata::tydecode; -use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter}; +use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter, + RegionParameter}; use metadata::tyencode; use middle::freevars::freevar_entry; use middle::typeck::{method_origin, method_map_entry}; @@ -234,6 +235,12 @@ impl tr for ast::DefId { } } +impl tr for Option { + fn tr(&self, xcx: @ExtendedDecodeContext) -> Option { + self.map(|d| xcx.tr_def_id(d)) + } +} + impl tr for Span { fn tr(&self, xcx: @ExtendedDecodeContext) -> Span { xcx.tr_span(*self) @@ -469,7 +476,11 @@ impl tr for ty::AutoRef { impl tr for ty::Region { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::Region { match *self { - ty::re_bound(br) => ty::re_bound(br.tr(xcx)), + ty::re_fn_bound(id, br) => ty::re_fn_bound(xcx.tr_id(id), + br.tr(xcx)), + ty::re_type_bound(id, index, ident) => ty::re_type_bound(xcx.tr_id(id), + index, + ident), ty::re_scope(id) => ty::re_scope(xcx.tr_id(id)), ty::re_empty | ty::re_static | ty::re_infer(*) => *self, ty::re_free(ref fr) => { @@ -483,10 +494,10 @@ impl tr for ty::Region { impl tr for ty::bound_region { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::bound_region { match *self { - ty::br_anon(_) | ty::br_named(_) | ty::br_self | + ty::br_anon(_) | ty::br_fresh(_) => *self, - ty::br_cap_avoid(id, br) => ty::br_cap_avoid(xcx.tr_id(id), - @br.tr(xcx)) + ty::br_named(id, ident) => ty::br_named(xcx.tr_def_id(id), + ident), } } } @@ -821,8 +832,8 @@ impl ebml_writer_helpers for writer::Encoder { this.emit_type_param_def(ecx, type_param_def); } } - do this.emit_struct_field("region_param", 1) |this| { - tpbt.generics.region_param.encode(this); + do this.emit_struct_field("region_param_defs", 1) |this| { + tpbt.generics.region_param_defs.encode(this); } } } @@ -1086,6 +1097,8 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { // are not used during trans. return do self.read_opaque |this, doc| { + debug!("read_ty({})", type_string(doc)); + let ty = tydecode::parse_ty_data( *doc.data, xcx.dcx.cdata.cnum, @@ -1093,10 +1106,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { xcx.dcx.tcx, |s, a| this.convert_def_id(xcx, s, a)); - debug!("read_ty({}) = {}", - type_string(doc), - ty_to_str(xcx.dcx.tcx, ty)); - ty }; @@ -1139,8 +1148,8 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { @this.read_to_vec(|this| this.read_type_param_def(xcx)) }), - region_param: - this.read_struct_field("region_param", + region_param_defs: + this.read_struct_field("region_param_defs", 1, |this| { Decodable::decode(this) @@ -1161,7 +1170,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { did: ast::DefId) -> ast::DefId { /*! - * * Converts a def-id that appears in a type. The correct * translation will depend on what kind of def-id this is. * This is a subtle point: type definitions are not @@ -1172,10 +1180,25 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { * However, *type parameters* are cloned along with the function * they are attached to. So we should translate those def-ids * to refer to the new, cloned copy of the type parameter. + * We only see references to free type parameters in the body of + * an inlined function. In such cases, we need the def-id to + * be a local id so that the TypeContents code is able to lookup + * the relevant info in the ty_param_defs table. + * + * *Region parameters*, unfortunately, are another kettle of fish. + * In such cases, def_id's can appear in types to distinguish + * shadowed bound regions and so forth. It doesn't actually + * matter so much what we do to these, since regions are erased + * at trans time, but it's good to keep them consistent just in + * case. We translate them with `tr_def_id()` which will map + * the crate numbers back to the original source crate. + * + * It'd be really nice to refactor the type repr to not include + * def-ids so that all these distinctions were unnecessary. */ let r = match source { - NominalType | TypeWithId => xcx.tr_def_id(did), + NominalType | TypeWithId | RegionParameter => xcx.tr_def_id(did), TypeParameter => xcx.tr_intern_def_id(did) }; debug!("convert_def_id(source={:?}, did={:?})={:?}", source, did, r); diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index dd161b189da2..729da749ec69 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -486,7 +486,8 @@ impl<'self> GatherLoanCtxt<'self> { } ty::re_empty | - ty::re_bound(*) | + ty::re_fn_bound(*) | + ty::re_type_bound(*) | ty::re_infer(*) => { self.tcx().sess.span_bug( cmt.span, diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index fd5114889fdd..99f2d7a87002 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -540,7 +540,7 @@ pub fn check_cast_for_escaping_regions( target_regions.push(r); } }, - |_| true); + |_| ()); // Check, based on the region associated with the trait, whether it can // possibly escape the enclosing fn item (note that all type parameters @@ -582,7 +582,6 @@ pub fn check_cast_for_escaping_regions( } _ => {} } - true }); fn is_re_scope(r: ty::Region) -> bool { diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 70aa05848f36..eeedd25adac2 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -781,7 +781,7 @@ impl<'self> Visitor<()> for PrivacyVisitor<'self> { debug!("privacy - list {}", pid.node.id); let seg = ast::PathSegment { identifier: pid.node.name, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }; let segs = ~[seg]; diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 9f848b4c2276..23fef5e35167 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4182,7 +4182,7 @@ impl Resolver { if path.segments .iter() - .any(|s| s.lifetime.is_some()) { + .any(|s| !s.lifetimes.is_empty()) { self.session.span_err(path.span, "lifetime parameters \ are not allowed on \ diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index a13248f2480d..7654a46ec363 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -173,35 +173,30 @@ impl Subst for ty::Generics { fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Generics { ty::Generics { type_param_defs: self.type_param_defs.subst(tcx, substs), - region_param: self.region_param + region_param_defs: self.region_param_defs.subst(tcx, substs), } } } +impl Subst for ty::RegionParameterDef { + fn subst(&self, _: ty::ctxt, _: &ty::substs) -> ty::RegionParameterDef { + *self + } +} + impl Subst for ty::Region { - fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Region { - // Note: This routine only handles the self region, because it - // is only concerned with substitutions of regions that appear - // in types. Region substitution of the bound regions that - // appear in a function signature is done using the - // specialized routine + fn subst(&self, _tcx: ty::ctxt, substs: &ty::substs) -> ty::Region { + // Note: This routine only handles regions that are bound on + // type declarationss and other outer declarations, not those + // bound in *fn types*. Region substitution of the bound + // regions that appear in a function signature is done using + // the specialized routine // `middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig()`. - // As we transition to the new region syntax this distinction - // will most likely disappear. match self { - &ty::re_bound(ty::br_self) => { + &ty::re_type_bound(_, i, _) => { match substs.regions { ty::ErasedRegions => ty::re_static, - ty::NonerasedRegions(ref regions) => { - if regions.len() != 1 { - tcx.sess.bug( - format!("ty::Region\\#subst(): \ - Reference to self region when \ - given substs with no self region: {}", - substs.repr(tcx))); - } - *regions.get(0) - } + ty::NonerasedRegions(ref regions) => *regions.get(i), } } _ => *self diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9d6ad4d8bf69..66fba347acc1 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -436,14 +436,17 @@ pub struct ClosureTy { * Signature of a function type, which I have arbitrarily * decided to use to refer to the input/output types. * - * - `lifetimes` is the list of region names bound in this fn. + * - `binder_id` is the node id where this fn type appeared; + * it is used to identify all the bound regions appearing + * in the input/output types that are bound by this fn type + * (vs some enclosing or enclosed fn type) * - `inputs` is the list of arguments and their modes. * - `output` is the return type. * - `variadic` indicates whether this is a varidic function. (only true for foreign fns) */ #[deriving(Clone, Eq, IterBytes)] pub struct FnSig { - bound_lifetime_names: OptVec, + binder_id: ast::NodeId, inputs: ~[t], output: t, variadic: bool @@ -458,16 +461,13 @@ pub struct param_ty { /// Representation of regions: #[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] pub enum Region { - /// Bound regions are found (primarily) in function types. They indicate - /// region parameters that have yet to be replaced with actual regions - /// (analogous to type parameters, except that due to the monomorphic - /// nature of our type system, bound type parameters are always replaced - /// with fresh type variables whenever an item is referenced, so type - /// parameters only appear "free" in types. Regions in contrast can - /// appear free or bound.). When a function is called, all bound regions - /// tied to that function's node-id are replaced with fresh region - /// variables whose value is then inferred. - re_bound(bound_region), + // Region bound in a type declaration (type/enum/struct/trait), + // which will be substituted when an instance of the type is accessed + re_type_bound(/* param id */ ast::NodeId, /*index*/ uint, ast::Ident), + + // Region bound in a fn scope, which will be substituted when the + // fn is called. + re_fn_bound(/* binder_id */ ast::NodeId, bound_region), /// When checking a function body, the types of all arguments and so forth /// that refer to bound region parameters are modified to refer to free @@ -496,42 +496,32 @@ pub enum Region { impl Region { pub fn is_bound(&self) -> bool { match self { - &re_bound(*) => true, + &ty::re_type_bound(*) => true, + &ty::re_fn_bound(*) => true, _ => false } } } -#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] +#[deriving(Clone, Eq, TotalOrd, TotalEq, IterBytes, Encodable, Decodable, ToStr)] pub struct FreeRegion { scope_id: NodeId, bound_region: bound_region } -#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] +#[deriving(Clone, Eq, TotalEq, TotalOrd, IterBytes, Encodable, Decodable, ToStr)] pub enum bound_region { - /// The self region for structs, impls (&T in a type defn or &'self T) - br_self, - /// An anonymous region parameter for a given fn (&T) br_anon(uint), /// Named region parameters for functions (a in &'a T) - br_named(ast::Ident), + /// + /// The def-id is needed to distinguish free regions in + /// the event of shadowing. + br_named(ast::DefId, ast::Ident), /// Fresh bound identifiers created during GLB computations. br_fresh(uint), - - /** - * Handles capture-avoiding substitution in a rather subtle case. If you - * have a closure whose argument types are being inferred based on the - * expected type, and the expected type includes bound regions, then we - * will wrap those bound regions in a br_cap_avoid() with the id of the - * fn expression. This ensures that the names are not "captured" by the - * enclosing scope, which may define the same names. For an example of - * where this comes up, see src/test/compile-fail/regions-ret-borrowed.rs - * and regions-ret-borrowed-1.rs. */ - br_cap_avoid(ast::NodeId, @bound_region), } /** @@ -868,12 +858,21 @@ pub struct TypeParameterDef { bounds: @ParamBounds } -/// Information about the type/lifetime parametesr associated with an item. +#[deriving(Encodable, Decodable, Clone)] +pub struct RegionParameterDef { + ident: ast::Ident, + def_id: ast::DefId, +} + +/// Information about the type/lifetime parameters associated with an item. /// Analogous to ast::Generics. #[deriving(Clone)] pub struct Generics { + /// List of type parameters declared on the item. type_param_defs: @~[TypeParameterDef], - region_param: Option, + + /// List of region parameters declared on the item. + region_param_defs: @[RegionParameterDef], } impl Generics { @@ -882,6 +881,33 @@ impl Generics { } } +/// When type checking, we use the `ParameterEnvironment` to track +/// details about the type/lifetime parameters that are in scope. +/// It primarily stores the bounds information. +/// +/// Note: This information might seem to be redundant with the data in +/// `tcx.ty_param_defs`, but it is not. That table contains the +/// parameter definitions from an "outside" perspective, but this +/// struct will contain the bounds for a parameter as seen from inside +/// the function body. Currently the only real distinction is that +/// bound lifetime parameters are replaced with free ones, but in the +/// future I hope to refine the representation of types so as to make +/// more distinctions clearer. +pub struct ParameterEnvironment { + /// A substitution that can be applied to move from + /// the "outer" view of a type or method to the "inner" view. + /// In general, this means converting from bound parameters to + /// free parameters. Since we currently represent bound/free type + /// parameters in the same way, this only has an affect on regions. + free_substs: ty::substs, + + /// Bound on the Self parameter + self_param_bound: Option<@TraitRef>, + + /// Bounds on each numbered type parameter + type_param_bounds: ~[ParamBounds], +} + /// A polytype. /// /// - `bounds`: The list of bounds for each type parameter. The length of the @@ -1255,14 +1281,17 @@ pub fn mk_bare_fn(cx: ctxt, fty: BareFnTy) -> t { mk_t(cx, ty_bare_fn(fty)) } -pub fn mk_ctor_fn(cx: ctxt, input_tys: &[ty::t], output: ty::t) -> t { +pub fn mk_ctor_fn(cx: ctxt, + binder_id: ast::NodeId, + input_tys: &[ty::t], + output: ty::t) -> t { let input_args = input_tys.map(|t| *t); mk_bare_fn(cx, BareFnTy { purity: ast::impure_fn, abis: AbiSet::Rust(), sig: FnSig { - bound_lifetime_names: opt_vec::Empty, + binder_id: binder_id, inputs: input_args, output: output, variadic: false @@ -4662,3 +4691,79 @@ pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: @str) -> u64 { hash.result_u64() } + +pub fn construct_parameter_environment( + tcx: ctxt, + self_bound: Option<@TraitRef>, + item_type_params: &[TypeParameterDef], + method_type_params: &[TypeParameterDef], + item_region_params: &[RegionParameterDef], + free_id: ast::NodeId) + -> ParameterEnvironment +{ + /*! See `ParameterEnvironment` struct def'n for details */ + + // + // Construct the free substs. + // + + // map Self => Self + let self_ty = self_bound.map(|t| ty::mk_self(tcx, t.def_id)); + + // map A => A + let num_item_type_params = item_type_params.len(); + let num_method_type_params = method_type_params.len(); + let num_type_params = num_item_type_params + num_method_type_params; + let type_params = vec::from_fn(num_type_params, |i| { + let def_id = if i < num_item_type_params { + item_type_params[i].def_id + } else { + method_type_params[i - num_item_type_params].def_id + }; + + ty::mk_param(tcx, i, def_id) + }); + + // map bound 'a => free 'a + let region_params = item_region_params.iter(). + map(|r| ty::re_free(ty::FreeRegion { + scope_id: free_id, + bound_region: ty::br_named(r.def_id, r.ident)})). + collect(); + + let free_substs = substs { + self_ty: self_ty, + tps: type_params, + regions: ty::NonerasedRegions(region_params) + }; + + // + // Compute the bounds on Self and the type parameters. + // + + let self_bound_substd = self_bound.map(|b| b.subst(tcx, &free_substs)); + let type_param_bounds_substd = vec::from_fn(num_type_params, |i| { + if i < num_item_type_params { + (*item_type_params[i].bounds).subst(tcx, &free_substs) + } else { + let j = i - num_item_type_params; + (*method_type_params[j].bounds).subst(tcx, &free_substs) + } + }); + + ty::ParameterEnvironment { + free_substs: free_substs, + self_param_bound: self_bound_substd, + type_param_bounds: type_param_bounds_substd, + } +} + +impl substs { + pub fn empty() -> substs { + substs { + self_ty: None, + tps: ~[], + regions: NonerasedRegions(opt_vec::Empty) + } + } +} diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 11d995762ee7..0c0abaa5d76c 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -154,13 +154,11 @@ pub fn opt_ast_region_to_region( fn ast_path_substs( this: &AC, rscope: &RS, - def_id: ast::DefId, decl_generics: &ty::Generics, self_ty: Option, 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`. @@ -171,30 +169,28 @@ fn ast_path_substs( // If the type is parameterized by the this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). - let regions = match (&decl_generics.region_param, - &path.segments.last().lifetime) { - (&None, &None) => { - opt_vec::Empty - } - (&None, &Some(_)) => { + let expected_num_region_params = decl_generics.region_param_defs.len(); + let supplied_num_region_params = path.segments.last().lifetimes.len(); + let regions = if expected_num_region_params == supplied_num_region_params { + path.segments.last().lifetimes.map( + |l| ast_region_to_region(this.tcx(), l)) + } else { + let anon_regions = + rscope.anon_regions(path.span, expected_num_region_params); + + if supplied_num_region_params != 0 || anon_regions.is_none() { tcx.sess.span_err( path.span, - format!("no region bound is allowed on `{}`, \ - which is not declared as containing region pointers", - ty::item_path_str(tcx, def_id))); - opt_vec::Empty + format!("wrong number of lifetime parameters: \ + expected {} but found {}", + expected_num_region_params, + supplied_num_region_params)); } - (&Some(_), &None) => { - let res = rscope.anon_region(path.span); - let r = get_region_reporting_err(this.tcx(), path.span, &None, res); - opt_vec::with(r) - } - (&Some(_), &Some(_)) => { - opt_vec::with( - ast_region_to_region(this, - rscope, - path.span, - &path.segments.last().lifetime)) + + match anon_regions { + Some(v) => opt_vec::from(v), + None => opt_vec::from(vec::from_fn(expected_num_region_params, + |_| ty::re_static)) // hokey } }; @@ -234,7 +230,7 @@ pub fn ast_path_to_substs_and_ty( ast_path_substs( this, rscope, - trait_def.trait_ref.def_id, &trait_def.generics, self_ty, path); @@ -304,6 +299,7 @@ pub fn ast_ty_to_ty( constr: &fn(ty::mt) -> ty::t) -> ty::t { let tcx = this.tcx(); + debug!("mk_pointer(vst={:?})", vst); match a_seq_ty.ty.node { ast::ty_vec(ref mt) => { @@ -311,6 +307,7 @@ pub fn ast_ty_to_ty( if a_seq_ty.mutbl == ast::MutMutable { mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl }; } + debug!("&[]: vst={:?}", vst); return ty::mk_evec(tcx, mt, vst); } ast::ty_path(ref path, ref bounds, id) => { @@ -369,7 +366,7 @@ pub fn ast_ty_to_ty( } if (flags & NO_REGIONS) != 0u { - if path.segments.last().lifetime.is_some() { + if !path.segments.last().lifetimes.is_empty() { tcx.sess.span_err( path.span, "region parameters are not allowed on this type"); @@ -422,8 +419,8 @@ pub fn ast_ty_to_ty( if bf.decl.variadic && !bf.abis.is_c() { tcx.sess.span_err(ast_ty.span, "variadic function must have C calling convention"); } - ty::mk_bare_fn(tcx, ty_of_bare_fn(this, rscope, bf.purity, - bf.abis, &bf.lifetimes, &bf.decl)) + ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.purity, + bf.abis, &bf.decl)) } ast::ty_closure(ref f) => { if f.sigil == ast::ManagedSigil { @@ -440,6 +437,7 @@ pub fn ast_ty_to_ty( }); let fn_decl = ty_of_closure(this, rscope, + ast_ty.id, f.sigil, f.purity, f.onceness, @@ -447,7 +445,6 @@ pub fn ast_ty_to_ty( &f.region, &f.decl, None, - &f.lifetimes, ast_ty.span); ty::mk_closure(tcx, fn_decl) } @@ -594,9 +591,8 @@ struct SelfInfo { pub fn ty_of_method( this: &AC, - rscope: &RS, + id: ast::NodeId, purity: ast::purity, - lifetimes: &OptVec, untransformed_self_ty: ty::t, explicit_self: ast::explicit_self, decl: &ast::fn_decl) -> (Option, ty::BareFnTy) @@ -606,33 +602,31 @@ pub fn ty_of_method( explicit_self: explicit_self }; let (a, b) = ty_of_method_or_bare_fn( - this, rscope, purity, AbiSet::Rust(), lifetimes, Some(&self_info), decl); + this, id, purity, AbiSet::Rust(), Some(&self_info), decl); (a.unwrap(), b) } -pub fn ty_of_bare_fn( +pub fn ty_of_bare_fn( this: &AC, - rscope: &RS, + id: ast::NodeId, purity: ast::purity, abi: AbiSet, - lifetimes: &OptVec, decl: &ast::fn_decl) -> ty::BareFnTy { - let (_, b) = ty_of_method_or_bare_fn( - this, rscope, purity, abi, lifetimes, None, decl); + let (_, b) = ty_of_method_or_bare_fn(this, id, purity, + abi, None, decl); b } -fn ty_of_method_or_bare_fn( +fn ty_of_method_or_bare_fn( this: &AC, - rscope: &RS, + id: ast::NodeId, purity: ast::purity, abi: AbiSet, - lifetimes: &OptVec, opt_self_info: Option<&SelfInfo>, decl: &ast::fn_decl) -> (Option>, ty::BareFnTy) { - debug!("ty_of_bare_fn"); + debug!("ty_of_method_or_bare_fn"); // new region names that appear inside of the fn decl are bound to // that function type @@ -653,12 +647,10 @@ fn ty_of_method_or_bare_fn( ty::BareFnTy { purity: purity, abis: abi, - sig: ty::FnSig { - bound_lifetime_names: bound_lifetime_names, - inputs: input_tys, - output: output_ty, - variadic: decl.variadic - } + sig: ty::FnSig {binder_id: id, + inputs: input_tys, + output: output_ty, + variadic: decl.variadic} }); fn transform_self_ty( @@ -697,6 +689,7 @@ fn ty_of_method_or_bare_fn( pub fn ty_of_closure( this: &AC, rscope: &RS, + id: ast::NodeId, sigil: ast::Sigil, purity: ast::purity, onceness: ast::Onceness, @@ -704,17 +697,10 @@ pub fn ty_of_closure( opt_lifetime: &Option, decl: &ast::fn_decl, expected_sig: Option, - lifetimes: &OptVec, span: Span) -> ty::ClosureTy { - // The caller should not both provide explicit bound lifetime - // names and expected types. Either we infer the bound lifetime - // names or they are provided, but not both. - assert!(lifetimes.is_empty() || expected_sig.is_none()); - debug!("ty_of_fn_decl"); - let _i = indenter(); // resolve the function bound region in the original region // scope `rscope`, not the scope of the function parameters @@ -763,12 +749,10 @@ pub fn ty_of_closure( onceness: onceness, region: bound_region, bounds: bounds, - sig: ty::FnSig { - bound_lifetime_names: bound_lifetime_names, - inputs: input_tys, - output: output_ty, - variadic: decl.variadic - } + sig: ty::FnSig {binder_id: id, + inputs: input_tys, + output: output_ty, + variadic: decl.variadic} } } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index af1d5ce3cc60..870b29882fd6 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -85,7 +85,6 @@ use middle::ty::*; use middle::ty; use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{structurally_resolved_type}; -use middle::typeck::check::vtable::VtableContext; use middle::typeck::check::vtable; use middle::typeck::check; use middle::typeck::infer; @@ -99,7 +98,6 @@ use util::ppaux::Repr; use std::hashmap::HashSet; use std::result; use std::vec; -use extra::list::Nil; use syntax::ast::{DefId, sty_value, sty_region, sty_box}; use syntax::ast::{sty_uniq, sty_static, NodeId}; use syntax::ast::{MutMutable, MutImmutable}; @@ -265,8 +263,7 @@ impl<'self> LookupContext<'self> { self.search_for_autosliced_method(self_ty, autoderefs) } - fn deref(&self, ty: ty::t) - -> Option { + fn deref(&self, ty: ty::t) -> Option { match ty::deref(self.tcx(), ty, false) { None => None, Some(t) => { @@ -327,11 +324,10 @@ impl<'self> LookupContext<'self> { ty_param(p) => { self.push_inherent_candidates_from_param(self_ty, p); } - ty_self(self_did) => { + ty_self(*) => { // Call is of the form "self.foo()" and appears in one // of a trait's default method implementations. - self.push_inherent_candidates_from_self( - self_ty, self_did); + self.push_inherent_candidates_from_self(self_ty); } _ => { /* No bound methods in these types */ } } @@ -448,32 +444,20 @@ impl<'self> LookupContext<'self> { param_ty: param_ty) { debug!("push_inherent_candidates_from_param(param_ty={:?})", param_ty); - let _indenter = indenter(); - - let tcx = self.tcx(); - let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) { - Some(t) => t, - None => { - tcx.sess.span_bug( - self.expr.span, - format!("No param def for {:?}", param_ty)); - } - }; - self.push_inherent_candidates_from_bounds( - rcvr_ty, type_param_def.bounds.trait_bounds, + rcvr_ty, + self.fcx.inh.param_env.type_param_bounds[param_ty.idx].trait_bounds, param_numbered(param_ty.idx)); } fn push_inherent_candidates_from_self(&self, - self_ty: ty::t, - did: DefId) { - let tcx = self.tcx(); - - let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref; + rcvr_ty: ty::t) { + debug!("push_inherent_candidates_from_self()"); self.push_inherent_candidates_from_bounds( - self_ty, &[trait_ref], param_self); + rcvr_ty, + [self.fcx.inh.param_env.self_param_bound.unwrap()], + param_self) } fn push_inherent_candidates_from_bounds(&self, @@ -574,10 +558,7 @@ impl<'self> LookupContext<'self> { // determine the `self` of the impl with fresh // variables for each parameter: let location_info = &vtable::location_info_for_expr(self.self_expr); - let vcx = VtableContext { - ccx: self.fcx.ccx, - infcx: self.fcx.infcx() - }; + let vcx = self.fcx.vtable_context(); let ty::ty_param_substs_and_ty { substs: impl_substs, ty: impl_ty @@ -1010,7 +991,7 @@ impl<'self> LookupContext<'self> { }; let (_, opt_transformed_self_ty, fn_sig) = replace_bound_regions_in_fn_sig( - tcx, @Nil, Some(transformed_self_ty), &bare_fn_ty.sig, + tcx, Some(transformed_self_ty), &bare_fn_ty.sig, |br| self.fcx.infcx().next_region_var( infer::BoundRegionInFnCall(self.expr.span, br))); let transformed_self_ty = opt_transformed_self_ty.unwrap(); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 32284584b658..982bc4934176 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -81,10 +81,12 @@ use middle::const_eval; use middle::pat_util::pat_id_map; use middle::pat_util; use middle::lint::unreachable_code; +use middle::subst::Subst; use middle::ty::{FnSig, VariantInfo}; use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty}; use middle::ty::{substs, param_ty, Disr, ExprTyProvider}; use middle::ty; +use middle::ty_fold::TypeFolder; use middle::typeck::astconv::AstConv; use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty}; use middle::typeck::astconv; @@ -99,22 +101,18 @@ use middle::typeck::check::vtable::{LocationInfo, VtableContext}; use middle::typeck::CrateCtxt; use middle::typeck::infer::{resolve_type, force_tvar}; use middle::typeck::infer; -use middle::typeck::rscope::bound_self_region; -use middle::typeck::rscope::{RegionError}; use middle::typeck::rscope::RegionScope; -use middle::typeck::{isr_alist, lookup_def_ccx}; +use middle::typeck::{lookup_def_ccx}; use middle::typeck::no_params; use middle::typeck::{require_same_types, method_map, vtable_map}; use util::common::{block_query, indenter, loop_query}; -use util::ppaux::{bound_region_ptr_to_str}; +use util::ppaux::UserString; use util::ppaux; - use std::hashmap::HashMap; use std::result; use std::util::replace; use std::vec; -use extra::list::Nil; use syntax::abi::AbiSet; use syntax::ast::{provided, required}; use syntax::ast; @@ -127,7 +125,6 @@ use syntax::codemap; use syntax::opt_vec::OptVec; use syntax::opt_vec; use syntax::parse::token; -use syntax::parse::token::special_idents; use syntax::print::pprust; use syntax::visit; use syntax::visit::Visitor; @@ -157,9 +154,10 @@ pub struct SelfInfo { /// Here, the function `foo()` and the closure passed to /// `bar()` will each have their own `FnCtxt`, but they will /// share the inherited fields. -pub struct inherited { +pub struct Inherited { infcx: @mut infer::InferCtxt, locals: @mut HashMap, + param_env: ty::ParameterEnvironment, // Temporary tables: node_types: @mut HashMap, @@ -249,22 +247,25 @@ pub struct FnCtxt { // function return type. fn_kind: FnKind, - in_scope_regions: isr_alist, - - inh: @inherited, + inh: @Inherited, ccx: @mut CrateCtxt, } -pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited { - @inherited { - infcx: infer::new_infer_ctxt(ccx.tcx), - locals: @mut HashMap::new(), - node_types: @mut HashMap::new(), - node_type_substs: @mut HashMap::new(), - adjustments: @mut HashMap::new(), - method_map: @mut HashMap::new(), - vtable_map: @mut HashMap::new(), +impl Inherited { + fn new(tcx: ty::ctxt, + param_env: ty::ParameterEnvironment) + -> Inherited { + Inherited { + infcx: infer::new_infer_ctxt(tcx), + locals: @mut HashMap::new(), + param_env: param_env, + node_types: @mut HashMap::new(), + node_type_substs: @mut HashMap::new(), + adjustments: @mut HashMap::new(), + method_map: @mut HashMap::new(), + vtable_map: @mut HashMap::new(), + } } } @@ -272,17 +273,19 @@ pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited { pub fn blank_fn_ctxt(ccx: @mut CrateCtxt, rty: ty::t, region_bnd: ast::NodeId) - -> @mut FnCtxt { -// It's kind of a kludge to manufacture a fake function context -// and statement context, but we might as well do write the code only once + -> @mut FnCtxt { + // It's kind of a kludge to manufacture a fake function context + // and statement context, but we might as well do write the code only once + let param_env = ty::ParameterEnvironment { free_substs: substs::empty(), + self_param_bound: None, + type_param_bounds: ~[] }; @mut FnCtxt { err_count_on_creation: ccx.tcx.sess.err_count(), ret_ty: rty, ps: PurityState::function(ast::impure_fn, 0), region_lb: region_bnd, - in_scope_regions: @Nil, fn_kind: Vanilla, - inh: blank_inherited(ccx), + inh: @Inherited::new(ccx.tcx, param_env), ccx: ccx } } @@ -315,14 +318,15 @@ pub fn check_bare_fn(ccx: @mut CrateCtxt, decl: &ast::fn_decl, body: &ast::Block, id: ast::NodeId, - self_info: Option) { - let fty = ty::node_id_to_type(ccx.tcx, id); + self_info: Option, + fty: ty::t, + param_env: ty::ParameterEnvironment) { match ty::get(fty).sty { ty::ty_bare_fn(ref fn_ty) => { let fcx = check_fn(ccx, self_info, fn_ty.purity, &fn_ty.sig, decl, id, body, Vanilla, - @Nil, blank_inherited(ccx));; + @Inherited::new(ccx.tcx, param_env)); vtable::resolve_in_block(fcx, body); regionck::regionck_fn(fcx, body); @@ -411,39 +415,35 @@ pub fn check_fn(ccx: @mut CrateCtxt, id: ast::NodeId, body: &ast::Block, fn_kind: FnKind, - inherited_isr: isr_alist, - inherited: @inherited) -> @mut FnCtxt + inherited: @Inherited) -> @mut FnCtxt { /*! - * * Helper used by check_bare_fn and check_expr_fn. Does the * grungy work of checking a function body and returns the * function context used for that purpose, since in the case of a * fn item there is still a bit more to do. * * - ... - * - inherited_isr: regions in scope from the enclosing fn (if any) * - inherited: other fields inherited from the enclosing fn (if any) */ let tcx = ccx.tcx; let err_count_on_creation = tcx.sess.err_count(); - // ______________________________________________________________________ // First, we have to replace any bound regions in the fn and self // types with free ones. The free region references will be bound // the node_id of the body block. - let (isr, opt_self_info, fn_sig) = { + let (opt_self_info, fn_sig) = { let opt_self_ty = opt_self_info.map(|i| i.self_ty); - let (isr, opt_self_ty, fn_sig) = + let (_, opt_self_ty, fn_sig) = replace_bound_regions_in_fn_sig( - tcx, inherited_isr, opt_self_ty, fn_sig, + tcx, opt_self_ty, fn_sig, |br| ty::re_free(ty::FreeRegion {scope_id: body.id, bound_region: br})); let opt_self_info = opt_self_info.map( |si| SelfInfo {self_ty: opt_self_ty.unwrap(), .. si}); - (isr, opt_self_info, fn_sig) + (opt_self_info, fn_sig) }; relate_free_regions(tcx, opt_self_info.map(|s| s.self_ty), &fn_sig); @@ -456,7 +456,6 @@ pub fn check_fn(ccx: @mut CrateCtxt, ppaux::ty_to_str(tcx, ret_ty), opt_self_info.map(|si| ppaux::ty_to_str(tcx, si.self_ty))); - // ______________________________________________________________________ // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. let fcx: @mut FnCtxt = { @@ -465,7 +464,6 @@ pub fn check_fn(ccx: @mut CrateCtxt, ret_ty: ret_ty, ps: PurityState::function(purity, id), region_lb: body.id, - in_scope_regions: isr, fn_kind: fn_kind, inh: inherited, ccx: ccx @@ -536,26 +534,6 @@ pub fn check_fn(ccx: @mut CrateCtxt, } } -pub fn check_method(ccx: @mut CrateCtxt, - method: @ast::method) -{ - let method_def_id = local_def(method.id); - let method_ty = ty::method(ccx.tcx, method_def_id); - let opt_self_info = method_ty.transformed_self_ty.map(|ty| { - SelfInfo {self_ty: ty, - self_id: method.self_id, - span: method.explicit_self.span} - }); - - check_bare_fn( - ccx, - &method.decl, - &method.body, - method.id, - opt_self_info - ); -} - pub fn check_no_duplicate_fields(tcx: ty::ctxt, fields: ~[(ast::Ident, Span)]) { let mut field_names = HashMap::new(); @@ -566,7 +544,7 @@ pub fn check_no_duplicate_fields(tcx: ty::ctxt, match orig_sp { Some(orig_sp) => { tcx.sess.span_err(sp, format!("Duplicate field name {} in record type declaration", - tcx.sess.str_of(id))); + tcx.sess.str_of(id))); tcx.sess.span_note(orig_sp, "First declaration of this field occurred here"); break; } @@ -603,18 +581,32 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { it.id); } ast::item_fn(ref decl, _, _, _, ref body) => { - check_bare_fn(ccx, decl, body, it.id, None); + let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); + + // FIXME -- this won't fly for the case where people reference + // a lifetime from within a type parameter. That's actually fairly + // tricky. + let param_env = ty::construct_parameter_environment( + ccx.tcx, + None, + *fn_tpt.generics.type_param_defs, + [], + [], + body.id); + + check_bare_fn(ccx, decl, body, it.id, None, fn_tpt.ty, param_env); } - ast::item_impl(_, _, _, ref ms) => { - let rp = ccx.tcx.region_paramd_items.find(&it.id).map(|x| *x); - debug!("item_impl {} with id {} rp {:?}", - ccx.tcx.sess.str_of(it.ident), it.id, rp); + ast::item_impl(_, ref opt_trait_ref, _, ref ms) => { + debug!("item_impl {} with id {}", ccx.tcx.sess.str_of(it.ident), it.id); + + let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); for m in ms.iter() { - check_method(ccx, *m); + check_method_body(ccx, &impl_tpt.generics, None, *m); } vtable::resolve_impl(ccx, it); } ast::item_trait(_, _, ref trait_methods) => { + let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id)); for trait_method in (*trait_methods).iter() { match *trait_method { required(*) => { @@ -622,7 +614,8 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { // bodies to check. } provided(m) => { - check_method(ccx, m); + check_method_body(ccx, &trait_def.generics, + Some(trait_def.trait_ref), m); } } } @@ -662,6 +655,58 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { } } +fn check_method_body(ccx: @mut CrateCtxt, + item_generics: &ty::Generics, + self_bound: Option<@ty::TraitRef>, + method: @ast::method) { + /*! + * Type checks a method body. + * + * # Parameters + * - `item_generics`: generics defined on the impl/trait that contains + * the method + * - `self_bound`: bound for the `Self` type parameter, if any + * - `method`: the method definition + */ + + debug!("check_method_body(item_generics={}, \ + self_bound={}, \ + method.id={})", + item_generics.repr(ccx.tcx), + self_bound.repr(ccx.tcx), + method.id); + let method_def_id = local_def(method.id); + let method_ty = ty::method(ccx.tcx, method_def_id); + let method_generics = &method_ty.generics; + + let param_env = + ty::construct_parameter_environment( + ccx.tcx, + self_bound, + *item_generics.type_param_defs, + *method_generics.type_param_defs, + item_generics.region_param_defs, + method.body.id); + + // Compute the self type and fty from point of view of inside fn + let opt_self_info = method_ty.transformed_self_ty.map(|ty| { + SelfInfo {self_ty: ty.subst(ccx.tcx, ¶m_env.free_substs), + self_id: method.self_id, + span: method.explicit_self.span} + }); + let fty = ty::node_id_to_type(ccx.tcx, method.id); + let fty = fty.subst(ccx.tcx, ¶m_env.free_substs); + + check_bare_fn( + ccx, + &method.decl, + &method.body, + method.id, + opt_self_info, + fty, + param_env); +} + impl AstConv for FnCtxt { fn tcx(&self) -> ty::ctxt { self.ccx.tcx } @@ -682,48 +727,26 @@ impl FnCtxt { pub fn infcx(&self) -> @mut infer::InferCtxt { self.inh.infcx } + pub fn err_count_since_creation(&self) -> uint { self.ccx.tcx.sess.err_count() - self.err_count_on_creation } - pub fn search_in_scope_regions(&self, - span: Span, - br: ty::bound_region) - -> Result { - let in_scope_regions = self.in_scope_regions; - match in_scope_regions.find(br) { - Some(r) => result::Ok(r), - None => { - let blk_br = ty::br_named(special_idents::blk); - if br == blk_br { - result::Ok(self.block_region()) - } else { - result::Err(RegionError { - msg: { - format!("named region `{}` not in scope here", - bound_region_ptr_to_str(self.tcx(), br)) - }, - replacement: { - self.infcx().next_region_var( - infer::BoundRegionError(span)) - } - }) - } - } + + pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> { + VtableContext { + infcx: self.infcx(), + param_env: &self.inh.param_env } } } -impl RegionScope for FnCtxt { - fn anon_region(&self, span: Span) -> Result { - result::Ok(self.infcx().next_region_var(infer::MiscVariable(span))) - } - fn self_region(&self, span: Span) -> Result { - self.search_in_scope_regions(span, ty::br_self) - } - fn named_region(&self, +impl RegionScope for @mut infer::InferCtxt { + fn anon_regions(&self, span: Span, - id: ast::Ident) -> Result { - self.search_in_scope_regions(span, ty::br_named(id)) + count: uint) -> Option<~[ty::Region]> { + Some(vec::from_fn( + count, + |_| self.next_region_var(infer::MiscVariable(span)))) } } @@ -805,7 +828,7 @@ impl FnCtxt { } pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t { - ast_ty_to_ty(self, self, ast_t) + ast_ty_to_ty(self, &self.infcx(), ast_t) } pub fn pat_to_str(&self, pat: @ast::Pat) -> ~str { @@ -817,7 +840,7 @@ impl FnCtxt { Some(&t) => t, None => { self.tcx().sess.bug(format!("no type for expr in fcx {}", - self.tag())); + self.tag())); } } } @@ -828,10 +851,10 @@ impl FnCtxt { None => { self.tcx().sess.bug( format!("no type for node {}: {} in fcx {}", - id, ast_map::node_id_to_str( - self.tcx().items, id, - token::get_ident_interner()), - self.tag())); + id, ast_map::node_id_to_str( + self.tcx().items, id, + token::get_ident_interner()), + self.tag())); } } } @@ -842,10 +865,9 @@ impl FnCtxt { None => { self.tcx().sess.bug( format!("no type substs for node {}: {} in fcx {}", - id, ast_map::node_id_to_str( - self.tcx().items, id, - token::get_ident_interner()), - self.tag())); + id, ast_map::node_id_to_str(self.tcx().items, id, + token::get_ident_interner()), + self.tag())); } } } @@ -924,20 +946,6 @@ impl FnCtxt { v } - pub fn region_var_if_parameterized(&self, - rp: Option, - span: Span) - -> OptVec { - match rp { - None => opt_vec::Empty, - Some(_) => { - opt_vec::with( - self.infcx().next_region_var( - infer::BoundRegionInTypeOrImpl(span))) - } - } - } - pub fn type_error_message(&self, sp: Span, mk_msg: &fn(~str) -> ~str, @@ -1105,20 +1113,22 @@ pub fn impl_self_ty(vcx: &VtableContext, -> ty_param_substs_and_ty { let tcx = vcx.tcx(); - let (n_tps, region_param, raw_ty) = { + let (n_tps, n_rps, raw_ty) = { let ity = ty::lookup_item_type(tcx, did); - (ity.generics.type_param_defs.len(), ity.generics.region_param, ity.ty) + (ity.generics.type_param_defs.len(), + ity.generics.region_param_defs.len(), + ity.ty) }; - let regions = ty::NonerasedRegions(if region_param.is_some() { - opt_vec::with(vcx.infcx.next_region_var( - infer::BoundRegionInTypeOrImpl(location_info.span))) - } else { - opt_vec::Empty - }); + let rps = + vcx.infcx.next_region_vars( + infer::BoundRegionInTypeOrImpl(location_info.span), + n_rps); let tps = vcx.infcx.next_ty_vars(n_tps); - let substs = substs {regions: regions, self_ty: None, tps: tps}; + let substs = substs {regions: ty::NonerasedRegions(opt_vec::from(rps)), + self_ty: None, + tps: tps}; let substd_ty = ty::subst(tcx, &substs, raw_ty); ty_param_substs_and_ty { substs: substs, ty: substd_ty } @@ -1174,22 +1184,21 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, // Verify that no lifetimes or type parameters are present anywhere // except the final two elements of the path. for i in range(0, path.segments.len() - 2) { - match path.segments[i].lifetime { - None => {} - Some(lifetime) => { - function_context.tcx() - .sess - .span_err(lifetime.span, - "lifetime parameters may not \ - appear here") - } + for lifetime in path.segments[i].lifetimes.iter() { + function_context.tcx() + .sess + .span_err(lifetime.span, + "lifetime parameters may not \ + appear here"); + break; } for typ in path.segments[i].types.iter() { function_context.tcx() .sess .span_err(typ.span, - "type parameters may not appear here") + "type parameters may not appear here"); + break; } } @@ -1197,7 +1206,7 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, // rest of typechecking will (attempt to) infer everything. if path.segments .iter() - .all(|s| s.lifetime.is_none() && s.types.is_empty()) { + .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) { return } @@ -1219,26 +1228,17 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, // Make sure lifetime parameterization agrees with the trait or // implementation type. - match (generics.region_param, trait_segment.lifetime) { - (Some(_), None) => { - function_context.tcx() - .sess - .span_err(path.span, - format!("this {} has a lifetime \ - parameter but no \ - lifetime was specified", - name)) - } - (None, Some(_)) => { - function_context.tcx() - .sess - .span_err(path.span, - format!("this {} has no lifetime \ - parameter but a lifetime \ - was specified", - name)) - } - (Some(_), Some(_)) | (None, None) => {} + let trait_region_parameter_count = generics.region_param_defs.len(); + let supplied_region_parameter_count = trait_segment.lifetimes.len(); + if trait_region_parameter_count != supplied_region_parameter_count + && supplied_region_parameter_count != 0 { + function_context.tcx() + .sess + .span_err(path.span, + format!("expected {} lifetime parameter(s), \ + found {} lifetime parameter(s)", + trait_region_parameter_count, + supplied_region_parameter_count)); } // Make sure the number of type parameters supplied on the trait @@ -1276,15 +1276,13 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, // Verify that no lifetimes or type parameters are present on // the penultimate segment of the path. let segment = &path.segments[path.segments.len() - 2]; - match segment.lifetime { - None => {} - Some(lifetime) => { - function_context.tcx() - .sess - .span_err(lifetime.span, - "lifetime parameters may not - appear here") - } + for lifetime in segment.lifetimes.iter() { + function_context.tcx() + .sess + .span_err(lifetime.span, + "lifetime parameters may not + appear here"); + break; } for typ in segment.types.iter() { function_context.tcx() @@ -1292,10 +1290,7 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, .span_err(typ.span, "type parameters may not appear \ here"); - function_context.tcx() - .sess - .span_note(typ.span, - format!("this is a {:?}", def)); + break; } } } @@ -1556,7 +1551,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // In that case, we check each argument against "error" in order to // set up all the node type bindings. let error_fn_sig = FnSig { - bound_lifetime_names: opt_vec::Empty, + binder_id: ast::CRATE_NODE_ID, inputs: err_args(args.len()), output: ty::mk_err(), variadic: false @@ -1577,7 +1572,6 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // signature with region variables let (_, _, fn_sig) = replace_bound_regions_in_fn_sig(fcx.tcx(), - @Nil, None, fn_sig, |br| fcx.infcx() @@ -1908,10 +1902,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, expected: Option) { let tcx = fcx.ccx.tcx; - // Find the expected input/output types (if any). Careful to - // avoid capture of bound regions in the expected type. See - // def'n of br_cap_avoid() for a more lengthy explanation of - // what's going on here. + // Find the expected input/output types (if any). Substitute + // fresh bound regions for any bound regions we find in the + // expected types so as to avoid capture. + // // Also try to pick up inferred purity and sigil, defaulting // to impure and block. Note that we only will use those for // block syntax lambdas; that is, lambdas without explicit @@ -1927,11 +1921,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, expected_bounds) = { match expected_sty { Some(ty::ty_closure(ref cenv)) => { - let id = expr.id; let (_, _, sig) = replace_bound_regions_in_fn_sig( - tcx, @Nil, None, &cenv.sig, - |br| ty::re_bound(ty::br_cap_avoid(id, @br))); + tcx, None, &cenv.sig, + |_| fcx.inh.infcx.fresh_bound_region(expr.id)); (Some(sig), cenv.purity, cenv.sigil, cenv.onceness, cenv.bounds) } @@ -1952,7 +1945,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // construct the function type let fn_ty = astconv::ty_of_closure(fcx, - fcx, + &fcx.infcx(), + expr.id, sigil, purity, expected_onceness, @@ -1960,13 +1954,12 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, &None, decl, expected_sig, - &opt_vec::Empty, expr.span); let fty_sig; let fty = if error_happened { fty_sig = FnSig { - bound_lifetime_names: opt_vec::Empty, + binder_id: ast::CRATE_NODE_ID, inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()), output: ty::mk_err(), variadic: false @@ -1989,7 +1982,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, sigil); check_fn(fcx.ccx, None, inherited_purity, &fty_sig, - decl, id, body, fn_kind, fcx.in_scope_regions, fcx.inh); + decl, id, body, fn_kind, fcx.inh); } @@ -2168,50 +2161,18 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Look up the number of type parameters and the raw type, and // determine whether the class is region-parameterized. - let type_parameter_count; - let region_parameterized; - let raw_type; - if class_id.crate == ast::LOCAL_CRATE { - region_parameterized = - tcx.region_paramd_items.find(&class_id.node). - map(|x| *x); - match tcx.items.find(&class_id.node) { - Some(&ast_map::node_item(@ast::item { - node: ast::item_struct(_, ref generics), - _ - }, _)) => { - - type_parameter_count = generics.ty_params.len(); - - let self_region = - bound_self_region(region_parameterized); - - raw_type = ty::mk_struct(tcx, class_id, substs { - regions: ty::NonerasedRegions(self_region), - self_ty: None, - tps: ty::ty_params_to_tys( - tcx, - generics) - }); - } - _ => { - tcx.sess.span_bug(span, - "resolve didn't map this to a class"); - } - } - } else { - let item_type = ty::lookup_item_type(tcx, class_id); - type_parameter_count = item_type.generics.type_param_defs.len(); - region_parameterized = item_type.generics.region_param; - raw_type = item_type.ty; - } + let item_type = ty::lookup_item_type(tcx, class_id); + let type_parameter_count = item_type.generics.type_param_defs.len(); + let region_parameter_count = item_type.generics.region_param_defs.len(); + let raw_type = item_type.ty; // Generate the struct type. - let regions = - fcx.region_var_if_parameterized(region_parameterized, span); + let regions = fcx.infcx().next_region_vars( + infer::BoundRegionInTypeOrImpl(span), + region_parameter_count); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { - regions: ty::NonerasedRegions(regions), + regions: ty::NonerasedRegions(opt_vec::from(regions)), self_ty: None, tps: type_parameters }; @@ -2258,48 +2219,18 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Look up the number of type parameters and the raw type, and // determine whether the enum is region-parameterized. - let type_parameter_count; - let region_parameterized; - let raw_type; - if enum_id.crate == ast::LOCAL_CRATE { - region_parameterized = - tcx.region_paramd_items.find(&enum_id.node).map(|x| *x); - match tcx.items.find(&enum_id.node) { - Some(&ast_map::node_item(@ast::item { - node: ast::item_enum(_, ref generics), - _ - }, _)) => { - - type_parameter_count = generics.ty_params.len(); - - let regions = bound_self_region(region_parameterized); - - raw_type = ty::mk_enum(tcx, enum_id, substs { - regions: ty::NonerasedRegions(regions), - self_ty: None, - tps: ty::ty_params_to_tys( - tcx, - generics) - }); - } - _ => { - tcx.sess.span_bug(span, - "resolve didn't map this to an enum"); - } - } - } else { - let item_type = ty::lookup_item_type(tcx, enum_id); - type_parameter_count = item_type.generics.type_param_defs.len(); - region_parameterized = item_type.generics.region_param; - raw_type = item_type.ty; - } + let item_type = ty::lookup_item_type(tcx, enum_id); + let type_parameter_count = item_type.generics.type_param_defs.len(); + let region_parameter_count = item_type.generics.region_param_defs.len(); + let raw_type = item_type.ty; // Generate the enum type. - let regions = - fcx.region_var_if_parameterized(region_parameterized, span); + let regions = fcx.infcx().next_region_vars( + infer::BoundRegionInTypeOrImpl(span), + region_parameter_count); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { - regions: ty::NonerasedRegions(regions), + regions: ty::NonerasedRegions(opt_vec::from(regions)), self_ty: None, tps: type_parameters }; @@ -3445,28 +3376,25 @@ pub fn instantiate_path(fcx: @mut FnCtxt, ty_param_count, ty_substs_len); - // determine the region bound, using the value given by the user + // determine the region parameters, using the value given by the user // (if any) and otherwise using a fresh region variable - let regions = match pth.segments.last().lifetime { - Some(_) => { // user supplied a lifetime parameter... - 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"); - opt_vec::Empty - } - Some(_) => { // ...and the type is lifetime parameterized, ok. - opt_vec::with( - ast_region_to_region(fcx, - fcx, - span, - &pth.segments.last().lifetime)) - } - } - } - None => { // no lifetime parameter supplied, insert default - fcx.region_var_if_parameterized(tpt.generics.region_param, span) + let num_expected_regions = tpt.generics.region_param_defs.len(); + let num_supplied_regions = pth.segments.last().lifetimes.len(); + let regions = if num_expected_regions == num_supplied_regions { + pth.segments.last().lifetimes.map( + |l| ast_region_to_region(fcx.tcx(), l)) + } else { + if num_supplied_regions != 0 { + fcx.ccx.tcx.sess.span_err( + span, + format!("expected {} lifetime parameter(s), \ + found {} lifetime parameter(s)", + num_expected_regions, num_supplied_regions)); } + + opt_vec::from(fcx.infcx().next_region_vars( + infer::BoundRegionInTypeOrImpl(span), + num_expected_regions)) }; // Special case: If there is a self parameter, omit it from the list of @@ -3642,18 +3570,14 @@ pub fn check_bounds_are_used(ccx: @mut CrateCtxt, if tps.len() == 0u { return; } let mut tps_used = vec::from_elem(tps.len(), false); - ty::walk_regions_and_ty( - ccx.tcx, ty, - |_r| {}, - |t| { + ty::walk_ty(ty, |t| { match ty::get(t).sty { - ty::ty_param(param_ty {idx, _}) => { - debug!("Found use of ty param \\#{}", idx); - tps_used[idx] = true; - } - _ => () + ty::ty_param(param_ty {idx, _}) => { + debug!("Found use of ty param \\#{}", idx); + tps_used[idx] = true; + } + _ => () } - true }); for (i, b) in tps_used.iter().enumerate() { @@ -3680,19 +3604,19 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { //We only care about the operation here match split[1] { "cxchg" => (0, ~[ty::mk_mut_rptr(tcx, - ty::re_bound(ty::br_anon(0)), + ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()), ty::mk_int(), ty::mk_int() ], ty::mk_int()), "load" => (0, ~[ - ty::mk_imm_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()) + ty::mk_imm_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()) ], ty::mk_int()), "store" => (0, ~[ - ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()), + ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()), ty::mk_int() ], ty::mk_nil()), @@ -3700,7 +3624,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax" | "umin" => { (0, ~[ty::mk_mut_rptr(tcx, - ty::re_bound(ty::br_anon(0)), + ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()), ty::mk_int() ], ty::mk_int()) } "fence" => { @@ -3726,7 +3650,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { "move_val" | "move_val_init" => { (1u, ~[ - ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), param(ccx, 0)), + ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), param(ccx, 0)), param(ccx, 0u) ], ty::mk_nil()) @@ -3738,7 +3662,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { "atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => { (0, ~[ - ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()), + ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()), ty::mk_int() ], ty::mk_int()) @@ -3761,7 +3685,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { Ok(t) => t, Err(s) => { tcx.sess.span_fatal(it.span, s); } }; - let region = ty::re_bound(ty::br_anon(0)); + let region = ty::re_fn_bound(it.id, ty::br_anon(0)); let visitor_object_ty = match ty::visitor_object_ty(tcx, region) { Ok((_, vot)) => vot, Err(s) => { tcx.sess.span_fatal(it.span, s); } @@ -3953,12 +3877,10 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { purity: ast::unsafe_fn, abis: AbiSet::Intrinsic(), - sig: FnSig { - bound_lifetime_names: opt_vec::Empty, - inputs: inputs, - output: output, - variadic: false - } + sig: FnSig {binder_id: it.id, + inputs: inputs, + output: output, + variadic: false} }); let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); let i_n_tps = i_ty.generics.type_param_defs.len(); @@ -3974,3 +3896,4 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { ppaux::ty_to_str(ccx.tcx, fty))); } } + diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index c0aa669d920a..cd94e040ac37 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -535,8 +535,14 @@ fn constrain_call(rcx: &mut Rcx, //! appear in the arguments appropriately. let tcx = rcx.fcx.tcx(); - debug!("constrain_call(call_expr={}, implicitly_ref_args={:?})", - call_expr.repr(tcx), implicitly_ref_args); + debug!("constrain_call(call_expr={}, \ + receiver={}, \ + arg_exprs={}, \ + implicitly_ref_args={:?})", + call_expr.repr(tcx), + receiver.repr(tcx), + arg_exprs.repr(tcx), + implicitly_ref_args); let callee_ty = rcx.resolve_node_type(callee_id); if ty::type_is_error(callee_ty) { // Bail, as function type is unknown @@ -552,6 +558,8 @@ fn constrain_call(rcx: &mut Rcx, let callee_region = ty::re_scope(callee_scope); for &arg_expr in arg_exprs.iter() { + debug!("Argument"); + // ensure that any regions appearing in the argument type are // valid for at least the lifetime of the function: constrain_regions_in_type_of_node( @@ -569,6 +577,7 @@ fn constrain_call(rcx: &mut Rcx, // as loop above, but for receiver for &r in receiver.iter() { + debug!("Receiver"); constrain_regions_in_type_of_node( rcx, r.id, callee_region, infer::CallRcvr(r.span)); if implicitly_ref_args { @@ -727,9 +736,9 @@ fn constrain_regions_in_type( ty_to_str(tcx, ty)); do relate_nested_regions(tcx, Some(minimum_lifetime), ty) |r_sub, r_sup| { - debug!("relate(r_sub={}, r_sup={})", - region_to_str(tcx, "", false, r_sub), - region_to_str(tcx, "", false, r_sup)); + debug!("relate_nested_regions(r_sub={}, r_sup={})", + r_sub.repr(tcx), + r_sup.repr(tcx)); if r_sup.is_bound() || r_sub.is_bound() { // a bound region is one which appears inside an fn type. diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index 9ba709f76510..ea7b2faf2734 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -10,155 +10,41 @@ // #[warn(deprecated_mode)]; - use middle::ty; - -use middle::typeck::isr_alist; -use util::common::indenter; -use util::ppaux::region_to_str; +use middle::ty_fold; +use middle::ty_fold::TypeFolder; +use std::hashmap::HashMap; +use util::ppaux::Repr; use util::ppaux; -use extra::list::Cons; - // Helper functions related to manipulating region types. pub fn replace_bound_regions_in_fn_sig( tcx: ty::ctxt, - isr: isr_alist, opt_self_ty: Option, fn_sig: &ty::FnSig, mapf: &fn(ty::bound_region) -> ty::Region) - -> (isr_alist, Option, ty::FnSig) + -> (HashMap, Option, ty::FnSig) { - let mut all_tys = ty::tys_in_fn_sig(fn_sig); + debug!("replace_bound_regions_in_fn_sig(self_ty={}, fn_sig={})", + opt_self_ty.repr(tcx), + fn_sig.repr(tcx)); - for &t in opt_self_ty.iter() { all_tys.push(t) } - - debug!("replace_bound_regions_in_fn_sig(self_ty={:?}, fn_sig={}, \ - all_tys={:?})", - opt_self_ty.map(|t| ppaux::ty_to_str(tcx, t)), - ppaux::fn_sig_to_str(tcx, fn_sig), - all_tys.map(|t| ppaux::ty_to_str(tcx, *t))); - let _i = indenter(); - - let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| { - debug!("br={:?}", br); - mapf(br) + let mut map = HashMap::new(); + let (fn_sig, opt_self_ty) = { + let mut f = ty_fold::RegionFolder::regions(tcx, |r| { + debug!("region r={}", r.to_str()); + match r { + ty::re_fn_bound(s, br) if s == fn_sig.binder_id => { + *map.find_or_insert_with(br, |_| mapf(br)) + } + _ => r + }}); + (ty_fold::super_fold_sig(&mut f, fn_sig), + ty_fold::fold_opt_ty(&mut f, opt_self_ty)) }; - let new_fn_sig = ty::fold_sig(fn_sig, |t| { - replace_bound_regions(tcx, isr, t) - }); - let new_self_ty = opt_self_ty.map(|t| replace_bound_regions(tcx, isr, t)); - - debug!("result of replace_bound_regions_in_fn_sig: \ - new_self_ty={:?}, \ - fn_sig={}", - new_self_ty.map(|t| ppaux::ty_to_str(tcx, t)), - ppaux::fn_sig_to_str(tcx, &new_fn_sig)); - - return (isr, new_self_ty, new_fn_sig); - - // Takes `isr`, a (possibly empty) mapping from in-scope region - // names ("isr"s) to their corresponding regions; `tys`, a list of - // types, and `to_r`, a closure that takes a bound_region and - // returns a region. Returns an updated version of `isr`, - // extended with the in-scope region names from all of the bound - // regions appearing in the types in the `tys` list (if they're - // not in `isr` already), with each of those in-scope region names - // mapped to a region that's the result of applying `to_r` to - // itself. - fn create_bound_region_mapping( - tcx: ty::ctxt, - isr: isr_alist, - tys: ~[ty::t], - to_r: &fn(ty::bound_region) -> ty::Region) -> isr_alist { - - // Takes `isr` (described above), `to_r` (described above), - // and `r`, a region. If `r` is anything other than a bound - // region, or if it's a bound region that already appears in - // `isr`, then we return `isr` unchanged. If `r` is a bound - // region that doesn't already appear in `isr`, we return an - // updated isr_alist that now contains a mapping from `r` to - // the result of calling `to_r` on it. - fn append_isr(isr: isr_alist, - to_r: &fn(ty::bound_region) -> ty::Region, - r: ty::Region) -> isr_alist { - match r { - ty::re_empty | ty::re_free(*) | ty::re_static | ty::re_scope(_) | - ty::re_infer(_) => { - isr - } - ty::re_bound(br) => { - match isr.find(br) { - Some(_) => isr, - None => @Cons((br, to_r(br)), isr) - } - } - } - } - - // For each type `ty` in `tys`... - do tys.iter().fold(isr) |isr, ty| { - let mut isr = isr; - - // Using fold_regions is inefficient, because it - // constructs new types, but it avoids code duplication in - // terms of locating all the regions within the various - // kinds of types. This had already caused me several - // bugs so I decided to switch over. - do ty::fold_regions(tcx, *ty) |r, in_fn| { - if !in_fn { isr = append_isr(isr, |br| to_r(br), r); } - r - }; - - isr - } - } - - // Takes `isr`, a mapping from in-scope region names ("isr"s) to - // their corresponding regions; and `ty`, a type. Returns an - // updated version of `ty`, in which bound regions in `ty` have - // been replaced with the corresponding bindings in `isr`. - fn replace_bound_regions( - tcx: ty::ctxt, - isr: isr_alist, - ty: ty::t) -> ty::t { - - do ty::fold_regions(tcx, ty) |r, in_fn| { - let r1 = match r { - // As long as we are not within a fn() type, `&T` is - // mapped to the free region anon_r. But within a fn - // type, it remains bound. - ty::re_bound(ty::br_anon(_)) if in_fn => r, - - ty::re_bound(br) => { - match isr.find(br) { - // In most cases, all named, bound regions will be - // mapped to some free region. - Some(fr) => fr, - - // But in the case of a fn() type, there may be - // named regions within that remain bound: - None if in_fn => r, - None => { - tcx.sess.bug( - format!("Bound region not found in \ - in_scope_regions list: {}", - region_to_str(tcx, "", false, r))); - } - } - } - - // Free regions like these just stay the same: - ty::re_empty | - ty::re_static | - ty::re_scope(_) | - ty::re_free(*) | - ty::re_infer(_) => r - }; - r1 - } - } + debug!("resulting map: {}", map.to_str()); + (map, opt_self_ty, fn_sig) } pub fn relate_nested_regions( @@ -168,7 +54,6 @@ pub fn relate_nested_regions( relate_op: &fn(ty::Region, ty::Region)) { /*! - * * This rather specialized function walks each region `r` that appear * in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl` * here is the region of any enclosing `&'r T` pointer. If there is @@ -194,41 +79,66 @@ pub fn relate_nested_regions( * Hence, in the second example above, `'r2` must be a subregion of `'r3`. */ - let mut the_stack = ~[]; - for &r in opt_region.iter() { the_stack.push(r); } - walk_ty(tcx, &mut the_stack, ty, relate_op); + let mut rr = RegionRelator { tcx: tcx, + stack: ~[], + relate_op: relate_op }; + match opt_region { + Some(o_r) => { rr.stack.push(o_r); } + None => {} + } + rr.fold_ty(ty); - fn walk_ty(tcx: ty::ctxt, - the_stack: &mut ~[ty::Region], - ty: ty::t, - relate_op: &fn(ty::Region, ty::Region)) - { - match ty::get(ty).sty { - ty::ty_rptr(r, ref mt) | - ty::ty_evec(ref mt, ty::vstore_slice(r)) => { - relate(*the_stack, r, |x,y| relate_op(x,y)); - the_stack.push(r); - walk_ty(tcx, the_stack, mt.ty, |x,y| relate_op(x,y)); - the_stack.pop(); - } - _ => { - ty::fold_regions_and_ty( - tcx, - ty, - |r| { relate( *the_stack, r, |x,y| relate_op(x,y)); r }, - |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t }, - |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t }); + struct RegionRelator<'self> { + tcx: ty::ctxt, + stack: ~[ty::Region], + relate_op: &'self fn(ty::Region, ty::Region), + } + + // FIXME we should define more precisely when a + // region is considered "nested" and take variance into account. + // + // I can't decide whether skipping closure parameter types and + // so on is necessary or not. What is the difference, after all, + // between `&'a |&'b T|` and `&'a Fn<&'b T>`? And yet in the + // latter case I'm inclined to think we should probably track + // the relationship (but then again maybe we should just skip + // all such cases until it "proves necessary") + + impl<'self> TypeFolder for RegionRelator<'self> { + fn tcx(&self) -> ty::ctxt { + self.tcx + } + + fn fold_ty(&mut self, ty: ty::t) -> ty::t { + match ty::get(ty).sty { + ty::ty_rptr(r, ref mt) | + ty::ty_evec(ref mt, ty::vstore_slice(r)) => { + self.relate(r); + self.stack.push(r); + ty_fold::super_fold_ty(self, mt.ty); + self.stack.pop(); + } + + _ => { + ty_fold::super_fold_ty(self, ty); + } } + + ty + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + self.relate(r); + r } } - fn relate(the_stack: &[ty::Region], - r_sub: ty::Region, - relate_op: &fn(ty::Region, ty::Region)) - { - for &r in the_stack.iter() { - if !r.is_bound() && !r_sub.is_bound() { - relate_op(r, r_sub); + impl<'self> RegionRelator<'self> { + fn relate(&mut self, r_sub: ty::Region) { + for &r in self.stack.iter() { + if !r.is_bound() && !r_sub.is_bound() { + (self.relate_op)(r, r_sub); + } } } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 3c4ff35b768d..ae76c9ed6dd4 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -11,6 +11,7 @@ use middle::ty::param_ty; use middle::ty; +use middle::ty_fold::TypeFolder; use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{structurally_resolved_type}; use middle::typeck::infer::fixup_err_to_str; @@ -68,13 +69,13 @@ pub struct LocationInfo { /// A vtable context includes an inference context, a crate context, and a /// callback function to call in case of type error. -pub struct VtableContext { - ccx: @mut CrateCtxt, - infcx: @mut infer::InferCtxt +pub struct VtableContext<'self> { + infcx: @mut infer::InferCtxt, + param_env: &'self ty::ParameterEnvironment, } -impl VtableContext { - pub fn tcx(&self) -> ty::ctxt { self.ccx.tcx } +impl<'self> VtableContext<'self> { + pub fn tcx(&self) -> ty::ctxt { self.infcx.tcx } } fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool { @@ -95,7 +96,6 @@ fn lookup_vtables(vcx: &VtableContext, substs.repr(vcx.tcx())); let _i = indenter(); - // We do this backwards for reasons discussed above. assert_eq!(substs.tps.len(), type_param_defs.len()); let mut result = @@ -233,8 +233,6 @@ fn lookup_vtable(vcx: &VtableContext, vcx.infcx.trait_ref_to_str(trait_ref)); let _i = indenter(); - let tcx = vcx.tcx(); - let ty = match fixup_ty(vcx, location_info, ty, is_early) { Some(ty) => ty, None => { @@ -250,18 +248,21 @@ fn lookup_vtable(vcx: &VtableContext, // If the type is self or a param, we look at the trait/supertrait // bounds to see if they include the trait we are looking for. let vtable_opt = match ty::get(ty).sty { - ty::ty_param(param_ty {idx: n, def_id: did}) => { - let type_param_def = tcx.ty_param_defs.get(&did.node); - lookup_vtable_from_bounds(vcx, location_info, - type_param_def.bounds.trait_bounds, + ty::ty_param(param_ty {idx: n, _}) => { + let type_param_bounds: &[@ty::TraitRef] = + vcx.param_env.type_param_bounds[n].trait_bounds; + lookup_vtable_from_bounds(vcx, + location_info, + type_param_bounds, param_numbered(n), trait_ref) } - ty::ty_self(trait_id) => { - let self_trait_ref = ty::lookup_trait_def(tcx, trait_id).trait_ref; - lookup_vtable_from_bounds(vcx, location_info, - &[self_trait_ref], + ty::ty_self(_) => { + let self_param_bound = vcx.param_env.self_param_bound.unwrap(); + lookup_vtable_from_bounds(vcx, + location_info, + [self_param_bound], param_self, trait_ref) } @@ -285,7 +286,7 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext, bounds: &[@ty::TraitRef], param: param_index, trait_ref: @ty::TraitRef) - -> Option { + -> Option { let tcx = vcx.tcx(); let mut n_bound = 0; @@ -317,8 +318,7 @@ fn search_for_vtable(vcx: &VtableContext, ty: ty::t, trait_ref: @ty::TraitRef, is_early: bool) - -> Option -{ + -> Option { let tcx = vcx.tcx(); let mut found = ~[]; @@ -494,7 +494,8 @@ fn fixup_substs(vcx: &VtableContext, fn fixup_ty(vcx: &VtableContext, location_info: &LocationInfo, ty: ty::t, - is_early: bool) -> Option { + 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), @@ -515,8 +516,7 @@ fn connect_trait_tps(vcx: &VtableContext, location_info: &LocationInfo, impl_substs: &ty::substs, trait_ref: @ty::TraitRef, - impl_did: ast::DefId) -{ + impl_did: ast::DefId) { let tcx = vcx.tcx(); let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) { @@ -571,7 +571,7 @@ pub fn early_resolve_expr(ex: @ast::Expr, if has_trait_bounds(*item_ty.generics.type_param_defs) { debug!("early_resolve_expr: looking up vtables for type params {}", item_ty.generics.type_param_defs.repr(fcx.tcx())); - let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; + let vcx = fcx.vtable_context(); let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex), *item_ty.generics.type_param_defs, substs, is_early); @@ -599,7 +599,7 @@ pub fn early_resolve_expr(ex: @ast::Expr, ex.repr(fcx.tcx())); if has_trait_bounds(*type_param_defs) { let substs = fcx.node_ty_substs(callee_id); - let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; + let vcx = fcx.vtable_context(); let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex), *type_param_defs, &substs, is_early); if !is_early { @@ -642,10 +642,7 @@ pub fn early_resolve_expr(ex: @ast::Expr, (&ty::ty_rptr(_, mt), ty::RegionTraitStore(*)) => { let location_info = &location_info_for_expr(ex); - let vcx = VtableContext { - ccx: fcx.ccx, - infcx: fcx.infcx() - }; + let vcx = fcx.vtable_context(); let target_trait_ref = @ty::TraitRef { def_id: target_def_id, substs: ty::substs { @@ -726,48 +723,58 @@ fn resolve_expr(fcx: @mut FnCtxt, visit::walk_expr(&mut fcx, ex, ()); } -pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { - let def_id = ast_util::local_def(impl_item.id); - match ty::impl_trait_ref(ccx.tcx, def_id) { - None => {}, - Some(trait_ref) => { - let infcx = infer::new_infer_ctxt(ccx.tcx); - let vcx = VtableContext { ccx: ccx, infcx: infcx }; - let loc_info = location_info_for_item(impl_item); +pub fn resolve_impl(ccx: @mut CrateCtxt, + impl_item: @ast::item, + impl_generics: &ty::Generics, + impl_trait_ref: &ty::TraitRef) { + let param_env = ty::construct_parameter_environment( + ccx.tcx, + None, + *impl_generics.type_param_defs, + [], + impl_generics.region_param_defs, + impl_item.id); - // First, check that the impl implements any trait bounds - // on the trait. - let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id); - let vtbls = lookup_vtables(&vcx, - &loc_info, - *trait_def.generics.type_param_defs, - &trait_ref.substs, - false); + let impl_trait_ref = @impl_trait_ref.subst(ccx.tcx, ¶m_env.free_substs); - // Now, locate the vtable for the impl itself. The real - // purpose of this is to check for supertrait impls, - // but that falls out of doing this. - let param_bounds = ty::ParamBounds { - builtin_bounds: ty::EmptyBuiltinBounds(), - trait_bounds: ~[trait_ref] - }; - let t = ty::node_id_to_type(ccx.tcx, impl_item.id); - debug!("=== Doing a self lookup now."); - // Right now, we don't have any place to store this. - // We will need to make one so we can use this information - // for compiling default methods that refer to supertraits. - let self_vtable_res = - lookup_vtables_for_param(&vcx, &loc_info, None, - ¶m_bounds, t, false); + let infcx = infer::new_infer_ctxt(ccx.tcx); + let vcx = VtableContext { infcx: infcx, param_env: ¶m_env }; + let loc_info = location_info_for_item(impl_item); + + // First, check that the impl implements any trait bounds + // on the trait. + let trait_def = ty::lookup_trait_def(ccx.tcx, impl_trait_ref.def_id); + let vtbls = lookup_vtables(&vcx, + &loc_info, + *trait_def.generics.type_param_defs, + &impl_trait_ref.substs, + false); + + // Now, locate the vtable for the impl itself. The real + // purpose of this is to check for supertrait impls, + // but that falls out of doing this. + let param_bounds = ty::ParamBounds { + builtin_bounds: ty::EmptyBuiltinBounds(), + trait_bounds: ~[impl_trait_ref] + }; + let t = ty::node_id_to_type(ccx.tcx, impl_item.id); + let t = t.subst(ccx.tcx, ¶m_env.free_substs); + debug!("=== Doing a self lookup now."); + + // Right now, we don't have any place to store this. + // We will need to make one so we can use this information + // for compiling default methods that refer to supertraits. + let self_vtable_res = + lookup_vtables_for_param(&vcx, &loc_info, None, + ¶m_bounds, t, false); - let res = impl_res { - trait_vtables: vtbls, - self_vtables: self_vtable_res - }; - ccx.tcx.impl_vtables.insert(def_id, res); - } - } + let res = impl_res { + trait_vtables: vtbls, + self_vtables: self_vtable_res + }; + let impl_def_id = ast_util::local_def(impl_item.id); + ccx.tcx.impl_vtables.insert(impl_def_id, res); } impl visit::Visitor<()> for @mut FnCtxt { diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 795074fa6190..b959c80db38a 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -357,8 +357,8 @@ impl CoherenceChecker { @vec::append( (*impl_poly_type.generics.type_param_defs).clone(), *new_method_ty.generics.type_param_defs), - region_param: - impl_poly_type.generics.region_param + region_param_defs: + impl_poly_type.generics.region_param_defs }; let new_polytype = ty::ty_param_bounds_and_ty { generics: new_generics, @@ -482,20 +482,17 @@ impl CoherenceChecker { pub fn universally_quantify_polytype(&self, polytype: ty_param_bounds_and_ty) -> UniversalQuantificationResult { - let regions = match polytype.generics.region_param { - None => opt_vec::Empty, - Some(_) => { - opt_vec::with( - self.inference_context.next_region_var( - infer::BoundRegionInCoherence)) - } - }; + let region_parameter_count = polytype.generics.region_param_defs.len(); + let region_parameters = + self.inference_context.next_region_vars( + infer::BoundRegionInCoherence, + region_parameter_count); let bounds_count = polytype.generics.type_param_defs.len(); let type_parameters = self.inference_context.next_ty_vars(bounds_count); let substitutions = substs { - regions: ty::NonerasedRegions(regions), + regions: ty::NonerasedRegions(opt_vec::from(region_parameters)), self_ty: None, tps: type_parameters }; diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 353639051097..c1908e69f1e0 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -39,15 +39,10 @@ use middle::subst::Subst; use middle::typeck::astconv::{AstConv, ty_of_arg}; use middle::typeck::astconv::{ast_ty_to_ty}; 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}; -use util::common::pluralize; use util::ppaux; -use util::ppaux::UserString; -use std::result; use std::vec; use syntax::abi::AbiSet; use syntax::ast::{RegionTyParamBound, TraitTyParamBound}; @@ -56,10 +51,9 @@ use syntax::ast_map; use syntax::ast_util::{local_def, split_trait_methods}; use syntax::codemap::Span; use syntax::codemap; -use syntax::print::pprust::{path_to_str, explicit_self_to_str}; +use syntax::print::pprust::{path_to_str}; use syntax::visit; use syntax::opt_vec::OptVec; -use syntax::opt_vec; use syntax::parse::token::special_idents; struct CollectItemTypesVisitor { @@ -97,19 +91,11 @@ pub fn collect_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) { } pub trait ToTy { - fn to_ty( - &self, - rs: &RS, - ast_ty: &ast::Ty) - -> ty::t; + fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t; } impl ToTy for CrateCtxt { - fn to_ty( - &self, - rs: &RS, - ast_ty: &ast::Ty) - -> ty::t { + fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t { ast_ty_to_ty(self, rs, ast_ty) } } @@ -149,59 +135,45 @@ impl AstConv for CrateCtxt { pub fn get_enum_variant_types(ccx: &CrateCtxt, enum_ty: ty::t, variants: &[ast::variant], - generics: &ast::Generics, - rp: Option) { + generics: &ast::Generics) { let tcx = ccx.tcx; // Create a set of parameter types shared among all the variants. for variant in variants.iter() { - let region_parameterization = - RegionParameterization::from_variance_and_generics(rp, generics); - // Nullary enum constructors get turned into constants; n-ary enum // constructors get turned into functions. - let result_ty; - match variant.node.kind { + let scope = variant.node.id; + let result_ty = match variant.node.kind { ast::tuple_variant_kind(ref args) if args.len() > 0 => { - let rs = TypeRscope(region_parameterization); + let rs = ExplicitRscope; let input_tys = args.map(|va| ccx.to_ty(&rs, &va.ty)); - result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty)); + ty::mk_ctor_fn(tcx, scope, input_tys, enum_ty) } ast::tuple_variant_kind(_) => { - result_ty = Some(enum_ty); + enum_ty } ast::struct_variant_kind(struct_def) => { let tpt = ty_param_bounds_and_ty { - generics: ty_generics(ccx, rp, generics, 0), + generics: ty_generics(ccx, generics, 0), ty: enum_ty }; - convert_struct(ccx, - rp, - struct_def, - generics, - tpt, - variant.node.id); + convert_struct(ccx, struct_def, tpt, variant.node.id); let input_tys = struct_def.fields.map( |f| ty::node_id_to_type(ccx.tcx, f.node.id)); - result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty)); + ty::mk_ctor_fn(tcx, scope, input_tys, enum_ty) } }; - match result_ty { - None => {} - Some(result_ty) => { - let tpt = ty_param_bounds_and_ty { - generics: ty_generics(ccx, rp, generics, 0), - ty: result_ty - }; - tcx.tcache.insert(local_def(variant.node.id), tpt); - write_ty_to_tcx(tcx, variant.node.id, result_ty); - } - } + let tpt = ty_param_bounds_and_ty { + generics: ty_generics(ccx, generics, 0), + ty: result_ty + }; + tcx.tcache.insert(local_def(variant.node.id), tpt); + write_ty_to_tcx(tcx, variant.node.id, result_ty); } } @@ -209,13 +181,13 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { let tcx = ccx.tcx; - let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|x| *x); match tcx.items.get_copy(&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, 0); + let trait_ty_generics = + ty_generics(ccx, generics, 0); // For each method, construct a suitable ty::Method and // store it into the `tcx.methods` table: @@ -223,14 +195,14 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, let ty_method = @match m { &ast::required(ref m) => { ty_method_of_trait_method( - ccx, trait_id, region_paramd, generics, + ccx, trait_id, &trait_ty_generics, &m.id, &m.ident, &m.explicit_self, &m.generics, &m.purity, &m.decl) } &ast::provided(ref m) => { ty_method_of_trait_method( - ccx, trait_id, region_paramd, generics, + ccx, trait_id, &trait_ty_generics, &m.id, &m.ident, &m.explicit_self, &m.generics, &m.purity, &m.decl) } @@ -264,13 +236,13 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_ty_generics: &ty::Generics) { // If declaration is // - // trait { - // fn foo(...) -> Self; + // trait<'a,'b,'c,A,B,C> { + // fn foo<'d,'e,'f,D,E,F>(...) -> Self; // } // // and we will create a function like // - // fn foo(...) -> D' {} + // fn foo<'a,'b,'c,'d,'e,'f,A',B',C',D',E',F',G'>(...) -> D' {} // // Note that `Self` is replaced with an explicit type // parameter D' that is sandwiched in between the trait params @@ -307,12 +279,19 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, m.generics.type_param_defs[i].def_id) }; + // Convert the regions 'a, 'b, 'c defined on the trait into + // bound regions on the fn. + let rps_from_trait = trait_ty_generics.region_param_defs.iter().map(|d| { + ty::re_fn_bound(m.fty.sig.binder_id, + ty::br_named(d.def_id, d.ident)) + }).collect(); + // build up the substitution from // A,B,C => A',B',C' // Self => D' // D,E,F => E',F',G' let substs = substs { - regions: ty::NonerasedRegions(opt_vec::Empty), + regions: ty::NonerasedRegions(rps_from_trait), self_ty: Some(self_param), tps: non_shifted_trait_tps + shifted_method_tps }; @@ -357,7 +336,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, ty_param_bounds_and_ty { generics: ty::Generics { type_param_defs: @new_type_param_defs, - region_param: trait_ty_generics.region_param + region_param_defs: @[], // fn items }, ty: ty }); @@ -365,8 +344,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, fn ty_method_of_trait_method(this: &CrateCtxt, trait_id: ast::NodeId, - trait_rp: Option, - trait_generics: &ast::Generics, + trait_generics: &ty::Generics, m_id: &ast::NodeId, m_ident: &ast::Ident, m_explicit_self: &ast::explicit_self, @@ -375,14 +353,14 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, m_decl: &ast::fn_decl) -> ty::Method { let trait_self_ty = ty::mk_self(this.tcx, local_def(trait_id)); - let rscope = MethodRscope::new(m_explicit_self.node, trait_rp, trait_generics); let (transformed_self_ty, fty) = - astconv::ty_of_method(this, &rscope, *m_purity, &m_generics.lifetimes, + astconv::ty_of_method(this, *m_id, *m_purity, trait_self_ty, *m_explicit_self, m_decl); - let num_trait_type_params = trait_generics.ty_params.len(); + let num_trait_type_params = trait_generics.type_param_defs.len(); ty::Method::new( *m_ident, - ty_generics(this, None, m_generics, num_trait_type_params), + // FIXME -- what about lifetime parameters here? + ty_generics(this, m_generics, num_trait_type_params), transformed_self_ty, fty, m_explicit_self.node, @@ -398,9 +376,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, pub fn ensure_supertraits(ccx: &CrateCtxt, id: ast::NodeId, sp: codemap::Span, - rp: Option, - ast_trait_refs: &[ast::trait_ref], - generics: &ast::Generics) -> ty::BuiltinBounds + ast_trait_refs: &[ast::trait_ref]) + -> ty::BuiltinBounds { let tcx = ccx.tcx; @@ -416,8 +393,7 @@ pub fn ensure_supertraits(ccx: &CrateCtxt, // FIXME(#8559): Need to instantiate the trait_ref whether or not it's a // builtin trait, so that the trait's node id appears in the tcx trait_ref // map. This is only needed for metadata; see the similar fixme in encoder.rs. - let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, rp, - generics, self_ty); + let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, self_ty); if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) { // FIXME(#5527) Could have same trait multiple times @@ -720,91 +696,68 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, } // fn pub fn convert_field(ccx: &CrateCtxt, - rp: Option, - type_param_defs: @~[ty::TypeParameterDef], - v: &ast::struct_field, - generics: &ast::Generics) { - let region_parameterization = - RegionParameterization::from_variance_and_generics(rp, generics); - let tt = ccx.to_ty(&TypeRscope(region_parameterization), &v.node.ty); + struct_generics: &ty::Generics, + v: &ast::struct_field) { + let tt = ccx.to_ty(&ExplicitRscope, &v.node.ty); write_ty_to_tcx(ccx.tcx, v.node.id, tt); /* add the field to the tcache */ ccx.tcx.tcache.insert(local_def(v.node.id), ty::ty_param_bounds_and_ty { - generics: ty::Generics { - type_param_defs: type_param_defs, - region_param: rp - }, + generics: struct_generics.clone(), ty: tt }); } -pub struct ConvertedMethod { - mty: @ty::Method, - id: ast::NodeId, - span: Span, - body_id: ast::NodeId -} - -pub fn convert_methods(ccx: &CrateCtxt, - container: MethodContainer, - ms: &[@ast::method], - untransformed_rcvr_ty: ty::t, - rcvr_ty_generics: &ty::Generics, - rcvr_ast_generics: &ast::Generics, - rcvr_visibility: ast::visibility) - -> ~[ConvertedMethod] +fn convert_methods(ccx: &CrateCtxt, + container: MethodContainer, + ms: &[@ast::method], + untransformed_rcvr_ty: ty::t, + rcvr_ty_generics: &ty::Generics, + rcvr_ast_generics: &ast::Generics, + rcvr_visibility: ast::visibility) { let tcx = ccx.tcx; - return ms.iter().map(|m| { + for m in ms.iter() { let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs.len(); - let m_ty_generics = - ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics, - num_rcvr_ty_params); + let m_ty_generics = ty_generics(ccx, &m.generics, num_rcvr_ty_params); let mty = @ty_of_method(ccx, container, *m, - rcvr_ty_generics.region_param, untransformed_rcvr_ty, rcvr_ast_generics, - rcvr_visibility, - &m.generics); + rcvr_visibility); let fty = ty::mk_bare_fn(tcx, mty.fty.clone()); + debug!("method {} (id {}) has type {}", + m.ident.repr(ccx.tcx), + m.id, + fty.repr(ccx.tcx)); 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 + // the parameters on the receiver and those on the method itself ty_param_bounds_and_ty { generics: ty::Generics { type_param_defs: @vec::append( (*rcvr_ty_generics.type_param_defs).clone(), *m_ty_generics.type_param_defs), - region_param: rcvr_ty_generics.region_param + region_param_defs: rcvr_ty_generics.region_param_defs, }, 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.id} - }).collect(); + } fn ty_of_method(ccx: &CrateCtxt, container: MethodContainer, m: &ast::method, - rp: Option, untransformed_rcvr_ty: ty::t, rcvr_generics: &ast::Generics, - rcvr_visibility: ast::visibility, - method_generics: &ast::Generics) -> ty::Method + rcvr_visibility: ast::visibility) -> ty::Method { - let rscope = MethodRscope::new(m.explicit_self.node, - rp, - rcvr_generics); let (transformed_self_ty, fty) = - astconv::ty_of_method(ccx, &rscope, m.purity, - &method_generics.lifetimes, + astconv::ty_of_method(ccx, m.id, m.purity, untransformed_rcvr_ty, m.explicit_self, &m.decl); @@ -817,7 +770,8 @@ pub fn convert_methods(ccx: &CrateCtxt, let num_rcvr_type_params = rcvr_generics.ty_params.len(); ty::Method::new( m.ident, - ty_generics(ccx, None, &m.generics, num_rcvr_type_params), + // FIXME region param + ty_generics(ccx, &m.generics, num_rcvr_type_params), transformed_self_ty, fty, m.explicit_self.node, @@ -845,27 +799,22 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, pub fn convert(ccx: &CrateCtxt, it: &ast::item) { let tcx = ccx.tcx; - let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x); - debug!("convert: item {} with id {} rp {:?}", - tcx.sess.str_of(it.ident), it.id, rp); + debug!("convert: item {} with id {}", tcx.sess.str_of(it.ident), it.id); match it.node { - // These don't define types. - ast::item_foreign_mod(_) | ast::item_mod(_) => {} - ast::item_enum(ref enum_definition, ref generics) => { - ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration"); - let tpt = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, tpt.ty); - get_enum_variant_types(ccx, - tpt.ty, - enum_definition.variants, - generics, - rp); - } + // These don't define types. + ast::item_foreign_mod(_) | ast::item_mod(_) => {} + ast::item_enum(ref enum_definition, ref generics) => { + ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration"); + let tpt = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + get_enum_variant_types(ccx, + tpt.ty, + enum_definition.variants, + generics); + } ast::item_impl(ref generics, ref opt_trait_ref, ref selfty, ref ms) => { - let i_ty_generics = ty_generics(ccx, rp, generics, 0); - let region_parameterization = - RegionParameterization::from_variance_and_generics(rp, generics); - let selfty = ccx.to_ty(&TypeRscope(region_parameterization), selfty); + let i_ty_generics = ty_generics(ccx, generics, 0); + let selfty = ccx.to_ty(&ExplicitRscope, selfty); write_ty_to_tcx(tcx, it.id, selfty); tcx.tcache.insert(local_def(it.id), ty_param_bounds_and_ty { @@ -883,17 +832,19 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) { it.vis }; - let cms = convert_methods(ccx, - ImplContainer(local_def(it.id)), - *ms, - selfty, - &i_ty_generics, - generics, - parent_visibility); - for t in opt_trait_ref.iter() { + convert_methods(ccx, + ImplContainer(local_def(it.id)), + *ms, + selfty, + &i_ty_generics, + generics, + parent_visibility); + + for trait_ref in opt_trait_ref.iter() { + let trait_ref = instantiate_trait_ref(ccx, trait_ref, selfty); + // Prevent the builtin kind traits from being manually implemented. - let trait_def_id = ty::trait_ref_to_def_id(tcx, t); - if tcx.lang_items.to_builtin_kind(trait_def_id).is_some() { + if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_some() { tcx.sess.span_err(it.span, "cannot provide an explicit implementation \ for a builtin kind"); @@ -903,21 +854,19 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) { } } ast::item_trait(ref generics, _, ref trait_methods) => { - let _trait_def = trait_def_of_item(ccx, it); + let trait_def = trait_def_of_item(ccx, it); // Run convert_methods on the provided methods. let (_, provided_methods) = split_trait_methods(*trait_methods); let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id)); - let (ty_generics, _) = mk_item_substs(ccx, generics, rp, - Some(untransformed_rcvr_ty)); - let _ = convert_methods(ccx, - TraitContainer(local_def(it.id)), - provided_methods, - untransformed_rcvr_ty, - &ty_generics, - generics, - it.vis); + convert_methods(ccx, + TraitContainer(local_def(it.id)), + provided_methods, + untransformed_rcvr_ty, + &trait_def.generics, + generics, + it.vis); // We need to do this *after* converting methods, since // convert_methods produces a tcache entry that is wrong for @@ -932,7 +881,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) { write_ty_to_tcx(tcx, it.id, tpt.ty); tcx.tcache.insert(local_def(it.id), tpt); - convert_struct(ccx, rp, struct_def, generics, tpt, it.id); + convert_struct(ccx, struct_def, tpt, it.id); } ast::item_ty(_, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); @@ -950,18 +899,16 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) { } pub fn convert_struct(ccx: &CrateCtxt, - rp: Option, struct_def: &ast::struct_def, - generics: &ast::Generics, tpt: ty::ty_param_bounds_and_ty, id: ast::NodeId) { let tcx = ccx.tcx; // Write the type of each of the members for f in struct_def.fields.iter() { - convert_field(ccx, rp, tpt.generics.type_param_defs, *f, generics); + convert_field(ccx, &tpt.generics, *f); } - let (_, substs) = mk_item_substs(ccx, generics, rp, None); + let substs = mk_item_substs(ccx, &tpt.generics, None); let selfty = ty::mk_struct(tcx, local_def(id), substs); // If this struct is enum-like or tuple-like, create the type of its @@ -979,7 +926,7 @@ pub fn convert_struct(ccx: &CrateCtxt, struct_def.fields.map( |field| ccx.tcx.tcache.get( &local_def(field.node.id)).ty); - let ctor_fn_ty = ty::mk_ctor_fn(tcx, inputs, selfty); + let ctor_fn_ty = ty::mk_ctor_fn(tcx, ctor_id, inputs, selfty); write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); tcx.tcache.insert(local_def(ctor_id), ty_param_bounds_and_ty { generics: tpt.generics, @@ -1014,8 +961,6 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::foreign_item) { pub fn instantiate_trait_ref(ccx: &CrateCtxt, ast_trait_ref: &ast::trait_ref, - rp: Option, - generics: &ast::Generics, self_ty: ty::t) -> @ty::TraitRef { /*! @@ -1024,9 +969,7 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt, * trait. Fails if the type is a type other than an trait type. */ - let rp = RegionParameterization::from_variance_and_generics(rp, generics); - - let rscope = TypeRscope(rp); + let rscope = ExplicitRscope; // FIXME match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) { ast::DefTrait(trait_did) => { @@ -1066,14 +1009,12 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::item) -> @ty::TraitDef { Some(&def) => return def, _ => {} } - let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x); match it.node { ast::item_trait(ref generics, ref supertraits, _) => { let self_ty = ty::mk_self(tcx, def_id); - let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, - Some(self_ty)); - let bounds = ensure_supertraits(ccx, it.id, it.span, rp, - *supertraits, generics); + let ty_generics = ty_generics(ccx, generics, 0); + let substs = mk_item_substs(ccx, &ty_generics, Some(self_ty)); + let bounds = ensure_supertraits(ccx, it.id, it.span, *supertraits); let trait_ref = @ty::TraitRef {def_id: def_id, substs: substs}; let trait_def = @ty::TraitDef {generics: ty_generics, @@ -1091,93 +1032,89 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::item) -> @ty::TraitDef { } pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::item) - -> ty::ty_param_bounds_and_ty { + -> ty::ty_param_bounds_and_ty { let def_id = local_def(it.id); let tcx = ccx.tcx; match tcx.tcache.find(&def_id) { - Some(&tpt) => return tpt, - _ => {} + Some(&tpt) => return tpt, + _ => {} } - let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x); match it.node { - ast::item_static(ref t, _, _) => { - let typ = ccx.to_ty(&EmptyRscope, t); - let tpt = no_params(typ); - tcx.tcache.insert(local_def(it.id), tpt); - return tpt; - } - ast::item_fn(ref decl, purity, abi, ref generics, _) => { - assert!(rp.is_none()); - let ty_generics = ty_generics(ccx, None, generics, 0); - let tofd = astconv::ty_of_bare_fn(ccx, - &EmptyRscope, - purity, - abi, - &generics.lifetimes, - decl); - let tpt = ty_param_bounds_and_ty { - generics: ty::Generics { - type_param_defs: ty_generics.type_param_defs, - region_param: None - }, - ty: ty::mk_bare_fn(ccx.tcx, tofd) - }; - debug!("type of {} (id {}) is {}", - tcx.sess.str_of(it.ident), - it.id, - ppaux::ty_to_str(tcx, tpt.ty)); - ccx.tcx.tcache.insert(local_def(it.id), tpt); - return tpt; - } - ast::item_ty(ref t, ref generics) => { - match tcx.tcache.find(&local_def(it.id)) { - Some(&tpt) => return tpt, - None => { } + ast::item_static(ref t, _, _) => { + let typ = ccx.to_ty(&ExplicitRscope, t); + let tpt = no_params(typ); + tcx.tcache.insert(local_def(it.id), tpt); + return tpt; } - - let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x); - let region_parameterization = - RegionParameterization::from_variance_and_generics(rp, generics); - let tpt = { - let ty = ccx.to_ty(&TypeRscope(region_parameterization), t); - ty_param_bounds_and_ty { - generics: ty_generics(ccx, rp, generics, 0), - ty: ty + ast::item_fn(ref decl, purity, abi, ref generics, _) => { + let ty_generics = ty_generics(ccx, generics, 0); + let tofd = astconv::ty_of_bare_fn(ccx, + it.id, + purity, + abi, + decl); + let tpt = ty_param_bounds_and_ty { + generics: ty::Generics { + type_param_defs: ty_generics.type_param_defs, + region_param_defs: @[], + }, + ty: ty::mk_bare_fn(ccx.tcx, tofd) + }; + debug!("type of {} (id {}) is {}", + tcx.sess.str_of(it.ident), + it.id, + ppaux::ty_to_str(tcx, tpt.ty)); + ccx.tcx.tcache.insert(local_def(it.id), tpt); + return tpt; + } + ast::item_ty(ref t, ref generics) => { + match tcx.tcache.find(&local_def(it.id)) { + Some(&tpt) => return tpt, + None => { } } - }; - tcx.tcache.insert(local_def(it.id), tpt); - return tpt; - } - ast::item_enum(_, ref generics) => { - // Create a new generic polytype. - let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None); - let t = ty::mk_enum(tcx, local_def(it.id), substs); - let tpt = ty_param_bounds_and_ty { - generics: ty_generics, - ty: t - }; - tcx.tcache.insert(local_def(it.id), tpt); - return tpt; - } - ast::item_trait(*) => { - tcx.sess.span_bug( - it.span, - format!("Invoked ty_of_item on trait")); - } - ast::item_struct(_, ref generics) => { - let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None); - let t = ty::mk_struct(tcx, local_def(it.id), substs); - let tpt = ty_param_bounds_and_ty { - generics: ty_generics, - ty: t - }; - tcx.tcache.insert(local_def(it.id), tpt); - return tpt; - } - ast::item_impl(*) | ast::item_mod(_) | - ast::item_foreign_mod(_) => fail!(), - ast::item_mac(*) => fail!("item macros unimplemented") + let tpt = { + let ty = ccx.to_ty(&ExplicitRscope, t); + ty_param_bounds_and_ty { + generics: ty_generics(ccx, generics, 0), + ty: ty + } + }; + + tcx.tcache.insert(local_def(it.id), tpt); + return tpt; + } + ast::item_enum(_, ref generics) => { + // Create a new generic polytype. + let ty_generics = ty_generics(ccx, generics, 0); + let substs = mk_item_substs(ccx, &ty_generics, None); + let t = ty::mk_enum(tcx, local_def(it.id), substs); + let tpt = ty_param_bounds_and_ty { + generics: ty_generics, + ty: t + }; + tcx.tcache.insert(local_def(it.id), tpt); + return tpt; + } + ast::item_trait(*) => { + tcx.sess.span_bug( + it.span, + format!("Invoked ty_of_item on trait")); + } + ast::item_struct(_, ref generics) => { + let ty_generics = ty_generics(ccx, generics, 0); + let substs = mk_item_substs(ccx, &ty_generics, None); + let t = ty::mk_struct(tcx, local_def(it.id), substs); + let tpt = ty_param_bounds_and_ty { + generics: ty_generics, + ty: t + }; + tcx.tcache.insert(local_def(it.id), tpt); + return tpt; + } + ast::item_impl(*) | ast::item_mod(_) | + ast::item_foreign_mod(_) => fail!(), + ast::item_mac(*) => fail!("item macros unimplemented") } } @@ -1197,28 +1134,29 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, ty::ty_param_bounds_and_ty { generics: ty::Generics { type_param_defs: @~[], - region_param: None, + region_param_defs: @[], }, - ty: ast_ty_to_ty(ccx, &EmptyRscope, t) + ty: ast_ty_to_ty(ccx, &ExplicitRscope, t) } } } } pub fn ty_generics(ccx: &CrateCtxt, - rp: Option, generics: &ast::Generics, base_index: uint) -> ty::Generics { return ty::Generics { - region_param: rp, + region_param_defs: generics.lifetimes.iter().map(|l| { + ty::RegionParameterDef { ident: l.ident, + def_id: local_def(l.id) } + }).collect(), type_param_defs: @generics.ty_params.mapi_to_vec(|offset, param| { match ccx.tcx.ty_param_defs.find(¶m.id) { Some(&def) => def, None => { let param_ty = ty::param_ty {idx: base_index + offset, def_id: local_def(param.id)}; - let bounds = @compute_bounds(ccx, rp, generics, - param_ty, ¶m.bounds); + let bounds = @compute_bounds(ccx, param_ty, ¶m.bounds); let def = ty::TypeParameterDef { ident: param.ident, def_id: local_def(param.id), @@ -1234,13 +1172,10 @@ pub fn ty_generics(ccx: &CrateCtxt, fn compute_bounds( ccx: &CrateCtxt, - rp: Option, - generics: &ast::Generics, param_ty: ty::param_ty, ast_bounds: &OptVec) -> ty::ParamBounds { /*! - * * 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 @@ -1256,7 +1191,7 @@ pub fn ty_generics(ccx: &CrateCtxt, match *ast_bound { TraitTyParamBound(ref b) => { let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id); - let trait_ref = instantiate_trait_ref(ccx, b, rp, generics, ty); + let trait_ref = instantiate_trait_ref(ccx, b, ty); if !ty::try_add_builtin_trait( ccx.tcx, trait_ref.def_id, &mut param_bounds.builtin_bounds) @@ -1282,9 +1217,8 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, ast_generics: &ast::Generics, abis: AbiSet) -> ty::ty_param_bounds_and_ty { - let ty_generics = ty_generics(ccx, None, ast_generics, 0); - let region_param_names = RegionParamNames::from_generics(ast_generics); - let rb = in_binding_rscope(&EmptyRscope, region_param_names); + let ty_generics = ty_generics(ccx, ast_generics, 0); + let rb = BindingRscope::new(def_id.node); 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); @@ -1293,12 +1227,10 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, ty::BareFnTy { abis: abis, purity: ast::unsafe_fn, - sig: ty::FnSig { - bound_lifetime_names: opt_vec::Empty, - inputs: input_tys, - output: output_ty, - variadic: decl.variadic - } + sig: ty::FnSig {binder_id: def_id.node, + inputs: input_tys, + output: output_ty, + variadic: decl.variadic} }); let tpt = ty_param_bounds_and_ty { generics: ty_generics, @@ -1309,19 +1241,18 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, } pub fn mk_item_substs(ccx: &CrateCtxt, - ast_generics: &ast::Generics, - rp: Option, - self_ty: Option) -> (ty::Generics, ty::substs) + ty_generics: &ty::Generics, + self_ty: Option) -> ty::substs { - let mut i = 0; - let ty_generics = ty_generics(ccx, rp, ast_generics, 0); - 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 regions = rscope::bound_self_region(rp); - (ty_generics, substs {regions: ty::NonerasedRegions(regions), - self_ty: self_ty, - tps: params}) + let params: ~[ty::t] = + ty_generics.type_param_defs.iter().enumerate().map( + |(i, t)| ty::mk_param(ccx.tcx, i, t.def_id)).collect(); + + let regions: OptVec = + ty_generics.region_param_defs.iter().enumerate().map( + |(i, l)| ty::re_type_bound(l.def_id.node, i, l.ident)).collect(); + + substs {regions: ty::NonerasedRegions(regions), + self_ty: self_ty, + tps: params} } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 5d0f44ae7e35..d6d1618de710 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -429,23 +429,20 @@ pub fn super_fn_sigs(this: &C, a: &ty::FnSig, b: &ty::FnSig) -> cres< return Err(ty::terr_variadic_mismatch(expected_found(this, a.variadic, b.variadic))); } - do argvecs(this, a.inputs, b.inputs) - .and_then |inputs| { - do this.tys(a.output, b.output).and_then |output| { - Ok(FnSig { - bound_lifetime_names: opt_vec::Empty, // FIXME(#4846) - inputs: inputs.clone(), - output: output, - variadic: a.variadic - }) - } - } + let inputs = if_ok!(argvecs(this, a.inputs, b.inputs)); + let output = if_ok!(this.tys(a.output, b.output)); + Ok(FnSig {binder_id: a.binder_id, + inputs: inputs, + output: output, + variadic: a.variadic}) } -pub fn super_tys( - this: &C, a: ty::t, b: ty::t) -> cres { +pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { let tcx = this.infcx().tcx; - return match (&ty::get(a).sty, &ty::get(b).sty) { + let a_sty = &ty::get(a).sty; + let b_sty = &ty::get(b).sty; + debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); + return match (a_sty, b_sty) { // The "subtype" ought to be handling cases involving bot or var: (&ty::ty_bot, _) | (_, &ty::ty_bot) | @@ -494,6 +491,7 @@ pub fn super_tys( unify_float_variable(this, !this.a_is_expected(), v_id, v) } + (&ty::ty_char, _) | (&ty::ty_nil, _) | (&ty::ty_bool, _) | (&ty::ty_int(_), _) | diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 87c7373b005d..78e0bd17ecaa 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -20,15 +20,13 @@ use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::{cres, InferCtxt}; use middle::typeck::infer::{TypeTrace, Subtype}; use middle::typeck::infer::fold_regions_in_sig; -use middle::typeck::isr_alist; use syntax::ast::{Many, Once, extern_fn, impure_fn, MutImmutable, MutMutable}; -use syntax::ast::{unsafe_fn}; +use syntax::ast::{unsafe_fn, NodeId}; use syntax::ast::{Onceness, purity}; +use std::hashmap::HashMap; use util::common::{indenter}; use util::ppaux::mt_to_str; -use extra::list; - pub struct Glb(CombineFields); // "greatest lower bound" (common subtype) impl Combine for Glb { @@ -132,14 +130,14 @@ impl Combine for Glb { let snapshot = self.infcx.region_vars.start_snapshot(); // Instantiate each bound region with a fresh region variable. - let (a_with_fresh, a_isr) = + let (a_with_fresh, a_map) = self.infcx.replace_bound_regions_with_fresh_regions( self.trace, a); - let a_vars = var_ids(self, a_isr); - let (b_with_fresh, b_isr) = + let a_vars = var_ids(self, &a_map); + let (b_with_fresh, b_map) = self.infcx.replace_bound_regions_with_fresh_regions( self.trace, b); - let b_vars = var_ids(self, b_isr); + let b_vars = var_ids(self, &b_map); // Collect constraints. let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh)); @@ -152,20 +150,23 @@ impl Combine for Glb { fold_regions_in_sig( self.infcx.tcx, &sig0, - |r, _in_fn| generalize_region(self, snapshot, - new_vars, a_isr, a_vars, b_vars, - r)); + |r| generalize_region(self, snapshot, + new_vars, sig0.binder_id, + &a_map, a_vars, b_vars, + r)); debug!("sig1 = {}", sig1.inf_str(self.infcx)); return Ok(sig1); fn generalize_region(this: &Glb, snapshot: uint, new_vars: &[RegionVid], - a_isr: isr_alist, + new_binder_id: NodeId, + a_map: &HashMap, a_vars: &[RegionVid], b_vars: &[RegionVid], r0: ty::Region) -> ty::Region { if !is_var_in_set(new_vars, r0) { + assert!(!r0.is_bound()); return r0; } @@ -177,13 +178,13 @@ impl Combine for Glb { for r in tainted.iter() { if is_var_in_set(a_vars, *r) { if a_r.is_some() { - return fresh_bound_variable(this); + return fresh_bound_variable(this, new_binder_id); } else { a_r = Some(*r); } } else if is_var_in_set(b_vars, *r) { if b_r.is_some() { - return fresh_bound_variable(this); + return fresh_bound_variable(this, new_binder_id); } else { b_r = Some(*r); } @@ -192,57 +193,57 @@ impl Combine for Glb { } } - // NB---I do not believe this algorithm computes - // (necessarily) the GLB. As written it can - // spuriously fail. In particular, if there is a case - // like: &fn(fn(&a)) and fn(fn(&b)), where a and b are - // free, it will return fn(&c) where c = GLB(a,b). If - // however this GLB is not defined, then the result is - // an error, even though something like - // "fn(fn(&X))" where X is bound would be a - // subtype of both of those. - // - // The problem is that if we were to return a bound - // variable, we'd be computing a lower-bound, but not - // necessarily the *greatest* lower-bound. + // NB---I do not believe this algorithm computes + // (necessarily) the GLB. As written it can + // spuriously fail. In particular, if there is a case + // like: &fn(fn(&a)) and fn(fn(&b)), where a and b are + // free, it will return fn(&c) where c = GLB(a,b). If + // however this GLB is not defined, then the result is + // an error, even though something like + // "fn(fn(&X))" where X is bound would be a + // subtype of both of those. + // + // The problem is that if we were to return a bound + // variable, we'd be computing a lower-bound, but not + // necessarily the *greatest* lower-bound. + // + // Unfortunately, this problem is non-trivial to solve, + // because we do not know at the time of computing the GLB + // whether a GLB(a,b) exists or not, because we haven't + // run region inference (or indeed, even fully computed + // the region hierarchy!). The current algorithm seems to + // works ok in practice. if a_r.is_some() && b_r.is_some() && only_new_vars { // Related to exactly one bound variable from each fn: - return rev_lookup(this, a_isr, a_r.unwrap()); + return rev_lookup(this, a_map, new_binder_id, a_r.unwrap()); } else if a_r.is_none() && b_r.is_none() { // Not related to bound variables from either fn: + assert!(!r0.is_bound()); return r0; } else { // Other: - return fresh_bound_variable(this); + return fresh_bound_variable(this, new_binder_id); } } fn rev_lookup(this: &Glb, - a_isr: isr_alist, + a_map: &HashMap, + new_binder_id: NodeId, r: ty::Region) -> ty::Region { - let mut ret = None; - do list::each(a_isr) |pair| { - let (a_br, a_r) = *pair; - if a_r == r { - ret = Some(ty::re_bound(a_br)); - false - } else { - true + for (a_br, a_r) in a_map.iter() { + if *a_r == r { + return ty::re_fn_bound(new_binder_id, *a_br); } - }; - - match ret { - Some(x) => x, - None => this.infcx.tcx.sess.span_bug( - this.trace.origin.span(), - format!("could not find original bound region for {:?}", r)) } + this.infcx.tcx.sess.span_bug( + this.trace.origin.span(), + format!("could not find original bound region for {:?}", r)) } - fn fresh_bound_variable(this: &Glb) -> ty::Region { - this.infcx.region_vars.new_bound() + fn fresh_bound_variable(this: &Glb, binder_id: NodeId) -> ty::Region { + this.infcx.region_vars.new_bound(binder_id) } } } diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs index 8a32a305b3a0..9aaa4be1181f 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/typeck/infer/lattice.rs @@ -35,7 +35,6 @@ use middle::ty::{RegionVid, TyVar, Vid}; use middle::ty; -use middle::typeck::isr_alist; use middle::typeck::infer::*; use middle::typeck::infer::combine::*; use middle::typeck::infer::glb::Glb; @@ -43,10 +42,9 @@ use middle::typeck::infer::lub::Lub; use middle::typeck::infer::unify::*; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; +use std::hashmap::HashMap; use util::common::indenter; -use extra::list; - pub trait LatticeValue { fn sub(cf: &CombineFields, a: &Self, b: &Self) -> ures; fn lub(cf: &CombineFields, a: &Self, b: &Self) -> cres; @@ -366,14 +364,13 @@ impl TyLatticeDir for Glb { } } -pub fn super_lattice_tys( - this: &L, - a: ty::t, - b: ty::t) -> cres { +pub fn super_lattice_tys(this: &L, + a: ty::t, + b: ty::t) + -> cres { debug!("{}.lattice_tys({}, {})", this.tag(), a.inf_str(this.infcx()), b.inf_str(this.infcx())); - let _r = indenter(); if a == b { return Ok(a); @@ -524,20 +521,17 @@ pub fn lattice_var_and_t(this: &T, isr: isr_alist) -> ~[RegionVid] { - let mut result = ~[]; - do list::each(isr) |pair| { - match pair.second() { - ty::re_infer(ty::ReVar(r)) => { result.push(r); } +pub fn var_ids(this: &T, + map: &HashMap) + -> ~[RegionVid] { + map.iter().map(|(_, r)| match *r { + ty::re_infer(ty::ReVar(r)) => { r } r => { this.infcx().tcx.sess.span_bug( this.trace().origin.span(), format!("Found non-region-vid: {:?}", r)); } - } - true - }; - result + }).collect() } pub fn is_var_in_set(new_vars: &[RegionVid], r: ty::Region) -> bool { diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 42793d956df0..ad649f379b58 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -20,13 +20,11 @@ use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::{cres, InferCtxt}; use middle::typeck::infer::fold_regions_in_sig; use middle::typeck::infer::{TypeTrace, Subtype}; -use middle::typeck::isr_alist; -use util::ppaux::mt_to_str; - -use extra::list; -use syntax::ast::{Many, Once, extern_fn, impure_fn}; +use std::hashmap::HashMap; +use syntax::ast::{Many, Once, extern_fn, impure_fn, NodeId}; use syntax::ast::{unsafe_fn}; use syntax::ast::{Onceness, purity}; +use util::ppaux::mt_to_str; pub struct Lub(CombineFields); // least-upper-bound: common supertype @@ -125,7 +123,7 @@ impl Combine for Lub { let snapshot = self.infcx.region_vars.start_snapshot(); // Instantiate each bound region with a fresh region variable. - let (a_with_fresh, a_isr) = + let (a_with_fresh, a_map) = self.infcx.replace_bound_regions_with_fresh_regions( self.trace, a); let (b_with_fresh, _) = @@ -143,17 +141,20 @@ impl Combine for Lub { fold_regions_in_sig( self.infcx.tcx, &sig0, - |r, _in_fn| generalize_region(self, snapshot, new_vars, - a_isr, r)); + |r| generalize_region(self, snapshot, new_vars, + sig0.binder_id, &a_map, r)); return Ok(sig1); fn generalize_region(this: &Lub, snapshot: uint, new_vars: &[RegionVid], - a_isr: isr_alist, - r0: ty::Region) -> ty::Region { + new_scope: NodeId, + a_map: &HashMap, + r0: ty::Region) + -> ty::Region { // Regions that pre-dated the LUB computation stay as they are. if !is_var_in_set(new_vars, r0) { + assert!(!r0.is_bound()); debug!("generalize_region(r0={:?}): not new variable", r0); return r0; } @@ -167,6 +168,7 @@ impl Combine for Lub { debug!("generalize_region(r0={:?}): \ non-new-variables found in {:?}", r0, tainted); + assert!(!r0.is_bound()); return r0; } @@ -175,27 +177,19 @@ impl Combine for Lub { // in both A and B. Replace the variable with the "first" // bound region from A that we find it to be associated // with. - let mut ret = None; - do list::each(a_isr) |pair| { - let (a_br, a_r) = *pair; - if tainted.iter().any(|x| x == &a_r) { + for (a_br, a_r) in a_map.iter() { + if tainted.iter().any(|x| x == a_r) { debug!("generalize_region(r0={:?}): \ replacing with {:?}, tainted={:?}", - r0, a_br, tainted); - ret = Some(ty::re_bound(a_br)); - false - } else { - true + r0, *a_br, tainted); + return ty::re_fn_bound(new_scope, *a_br); } - }; - - match ret { - Some(x) => x, - None => this.infcx.tcx.sess.span_bug( - this.trace.origin.span(), - format!("Region {:?} is not associated with \ - any bound region from A!", r0)) } + + this.infcx.tcx.sess.span_bug( + this.trace.origin.span(), + format!("Region {:?} is not associated with \ + any bound region from A!", r0)) } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 487eb4c32890..121b32f4145a 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -20,8 +20,11 @@ pub use middle::typeck::infer::resolve::{resolve_ivar, resolve_all}; pub use middle::typeck::infer::resolve::{resolve_nested_tvar}; pub use middle::typeck::infer::resolve::{resolve_rvar}; +use extra::smallintmap::SmallIntMap; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid}; use middle::ty; +use middle::ty_fold; +use middle::ty_fold::TypeFolder; use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig}; use middle::typeck::infer::coercion::Coerce; use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys}; @@ -32,19 +35,16 @@ use middle::typeck::infer::lub::Lub; use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::unify::{ValsAndBindings, Root}; use middle::typeck::infer::error_reporting::ErrorReporting; -use middle::typeck::isr_alist; -use util::common::indent; -use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str, Repr, - UserString}; - +use std::hashmap::HashMap; use std::result; use std::vec; -use extra::list::Nil; -use extra::smallintmap::SmallIntMap; use syntax::ast::{MutImmutable, MutMutable}; use syntax::ast; use syntax::codemap; use syntax::codemap::Span; +use util::common::indent; +use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str, Repr, + UserString}; pub mod doc; pub mod macros; @@ -225,8 +225,6 @@ pub enum RegionVariableOrigin { BoundRegionInTypeOrImpl(Span), BoundRegionInCoherence, - - BoundRegionError(Span), } pub enum fixup_err { @@ -568,15 +566,16 @@ impl InferCtxt { /// Execute `f`, unroll bindings on failure pub fn try(@mut self, f: &fn() -> Result) -> Result { debug!("try()"); - do indent { - let snapshot = self.start_snapshot(); - let r = f(); - match r { - Ok(_) => (), - Err(_) => self.rollback_to(&snapshot) + let snapshot = self.start_snapshot(); + let r = f(); + match r { + Ok(_) => { debug!("success"); } + Err(ref e) => { + debug!("error: {:?}", *e); + self.rollback_to(&snapshot) } - r } + r } /// Execute `f` then unroll any bindings it creates @@ -642,6 +641,17 @@ impl InferCtxt { ty::re_infer(ty::ReVar(self.region_vars.new_region_var(origin))) } + pub fn next_region_vars(&mut self, + origin: RegionVariableOrigin, + count: uint) + -> ~[ty::Region] { + vec::from_fn(count, |_| self.next_region_var(origin)) + } + + pub fn fresh_bound_region(&mut self, binder_id: ast::NodeId) -> ty::Region { + self.region_vars.new_bound(binder_id) + } + pub fn resolve_regions(@mut self) { let errors = self.region_vars.resolve_regions(); self.report_region_errors(&errors); // see error_reporting.rs @@ -787,9 +797,11 @@ impl InferCtxt { pub fn replace_bound_regions_with_fresh_regions(&mut self, trace: TypeTrace, fsig: &ty::FnSig) - -> (ty::FnSig, isr_alist) { - let(isr, _, fn_sig) = - replace_bound_regions_in_fn_sig(self.tcx, @Nil, None, fsig, |br| { + -> (ty::FnSig, + HashMap) { + let (map, _, fn_sig) = + replace_bound_regions_in_fn_sig(self.tcx, None, fsig, |br| { let rvar = self.next_region_var( BoundRegionInFnType(trace.origin.span(), br)); debug!("Bound region {} maps to {:?}", @@ -797,18 +809,16 @@ impl InferCtxt { rvar); rvar }); - (fn_sig, isr) + (fn_sig, map) } } pub fn fold_regions_in_sig( tcx: ty::ctxt, fn_sig: &ty::FnSig, - fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnSig + fldr: &fn(r: ty::Region) -> ty::Region) -> ty::FnSig { - do ty::fold_sig(fn_sig) |t| { - ty::fold_regions(tcx, t, |r, in_fn| fldr(r, in_fn)) - } + ty_fold::RegionFolder::regions(tcx, fldr).fold_sig(fn_sig) } impl TypeTrace { @@ -910,7 +920,6 @@ impl RegionVariableOrigin { BoundRegionInFnType(a, _) => a, BoundRegionInTypeOrImpl(a) => a, BoundRegionInCoherence => codemap::dummy_sp(), - BoundRegionError(a) => a, } } } @@ -931,7 +940,6 @@ impl Repr for RegionVariableOrigin { BoundRegionInTypeOrImpl(a) => format!("BoundRegionInTypeOrImpl({})", a.repr(tcx)), BoundRegionInCoherence => format!("BoundRegionInCoherence"), - BoundRegionError(a) => format!("BoundRegionError({})", a.repr(tcx)), } } } diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 68c5ec3b7d66..effd34da0de9 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -13,7 +13,8 @@ use middle::ty; use middle::ty::{FreeRegion, Region, RegionVid}; -use middle::ty::{re_empty, re_static, re_infer, re_free, re_bound}; +use middle::ty::{re_empty, re_static, re_infer, re_free, re_type_bound, + re_fn_bound}; use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh}; use middle::typeck::infer::cres; use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin}; @@ -192,24 +193,33 @@ impl RegionVarBindings { re_infer(ReSkolemized(sc, br)) } - pub fn new_bound(&mut self) -> Region { + pub fn new_bound(&mut self, binder_id: ast::NodeId) -> Region { // Creates a fresh bound variable for use in GLB computations. // See discussion of GLB computation in the large comment at // the top of this file for more details. // - // This computation is mildly wrong in the face of rollover. - // It's conceivable, if unlikely, that one might wind up with - // accidental capture for nested functions in that case, if - // the outer function had bound regions created a very long - // time before and the inner function somehow wound up rolling - // over such that supposedly fresh identifiers were in fact - // shadowed. We should convert our bound_region - // representation to use deBruijn indices or something like - // that to eliminate that possibility. + // This computation is potentially wrong in the face of + // rollover. It's conceivable, if unlikely, that one might + // wind up with accidental capture for nested functions in + // that case, if the outer function had bound regions created + // a very long time before and the inner function somehow + // wound up rolling over such that supposedly fresh + // identifiers were in fact shadowed. For now, we just assert + // that there is no rollover -- eventually we should try to be + // robust against this possibility, either by checking the set + // of bound identifiers that appear in a given expression and + // ensure that we generate one that is distinct, or by + // changing the representation of bound regions in a fn + // declaration let sc = self.bound_count; self.bound_count += 1; - re_bound(br_fresh(sc)) + + if sc >= self.bound_count { + self.tcx.sess.bug("Rollover in RegionInference new_bound()"); + } + + re_fn_bound(binder_id, br_fresh(sc)) } pub fn add_constraint(&mut self, @@ -236,6 +246,16 @@ impl RegionVarBindings { debug!("RegionVarBindings: make_subregion({:?}, {:?})", sub, sup); match (sub, sup) { + (re_type_bound(*), _) | + (re_fn_bound(*), _) | + (_, re_type_bound(*)) | + (_, re_fn_bound(*)) => { + self.tcx.sess.span_bug( + origin.span(), + format!("Cannot relate bound region: {} <= {}", + sub.repr(self.tcx), + sup.repr(self.tcx))); + } (re_infer(ReVar(sub_id)), re_infer(ReVar(sup_id))) => { self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); } @@ -245,16 +265,6 @@ impl RegionVarBindings { (re_infer(ReVar(sub_id)), r) => { self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); } - (re_bound(br), _) => { - self.tcx.sess.span_bug( - origin.span(), - format!("Cannot relate bound region as subregion: {:?}", br)); - } - (_, re_bound(br)) => { - self.tcx.sess.span_bug( - origin.span(), - format!("Cannot relate bound region as superregion: {:?}", br)); - } _ => { self.add_constraint(ConstrainRegSubReg(sub, sup), origin); } @@ -485,6 +495,16 @@ impl RegionVarBindings { fn lub_concrete_regions(&self, a: Region, b: Region) -> Region { match (a, b) { + (re_fn_bound(*), _) | + (_, re_fn_bound(*)) | + (re_type_bound(*), _) | + (_, re_type_bound(*)) => { + self.tcx.sess.bug( + format!("Cannot relate bound region: LUB({}, {})", + a.repr(self.tcx), + b.repr(self.tcx))); + } + (re_static, _) | (_, re_static) => { re_static // nothing lives longer than static } @@ -536,12 +556,7 @@ impl RegionVarBindings { // For these types, we cannot define any additional // relationship: (re_infer(ReSkolemized(*)), _) | - (_, re_infer(ReSkolemized(*))) | - (re_bound(_), re_bound(_)) | - (re_bound(_), re_free(_)) | - (re_bound(_), re_scope(_)) | - (re_free(_), re_bound(_)) | - (re_scope(_), re_bound(_)) => { + (_, re_infer(ReSkolemized(*))) => { if a == b {a} else {re_static} } } @@ -584,6 +599,16 @@ impl RegionVarBindings { -> cres { debug!("glb_concrete_regions({:?}, {:?})", a, b); match (a, b) { + (re_fn_bound(*), _) | + (_, re_fn_bound(*)) | + (re_type_bound(*), _) | + (_, re_type_bound(*)) => { + self.tcx.sess.bug( + format!("Cannot relate bound region: GLB({}, {})", + a.repr(self.tcx), + b.repr(self.tcx))); + } + (re_static, r) | (r, re_static) => { // static lives longer than everything else Ok(r) @@ -627,12 +652,7 @@ impl RegionVarBindings { // For these types, we cannot define any additional // relationship: (re_infer(ReSkolemized(*)), _) | - (_, re_infer(ReSkolemized(*))) | - (re_bound(_), re_bound(_)) | - (re_bound(_), re_free(_)) | - (re_bound(_), re_scope(_)) | - (re_free(_), re_bound(_)) | - (re_scope(_), re_bound(_)) => { + (_, re_infer(ReSkolemized(*))) => { if a == b { Ok(a) } else { diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index 564fcb76dc73..84f3d9c69379 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -50,6 +50,7 @@ use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; use middle::ty::{type_is_bot, IntType, UintType}; use middle::ty; +use middle::ty_fold; use middle::typeck::infer::{Bounds, cyclic_ty, fixup_err, fres, InferCtxt}; use middle::typeck::infer::{region_var_bound_by_region_var, unresolved_ty}; use middle::typeck::infer::to_str::InferStr; @@ -96,6 +97,20 @@ pub fn resolver(infcx: @mut InferCtxt, modes: uint) -> ResolveState { } } +impl ty_fold::TypeFolder for ResolveState { + fn tcx(&self) -> ty::ctxt { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: ty::t) -> ty::t { + self.resolve_type(t) + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + self.resolve_region(r) + } +} + impl ResolveState { pub fn should(&mut self, mode: uint) -> bool { (self.modes & mode) == mode @@ -166,11 +181,7 @@ impl ResolveState { typ } else { self.type_depth += 1; - let result = ty::fold_regions_and_ty( - self.infcx.tcx, typ, - |r| self.resolve_region(r), - |t| self.resolve_type(t), - |t| self.resolve_type(t)); + let result = ty_fold::super_fold_ty(self, typ); self.type_depth -= 1; result } diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index e5afefe0c716..802d635a3f0c 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -24,8 +24,6 @@ use middle::typeck::infer::{TypeTrace, Subtype}; use util::common::{indenter}; use util::ppaux::bound_region_to_str; -use extra::list::Nil; -use extra::list; use syntax::ast::{Onceness, purity}; pub struct Sub(CombineFields); // "subtype", "subregion" etc @@ -168,9 +166,8 @@ impl Combine for Sub { // Second, we instantiate each bound region in the supertype with a // fresh concrete region. - let (skol_isr, _, b_sig) = { - do replace_bound_regions_in_fn_sig(self.infcx.tcx, @Nil, - None, b) |br| { + let (skol_map, _, b_sig) = { + do replace_bound_regions_in_fn_sig(self.infcx.tcx, None, b) |br| { let skol = self.infcx.region_vars.new_skolemized(br); debug!("Bound region {} skolemized to {:?}", bound_region_to_str(self.infcx.tcx, "", false, br), @@ -189,10 +186,7 @@ impl Combine for Sub { // that the skolemized regions do not "leak". let new_vars = self.infcx.region_vars.vars_created_since_snapshot(snapshot); - - let mut ret = Ok(sig); - do list::each(skol_isr) |pair| { - let (skol_br, skol) = *pair; + for (&skol_br, &skol) in skol_map.iter() { let tainted = self.infcx.region_vars.tainted(snapshot, skol); for tainted_region in tainted.iter() { // Each skolemized should only be relatable to itself @@ -208,19 +202,16 @@ impl Combine for Sub { // A is not as polymorphic as B: if self.a_is_expected { - ret = Err(ty::terr_regions_insufficiently_polymorphic( - skol_br, *tainted_region)); - break + return Err(ty::terr_regions_insufficiently_polymorphic( + skol_br, *tainted_region)); } else { - ret = Err(ty::terr_regions_overly_polymorphic( - skol_br, *tainted_region)); - break + return Err(ty::terr_regions_overly_polymorphic( + skol_br, *tainted_region)); } } - ret.is_ok() - }; + } - ret + return Ok(sig); } } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 75c7adfb03e4..022c0ffb4325 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -64,7 +64,6 @@ use extra::list; use syntax::codemap::Span; use syntax::print::pprust::*; use syntax::{ast, ast_map, abi}; -use syntax::opt_vec; pub mod check; pub mod rscope; @@ -266,7 +265,7 @@ pub fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId) pub fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty { generics: ty::Generics {type_param_defs: @~[], - region_param: None}, + region_param_defs: @[]}, ty: t } } @@ -354,7 +353,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, purity: ast::impure_fn, abis: abi::AbiSet::Rust(), sig: ty::FnSig { - bound_lifetime_names: opt_vec::Empty, + binder_id: main_id, inputs: ~[], output: ty::mk_nil(), variadic: false @@ -400,7 +399,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, purity: ast::impure_fn, abis: abi::AbiSet::Rust(), sig: ty::FnSig { - bound_lifetime_names: opt_vec::Empty, + binder_id: start_id, inputs: ~[ ty::mk_int(), ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8())) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 006e14232f36..89dc71b3af64 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -11,10 +11,10 @@ use metadata::encoder; use middle::ty::{ReSkolemized, ReVar}; -use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid}; +use middle::ty::{bound_region, br_anon, br_named}; use middle::ty::{br_fresh, ctxt, field}; use middle::ty::{mt, t, param_ty}; -use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region, +use middle::ty::{re_free, re_scope, re_infer, re_static, Region, re_empty}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure}; @@ -118,6 +118,11 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) let (msg, opt_span) = explain_span(cx, "block", blk.span); (format!("{} {}", prefix, msg), opt_span) } + Some(&ast_map::node_item(it, _)) if match it.node { + ast::item_impl(*) => true, _ => false} => { + let (msg, opt_span) = explain_span(cx, "impl", it.span); + (format!("{} {}", prefix, msg), opt_span) + } Some(_) | None => { // this really should not happen (format!("{} node {}", prefix, fr.scope_id), None) @@ -131,7 +136,7 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) // I believe these cases should not occur (except when debugging, // perhaps) - re_infer(_) | re_bound(_) => { + ty::re_infer(_) | ty::re_type_bound(*) | ty::re_fn_bound(*) => { (format!("lifetime {:?}", region), None) } }; @@ -154,14 +159,15 @@ pub fn bound_region_to_str(cx: ctxt, br: bound_region) -> ~str { let space_str = if space { " " } else { "" }; - if cx.sess.verbose() { return format!("{}{:?}{}", prefix, br, space_str); } + if cx.sess.verbose() { + return format!("{}{}{}", prefix, br.repr(cx), space_str); + } match br { - br_named(id) => format!("{}'{}{}", prefix, cx.sess.str_of(id), space_str), - br_self => format!("{}'self{}", prefix, space_str), + br_named(_, ident) => format!("{}'{}{}", prefix, + cx.sess.str_of(ident), space_str), br_anon(_) => prefix.to_str(), br_fresh(_) => prefix.to_str(), - br_cap_avoid(_, br) => bound_region_to_str(cx, prefix, space, *br) } } @@ -215,7 +221,7 @@ pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~st let space_str = if space { " " } else { "" }; if cx.sess.verbose() { - return format!("{}{:?}{}", prefix, region, space_str); + return format!("{}{}{}", prefix, region.repr(cx), space_str); } // These printouts are concise. They do not contain all the information @@ -223,15 +229,16 @@ pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~st // to fit that into a short string. Hence the recommendation to use // `explain_region()` or `note_and_explain_region()`. match region { - re_scope(_) => prefix.to_str(), - re_bound(br) => bound_region_to_str(cx, prefix, space, br), - re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region), - re_infer(ReSkolemized(_, br)) => { + ty::re_scope(_) => prefix.to_str(), + ty::re_type_bound(_, _, ident) => cx.sess.str_of(ident).to_owned(), + ty::re_fn_bound(_, br) => bound_region_to_str(cx, prefix, space, br), + ty::re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region), + ty::re_infer(ReSkolemized(_, br)) => { bound_region_to_str(cx, prefix, space, br) } - re_infer(ReVar(_)) => prefix.to_str(), - re_static => format!("{}'static{}", prefix, space_str), - re_empty => format!("{}'{}", prefix, space_str) + ty::re_infer(ReVar(_)) => prefix.to_str(), + ty::re_static => format!("{}'static{}", prefix, space_str), + ty::re_empty => format!("{}'{}", prefix, space_str) } } @@ -289,9 +296,10 @@ pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str { } pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str { - format!("fn{} -> {}", - tys_to_str(cx, typ.inputs.map(|a| *a)), - ty_to_str(cx, typ.output)) + format!("fn{}{} -> {}", + typ.binder_id, + typ.inputs.repr(cx), + typ.output.repr(cx)) } pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str { @@ -594,8 +602,17 @@ impl Repr for ~[T] { impl Repr for ty::TypeParameterDef { fn repr(&self, tcx: ctxt) -> ~str { - format!("TypeParameterDef \\{{:?}, bounds: {}\\}", - self.def_id, self.bounds.repr(tcx)) + format!("TypeParameterDef({:?}, {})", + self.def_id, + self.bounds.repr(tcx)) + } +} + +impl Repr for ty::RegionParameterDef { + fn repr(&self, tcx: ctxt) -> ~str { + format!("RegionParameterDef({}, {:?})", + tcx.sess.str_of(self.ident), + self.def_id) } } @@ -655,6 +672,15 @@ impl Repr for ast::Expr { } } +impl Repr for ast::item { + fn repr(&self, tcx: ctxt) -> ~str { + format!("item({})", + ast_map::node_id_to_str(tcx.items, + self.id, + token::get_ident_interner())) + } +} + impl Repr for ast::Pat { fn repr(&self, tcx: ctxt) -> ~str { format!("pat({}: {})", @@ -665,13 +691,56 @@ impl Repr for ast::Pat { impl Repr for ty::bound_region { fn repr(&self, tcx: ctxt) -> ~str { - bound_region_ptr_to_str(tcx, *self) + match *self { + ty::br_anon(id) => format!("br_anon({})", id), + ty::br_named(id, ident) => format!("br_named({}, {})", + id.repr(tcx), + ident.repr(tcx)), + ty::br_fresh(id) => format!("br_fresh({})", id), + } } } impl Repr for ty::Region { fn repr(&self, tcx: ctxt) -> ~str { - region_to_str(tcx, "", false, *self) + match *self { + ty::re_type_bound(id, index, ident) => { + format!("re_type_bound({}, {}, {})", + id, index, ident.repr(tcx)) + } + + ty::re_fn_bound(binder_id, ref bound_region) => { + format!("re_fn_bound({}, {})", + binder_id, bound_region.repr(tcx)) + } + + ty::re_free(ref fr) => { + format!("re_free({}, {})", + fr.scope_id, + fr.bound_region.repr(tcx)) + } + + ty::re_scope(id) => { + format!("re_scope({})", id) + } + + ty::re_static => { + format!("re_static") + } + + ty::re_infer(ReVar(ref vid)) => { + format!("re_infer({})", vid.id) + } + + ty::re_infer(ReSkolemized(id, ref bound_region)) => { + format!("re_skolemized({}, {})", + id, bound_region.repr(tcx)) + } + + ty::re_empty => { + format!("re_empty") + } + } } } @@ -707,23 +776,38 @@ impl Repr for ty::ty_param_bounds_and_ty { impl Repr for ty::Generics { fn repr(&self, tcx: ctxt) -> ~str { - format!("Generics \\{type_param_defs: {}, region_param: {:?}\\}", - self.type_param_defs.repr(tcx), - self.region_param) + format!("Generics(type_param_defs: {}, region_param_defs: {})", + self.type_param_defs.repr(tcx), + self.region_param_defs.repr(tcx)) + } +} + +impl Repr for ty::ItemVariances { + fn repr(&self, tcx: ctxt) -> ~str { + format!("IterVariances(self_param={}, type_params={}, region_params={})", + self.self_param.repr(tcx), + self.type_params.repr(tcx), + self.region_params.repr(tcx)) + } +} + +impl Repr for ty::Variance { + fn repr(&self, _: ctxt) -> ~str { + self.to_str().to_owned() } } impl Repr for ty::Method { fn repr(&self, tcx: ctxt) -> ~str { - format!("method \\{ident: {}, generics: {}, transformed_self_ty: {}, \ - fty: {}, explicit_self: {}, vis: {}, def_id: {}\\}", - self.ident.repr(tcx), - self.generics.repr(tcx), - self.transformed_self_ty.repr(tcx), - self.fty.repr(tcx), - self.explicit_self.repr(tcx), - self.vis.repr(tcx), - self.def_id.repr(tcx)) + format!("method(ident: {}, generics: {}, transformed_self_ty: {}, \ + fty: {}, explicit_self: {}, vis: {}, def_id: {})", + self.ident.repr(tcx), + self.generics.repr(tcx), + self.transformed_self_ty.repr(tcx), + self.fty.repr(tcx), + self.explicit_self.repr(tcx), + self.vis.repr(tcx), + self.def_id.repr(tcx)) } } diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index dd1ad8263da8..f48ad25712d1 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -835,7 +835,7 @@ impl Clean for ast::Path { #[deriving(Clone, Encodable, Decodable)] pub struct PathSegment { name: ~str, - lifetime: Option, + lifetimes: ~[Lifetime], types: ~[Type], } @@ -843,7 +843,7 @@ impl Clean for ast::PathSegment { fn clean(&self) -> PathSegment { PathSegment { name: self.identifier.clean(), - lifetime: self.lifetime.clean(), + lifetimes: self.lifetimes.clean(), types: self.types.clean() } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9ff450d4135f..4c64feee3843 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -92,16 +92,17 @@ impl fmt::Default for clean::Path { if i > 0 { f.buf.write("::".as_bytes()) } f.buf.write(seg.name.as_bytes()); - if seg.lifetime.is_some() || seg.types.len() > 0 { + if seg.lifetimes.len() > 0 || seg.types.len() > 0 { f.buf.write("<".as_bytes()); - match seg.lifetime { - Some(ref lifetime) => write!(f.buf, "{}", *lifetime), - None => {} + let mut comma = false; + for lifetime in seg.lifetimes.iter() { + if comma { f.buf.write(", ".as_bytes()); } + comma = true; + write!(f.buf, "{}", *lifetime); } - for (i, ty) in seg.types.iter().enumerate() { - if i > 0 || seg.lifetime.is_some() { - f.buf.write(", ".as_bytes()); - } + for ty in seg.types.iter() { + if comma { f.buf.write(", ".as_bytes()); } + comma = true; write!(f.buf, "{}", *ty); } f.buf.write(">".as_bytes()); @@ -152,16 +153,17 @@ fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool, // The generics will get written to both the title and link let mut generics = ~""; let last = path.segments.last(); - if last.lifetime.is_some() || last.types.len() > 0 { + if last.lifetimes.len() > 0 || last.types.len() > 0 { + let mut counter = 0; generics.push_str("<"); - match last.lifetime { - Some(ref lifetime) => generics.push_str(format!("{}", *lifetime)), - None => {} + for lifetime in last.lifetimes.iter() { + if counter > 0 { generics.push_str(", "); } + counter += 1; + generics.push_str(format!("{}", *lifetime)); } - for (i, ty) in last.types.iter().enumerate() { - if i > 0 || last.lifetime.is_some() { - generics.push_str(", "); - } + for ty in last.types.iter() { + if counter > 0 { generics.push_str(", "); } + counter += 1; generics.push_str(format!("{}", *ty)); } generics.push_str(">"); @@ -495,7 +497,7 @@ impl fmt::Default for clean::ViewListIdent { global: false, segments: ~[clean::PathSegment { name: v.name.clone(), - lifetime: None, + lifetimes: ~[], types: ~[], }] }; diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index 7d10061e812c..90729966c18a 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -12,7 +12,7 @@ use clone::Clone; use container::Container; -use iter::Iterator; +use iter::{Iterator, FromIterator}; use option::{Option, Some, None}; use mem; use unstable::raw::Repr; @@ -134,6 +134,17 @@ impl Clone for @[T] { } } +impl FromIterator for @[A] { + fn from_iterator>(iterator: &mut T) -> @[A] { + let (lower, _) = iterator.size_hint(); + do build(Some(lower)) |push| { + for x in *iterator { + push(x); + } + } + } +} + #[cfg(not(test))] #[allow(missing_doc)] pub mod traits { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c0c2e2822f16..6245c61dfa18 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -28,7 +28,7 @@ use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; // table) and a SyntaxContext to track renaming and // macro expansion per Flatt et al., "Macros // That Work Together" -#[deriving(Clone, IterBytes, ToStr)] +#[deriving(Clone, IterBytes, ToStr, TotalEq, TotalOrd)] pub struct Ident { name: Name, ctxt: SyntaxContext } impl Ident { @@ -110,6 +110,7 @@ pub enum SyntaxContext_ { /// A name is a part of an identifier, representing a string or gensym. It's /// the result of interning. pub type Name = uint; + /// A mark represents a unique id associated with a macro expansion pub type Mrk = uint; @@ -156,9 +157,8 @@ pub struct Path { pub struct PathSegment { /// The identifier portion of this path segment. identifier: Ident, - /// The lifetime parameter for this path segment. Currently only one - /// lifetime parameter is allowed. - lifetime: Option, + /// The lifetime parameters for this path segment. + lifetimes: OptVec, /// The type parameters for this path segment, if present. types: OptVec, } @@ -167,7 +167,7 @@ pub type CrateNum = int; pub type NodeId = int; -#[deriving(Clone, Eq, Encodable, Decodable, IterBytes, ToStr)] +#[deriving(Clone, TotalEq, TotalOrd, Eq, Encodable, Decodable, IterBytes, ToStr)] pub struct DefId { crate: CrateNum, node: NodeId, diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 17613d19c7ef..f3d7ac1804db 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -488,3 +488,15 @@ pub fn node_item_query(items: map, id: NodeId, _ => fail!("{}", error_msg) } } + +pub fn item_span(items: map, + id: ast::NodeId) + -> Span { + match items.find(&id) { + Some(&node_item(item, _)) => item.span, + r => { + fail!(format!("item_span: expected item with id {} but found {:?}", + id, r)) + } + } +} diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 3ec87dbdd26f..ccae25dc012a 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -225,7 +225,7 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path { segments: ~[ ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -948,7 +948,7 @@ pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> boo for (idx,seg) in a.iter().enumerate() { if (seg.identifier.name != b[idx].identifier.name) // FIXME #7743: ident -> name problems in lifetime comparison? - || (seg.lifetime != b[idx].lifetime) + || (seg.lifetimes != b[idx].lifetimes) // can types contain idents? || (seg.types != b[idx].types) { return false; @@ -966,7 +966,9 @@ mod test { use std::hashmap::HashMap; fn ident_to_segment(id : &Ident) -> PathSegment { - PathSegment{identifier:id.clone(), lifetime: None, types: opt_vec::Empty} + PathSegment {identifier:id.clone(), + lifetimes: opt_vec::Empty, + types: opt_vec::Empty} } #[test] fn idents_name_eq_test() { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 0a5e20fc2b29..5ae158045e0e 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -38,7 +38,7 @@ pub trait AstBuilder { fn path_all(&self, sp: Span, global: bool, idents: ~[ast::Ident], - rp: Option, + lifetimes: OptVec, types: ~[ast::Ty]) -> ast::Path; @@ -237,19 +237,19 @@ pub trait AstBuilder { impl AstBuilder for @ExtCtxt { fn path(&self, span: Span, strs: ~[ast::Ident]) -> ast::Path { - self.path_all(span, false, strs, None, ~[]) + self.path_all(span, false, strs, opt_vec::Empty, ~[]) } fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path { self.path(span, ~[id]) } fn path_global(&self, span: Span, strs: ~[ast::Ident]) -> ast::Path { - self.path_all(span, true, strs, None, ~[]) + self.path_all(span, true, strs, opt_vec::Empty, ~[]) } fn path_all(&self, sp: Span, global: bool, mut idents: ~[ast::Ident], - rp: Option, + lifetimes: OptVec, types: ~[ast::Ty]) -> ast::Path { let last_identifier = idents.pop(); @@ -257,13 +257,13 @@ impl AstBuilder for @ExtCtxt { .map(|ident| { ast::PathSegment { identifier: ident, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect(); segments.push(ast::PathSegment { identifier: last_identifier, - lifetime: rp, + lifetimes: lifetimes, types: opt_vec::from(types), }); ast::Path { @@ -327,7 +327,7 @@ impl AstBuilder for @ExtCtxt { self.ident_of("option"), self.ident_of("Option") ], - None, + opt_vec::Empty, ~[ ty ]), None) } diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 0ca18f1208d0..216bc3097ce9 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -43,7 +43,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) segments: ~[ ast::PathSegment { identifier: res, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ] diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index cfb6048df18f..b37757341efd 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -375,14 +375,10 @@ impl<'self> TraitDef<'self> { cx.ty_ident(trait_span, ty_param.ident) }; - let self_lifetime = if generics.lifetimes.is_empty() { - None - } else { - Some(*generics.lifetimes.get(0)) - }; + let self_lifetimes = generics.lifetimes.clone(); // Create the type of `self`. - let self_type = cx.ty_path(cx.path_all(trait_span, false, ~[ type_ident ], self_lifetime, + let self_type = cx.ty_path(cx.path_all(trait_span, false, ~[ type_ident ], self_lifetimes, opt_vec::take_vec(self_ty_params)), None); let doc_attr = cx.attribute( diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 1e2a6fa2eb51..d014816c070c 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -14,6 +14,7 @@ use codemap::Span; use ext::base::ExtCtxt; use ext::build::{AstBuilder}; use ext::deriving::generic::*; +use opt_vec; pub fn expand_deriving_rand(cx: @ExtCtxt, span: Span, @@ -77,7 +78,7 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr { let rand_name = cx.path_all(span, true, rand_ident.clone(), - None, + opt_vec::Empty, ~[]); let rand_name = cx.expr_path(rand_name); diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index c60259304aef..d1a5af5f7e89 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -19,6 +19,7 @@ use ext::base::ExtCtxt; use ext::build::AstBuilder; use codemap::{Span,respan}; use opt_vec; +use opt_vec::OptVec; /// The types of pointers pub enum PtrTy<'self> { @@ -71,7 +72,7 @@ impl<'self> Path<'self> { self_generics: &Generics) -> ast::Path { let idents = self.path.map(|s| cx.ident_of(*s) ); - let lt = mk_lifetime(cx, span, &self.lifetime); + let lt = mk_lifetimes(cx, span, &self.lifetime); let tys = self.params.map(|t| t.to_ty(cx, span, self_ty, self_generics)); cx.path_all(span, self.global, idents, lt, tys) @@ -116,6 +117,13 @@ fn mk_lifetime(cx: @ExtCtxt, span: Span, lt: &Option<&str>) -> Option) -> OptVec { + match *lt { + Some(ref s) => opt_vec::with(cx.lifetime(span, cx.ident_of(*s))), + None => opt_vec::Empty + } +} + impl<'self> Ty<'self> { pub fn to_ty(&self, cx: @ExtCtxt, @@ -166,13 +174,9 @@ impl<'self> Ty<'self> { let self_params = do self_generics.ty_params.map |ty_param| { cx.ty_ident(span, ty_param.ident) }; - let lifetime = if self_generics.lifetimes.is_empty() { - None - } else { - Some(*self_generics.lifetimes.get(0)) - }; + let lifetimes = self_generics.lifetimes.clone(); - cx.path_all(span, false, ~[self_ty], lifetime, + cx.path_all(span, false, ~[self_ty], lifetimes, opt_vec::take_vec(self_params)) } Literal(ref p) => { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index ba946d5fb1f1..b74349da2a9f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -169,7 +169,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, segments: ~[ ast::PathSegment { identifier: ident, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -628,7 +628,7 @@ impl Visitor<()> for NewNameFinderContext { segments: [ ast::PathSegment { identifier: id, - lifetime: _, + lifetimes: _, types: _ } ] diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 943279d2dc68..00919fce5db6 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -15,7 +15,7 @@ use ext::base; use ext::build::AstBuilder; use rsparse = parse; use parse::token; - +use opt_vec; use std::fmt::parse; use std::hashmap::{HashMap, HashSet}; use std::vec; @@ -464,7 +464,7 @@ impl Context { sp, true, rtpath("Method"), - Some(life), + opt_vec::with(life), ~[] ), None); let st = ast::item_static(ty, ast::MutImmutable, method); @@ -582,7 +582,8 @@ impl Context { self.ecx.ident_of("rt"), self.ecx.ident_of("Piece"), ], - Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))), + opt_vec::with( + self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))), ~[] ), None); let ty = ast::ty_fixed_length_vec( diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 388de29b4568..ea0ab95a4510 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -144,7 +144,7 @@ pub trait ast_fold { ident: self.fold_ident(m.ident), attrs: m.attrs.map(|a| fold_attribute_(*a, self)), generics: fold_generics(&m.generics, self), - explicit_self: m.explicit_self, + explicit_self: self.fold_explicit_self(&m.explicit_self), purity: m.purity, decl: fold_fn_decl(&m.decl, self), body: self.fold_block(&m.body), @@ -245,12 +245,14 @@ pub trait ast_fold { ty_uniq(ref mt) => ty_uniq(fold_mt(mt, self)), ty_vec(ref mt) => ty_vec(fold_mt(mt, self)), ty_ptr(ref mt) => ty_ptr(fold_mt(mt, self)), - ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, self)), + ty_rptr(ref region, ref mt) => { + ty_rptr(fold_opt_lifetime(region, self), fold_mt(mt, self)) + } ty_closure(ref f) => { ty_closure(@TyClosure { sigil: f.sigil, purity: f.purity, - region: f.region, + region: fold_opt_lifetime(&f.region, self), onceness: f.onceness, bounds: fold_opt_bounds(&f.bounds, self), decl: fold_fn_decl(&f.decl, self), @@ -349,7 +351,7 @@ pub trait ast_fold { global: p.global, segments: p.segments.map(|segment| ast::PathSegment { identifier: self.fold_ident(segment.identifier), - lifetime: segment.lifetime, + lifetimes: segment.lifetimes.map(|l| fold_lifetime(l, self)), types: segment.types.map(|typ| self.fold_ty(typ)), }) } @@ -389,6 +391,24 @@ pub trait ast_fold { fn new_span(&self, sp: Span) -> Span { sp } + + fn fold_explicit_self(&self, es: &explicit_self) -> explicit_self { + Spanned { + span: self.new_span(es.span), + node: self.fold_explicit_self_(&es.node) + } + } + + fn fold_explicit_self_(&self, es: &explicit_self_) -> explicit_self_ { + match *es { + sty_static | sty_value(_) | sty_uniq(_) | sty_box(_) => { + *es + } + sty_region(ref lifetime, m) => { + sty_region(fold_opt_lifetime(lifetime, self), m) + } + } + } } /* some little folds that probably aren't useful to have in ast_fold itself*/ @@ -505,6 +525,11 @@ pub fn fold_lifetimes(lts: &OptVec, fld: &T) lts.map(|l| fold_lifetime(l, fld)) } +pub fn fold_opt_lifetime(o_lt: &Option, fld: &T) + -> Option { + o_lt.as_ref().map(|lt| fold_lifetime(lt, fld)) +} + pub fn fold_generics(generics: &Generics, fld: &T) -> Generics { Generics {ty_params: fold_ty_params(&generics.ty_params, fld), lifetimes: fold_lifetimes(&generics.lifetimes, fld)} @@ -675,7 +700,7 @@ pub fn noop_fold_type_method(m: &TypeMethod, fld: &T) purity: m.purity, decl: fold_fn_decl(&m.decl, fld), generics: fold_generics(&m.generics, fld), - explicit_self: m.explicit_self, + explicit_self: fld.fold_explicit_self(&m.explicit_self), id: fld.new_id(m.id), span: fld.new_span(m.span), } diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 2000d0b97461..4d39d4df72f5 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -165,3 +165,13 @@ impl<'self, T> Iterator<&'self T> for OptVecIterator<'self, T> { } } } + +impl FromIterator for OptVec { + fn from_iterator>(iterator: &mut T) -> OptVec { + let mut r = Empty; + for x in *iterator { + r.push(x); + } + r + } +} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6c81784b5dee..672865aadcc2 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -368,7 +368,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("a"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -387,12 +387,12 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("a"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ] @@ -592,7 +592,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("d"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -614,7 +614,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -641,7 +641,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -669,7 +669,7 @@ mod test { ast::PathSegment { identifier: str_to_ident("int"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -687,7 +687,7 @@ mod test { ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -724,8 +724,8 @@ mod test { identifier: str_to_ident( "b"), - lifetime: - None, + lifetimes: + opt_vec::Empty, types: opt_vec::Empty } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7c98d8d1c85b..cfb4da87720b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1490,7 +1490,7 @@ impl Parser { segments.push(PathSegmentAndBoundSet { segment: ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, bound_set: bound_set @@ -1499,46 +1499,21 @@ impl Parser { } // Parse the `<` before the lifetime and types, if applicable. - let (any_lifetime_or_types, optional_lifetime, types) = - if mode != NoTypesAllowed && self.eat(&token::LT) { - // Parse an optional lifetime. - let optional_lifetime = match *self.token { - token::LIFETIME(*) => Some(self.parse_lifetime()), - _ => None, - }; - - // Parse type parameters. - let mut types = opt_vec::Empty; - let mut need_comma = optional_lifetime.is_some(); - loop { - // We're done if we see a `>`. - match *self.token { - token::GT | token::BINOP(token::SHR) => { - self.expect_gt(); - break - } - _ => {} // Go on. - } - - if need_comma { - self.expect(&token::COMMA) - } else { - need_comma = true - } - - types.push(self.parse_ty(false)) + let (any_lifetime_or_types, lifetimes, types) = { + if mode != NoTypesAllowed && self.eat(&token::LT) { + let (lifetimes, types) = + self.parse_generic_values_after_lt(); + (true, lifetimes, opt_vec::from(types)) + } else { + (false, opt_vec::Empty, opt_vec::Empty) } - - (true, optional_lifetime, types) - } else { - (false, None, opt_vec::Empty) }; // Assemble and push the result. segments.push(PathSegmentAndBoundSet { segment: ast::PathSegment { identifier: identifier, - lifetime: optional_lifetime, + lifetimes: lifetimes, types: types, }, bound_set: bound_set @@ -1609,11 +1584,11 @@ impl Parser { pub fn parse_lifetime(&self) -> ast::Lifetime { match *self.token { token::LIFETIME(i) => { - let span = self.span; + let span = *self.span; self.bump(); return ast::Lifetime { id: ast::DUMMY_NODE_ID, - span: *span, + span: span, ident: i }; } @@ -4856,7 +4831,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -4892,7 +4867,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -4910,7 +4885,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -4932,7 +4907,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 08c2ae88e4fa..fd02ac68f4e1 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1566,13 +1566,13 @@ fn print_path_(s: @ps, } } - if segment.lifetime.is_some() || !segment.types.is_empty() { + if !segment.lifetimes.is_empty() || !segment.types.is_empty() { if colons_before_params { word(s.s, "::") } word(s.s, "<"); - for lifetime in segment.lifetime.iter() { + for lifetime in segment.lifetimes.iter() { print_lifetime(s, lifetime); if !segment.types.is_empty() { word_space(s, ",") @@ -1905,7 +1905,8 @@ pub fn print_meta_item(s: @ps, item: &ast::MetaItem) { pub fn print_view_path(s: @ps, vp: &ast::view_path) { match vp.node { ast::view_path_simple(ident, ref path, _) => { - if path.segments.last().identifier != ident { + // FIXME can't compare identifiers directly here + if path.segments.last().identifier.name != ident.name { print_ident(s, ident); space(s.s); word_space(s, "=");