Generalize AST and ty::Generics to accept multiple lifetimes.

This commit is contained in:
Niko Matsakis 2013-10-29 06:03:32 -04:00
parent 85c51d3b02
commit 1f4faaee40
52 changed files with 1510 additions and 1454 deletions

View file

@ -116,12 +116,12 @@ impl fold::ast_fold for StandardLibraryInjector {
segments: ~[ segments: ~[
ast::PathSegment { ast::PathSegment {
identifier: self.sess.ident_of("std"), identifier: self.sess.ident_of("std"),
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
}, },
ast::PathSegment { ast::PathSegment {
identifier: self.sess.ident_of("prelude"), identifier: self.sess.ident_of("prelude"),
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
}, },
], ],

View file

@ -343,7 +343,7 @@ fn path_node(ids: ~[ast::Ident]) -> ast::Path {
global: false, global: false,
segments: ids.move_iter().map(|identifier| ast::PathSegment { segments: ids.move_iter().map(|identifier| ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
}).collect() }).collect()
} }
@ -355,7 +355,7 @@ fn path_node_global(ids: ~[ast::Ident]) -> ast::Path {
global: true, global: true,
segments: ids.move_iter().map(|identifier| ast::PathSegment { segments: ids.move_iter().map(|identifier| ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
}).collect() }).collect()
} }

View file

@ -53,8 +53,10 @@ use syntax::diagnostic;
pub mod middle { pub mod middle {
pub mod trans; pub mod trans;
pub mod ty; pub mod ty;
pub mod ty_fold;
pub mod subst; pub mod subst;
pub mod resolve; pub mod resolve;
pub mod resolve_lifetime;
pub mod typeck; pub mod typeck;
pub mod check_loop; pub mod check_loop;
pub mod check_match; pub mod check_match;

View file

@ -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_ident: uint = 0x88;
pub static tag_path_elt_pretty_name_extra: uint = 0x89; 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 { pub struct LinkMeta {
name: @str, name: @str,
vers: @str, vers: @str,

View file

@ -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) decoder::get_trait_def(cdata, def.node, tcx)
} }
pub fn get_region_param(cstore: @mut metadata::cstore::CStore,
def: ast::DefId) -> Option<ty::region_variance> {
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, pub fn get_field_type(tcx: ty::ctxt, class_id: ast::DefId,
def: ast::DefId) -> ty::ty_param_bounds_and_ty { def: ast::DefId) -> ty::ty_param_bounds_and_ty {
let cstore = tcx.cstore; 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); let ty = decoder::item_type(def, the_field, tcx, cdata);
ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty {
generics: ty::Generics {type_param_defs: @~[], generics: ty::Generics {type_param_defs: @~[],
region_param: None}, region_param_defs: @[]},
ty: ty ty: ty
} }
} }

View file

@ -25,7 +25,7 @@ use middle::ty;
use middle::typeck; use middle::typeck;
use middle::astencode::vtable_decoder_helpers; use middle::astencode::vtable_decoder_helpers;
use std::at_vec;
use std::u64; use std::u64;
use std::rt::io; use std::rt::io;
use std::rt::io::extensions::u64_from_be_bytes; 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) 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) tag: uint)
-> @~[ty::TypeParameterDef] { -> @~[ty::TypeParameterDef] {
let mut bounds = ~[]; let mut bounds = ~[];
do reader::tagged_docs(item, tag) |p| { do reader::tagged_docs(item, tag) |p| {
let bd = parse_type_param_def_data( 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 @bounds
} }
fn item_ty_region_param(item: ebml::Doc) -> Option<ty::region_variance> { fn item_region_param_defs(item_doc: ebml::Doc,
do reader::maybe_get_doc(item, tag_region_param).map |doc| { tcx: ty::ctxt,
let mut decoder = reader::Decoder(doc); cdata: Cmd)
Decodable::decode(&mut decoder) -> @[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 item_doc = lookup_item(item_id, cdata.data);
let tp_defs = item_ty_param_defs(item_doc, tcx, cdata, let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
tag_items_data_item_ty_param_bounds); 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(); let mut bounds = ty::EmptyBuiltinBounds();
// Collect the builtin bounds from the encoded supertraits. // Collect the builtin bounds from the encoded supertraits.
// FIXME(#8559): They should be encoded directly. // FIXME(#8559): They should be encoded directly.
@ -407,7 +422,7 @@ pub fn get_trait_def(cdata: Cmd,
}; };
ty::TraitDef { ty::TraitDef {
generics: ty::Generics {type_param_defs: tp_defs, generics: ty::Generics {type_param_defs: tp_defs,
region_param: rp}, region_param_defs: rp_defs},
bounds: bounds, bounds: bounds,
trait_ref: @item_trait_ref(item_doc, tcx, cdata) 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 { -> ty::ty_param_bounds_and_ty {
let item = lookup_item(id, cdata.data); let item = lookup_item(id, cdata.data);
let t = item_type(ast::DefId { crate: cdata.cnum, node: id }, item, tcx, let t = item_type(ast::DefId { crate: cdata.cnum, node: id }, item, tcx,
cdata); 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) let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds);
} else { @~[] }; let rp_defs = item_region_param_defs(item, tcx, cdata);
let rp = item_ty_region_param(item);
ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty {
generics: ty::Generics {type_param_defs: tp_defs, generics: ty::Generics {type_param_defs: tp_defs,
region_param: rp}, region_param_defs: rp_defs},
ty: t ty: t
} }
} }
pub fn get_region_param(cdata: Cmd, id: ast::NodeId)
-> Option<ty::region_variance> {
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 { pub fn get_type_param_count(data: @~[u8], id: ast::NodeId) -> uint {
item_ty_param_count(lookup_item(id, data)) item_ty_param_count(lookup_item(id, data))
} }
pub fn get_impl_trait(cdata: Cmd, pub fn get_impl_trait(cdata: Cmd,
id: ast::NodeId, id: ast::NodeId,
tcx: ty::ctxt) -> Option<@ty::TraitRef> tcx: ty::ctxt) -> Option<@ty::TraitRef>
{ {
let item_doc = lookup_item(id, cdata.data); let item_doc = lookup_item(id, cdata.data);
do reader::maybe_get_doc(item_doc, tag_item_trait_ref).map |tp| { 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 name = item_name(intr, method_doc);
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata, let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps); 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 transformed_self_ty = doc_transformed_self_ty(method_doc, tcx, cdata);
let fty = doc_method_fty(method_doc, tcx, cdata); let fty = doc_method_fty(method_doc, tcx, cdata);
let vis = item_visibility(method_doc); let vis = item_visibility(method_doc);
@ -1054,7 +1064,7 @@ pub fn get_method(intr: @ident_interner, cdata: Cmd, id: ast::NodeId,
name, name,
ty::Generics { ty::Generics {
type_param_defs: type_param_defs, type_param_defs: type_param_defs,
region_param: None region_param_defs: rp_defs,
}, },
transformed_self_ty, transformed_self_ty,
fty, fty,

View file

@ -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)); 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)] #[deriving(Clone)]
struct entry<T> { struct entry<T> {
val: T, 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, fn encode_bounds_and_type(ebml_w: &mut writer::Encoder,
ecx: &EncodeContext, ecx: &EncodeContext,
tpt: &ty::ty_param_bounds_and_ty) { tpt: &ty::ty_param_bounds_and_ty) {
encode_ty_type_param_defs(ebml_w, ecx, tpt.generics.type_param_defs, encode_ty_type_param_defs(ebml_w, ecx, tpt.generics.type_param_defs,
tag_items_data_item_ty_param_bounds); 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); 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_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(ecx, ebml_w, item.ident); encode_name(ecx, ebml_w, item.ident);
encode_path(ecx, ebml_w, path, ast_map::path_name(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); encode_visibility(ebml_w, vis);
ebml_w.end_tag(); 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)); (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); 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 for this enumeration.
encode_inherent_implementations(ecx, ebml_w, def_id); 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_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs); encode_attributes(ebml_w, item.attrs);
encode_path(ecx, ebml_w, path, ast_map::path_name(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); encode_visibility(ebml_w, vis);
/* Encode def_ids for each field and method /* 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); ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, def_id); encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'i'); 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_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(ecx, ebml_w, item.ident); encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs); 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); ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, def_id); encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'I'); encode_family(ebml_w, 'I');
encode_region_param(ecx, ebml_w, item);
let trait_def = ty::lookup_trait_def(tcx, def_id); let trait_def = ty::lookup_trait_def(tcx, def_id);
encode_ty_type_param_defs(ebml_w, ecx, encode_ty_type_param_defs(ebml_w, ecx,
trait_def.generics.type_param_defs, trait_def.generics.type_param_defs,

View file

@ -48,7 +48,10 @@ pub enum DefIdSource {
TypeWithId, TypeWithId,
// Identifies a type parameter (`fn foo<X>() { ... }`). // Identifies a type parameter (`fn foo<X>() { ... }`).
TypeParameter TypeParameter,
// Identifies a region parameter (`fn foo<'X>() { ... }`).
RegionParameter,
} }
type conv_did<'self> = type conv_did<'self> =
&'self fn(source: DefIdSource, ast::DefId) -> ast::DefId; &'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| { segments: idents.move_iter().map(|identifier| {
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
}).collect() }).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), '/'); assert_eq!(next(st), '/');
let c = peek(st); let c = peek(st);
@ -178,22 +181,22 @@ fn parse_vstore(st: &mut PState) -> ty::vstore {
match next(st) { match next(st) {
'~' => ty::vstore_uniq, '~' => ty::vstore_uniq,
'@' => ty::vstore_box, '@' => 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)) 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) { match next(st) {
'~' => ty::UniqTraitStore, '~' => ty::UniqTraitStore,
'@' => ty::BoxTraitStore, '@' => 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)) c => st.tcx.sess.bug(format!("parse_trait_store(): bad input '{}'", c))
} }
} }
fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs { 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)) ); 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) { match next(st) {
'e' => ty::ErasedRegions, 'e' => ty::ErasedRegions,
'n' => { 'n' => {
let mut regions = opt_vec::Empty; let mut regions = opt_vec::Empty;
while peek(st) != '.' { while peek(st) != '.' {
let r = parse_region(st); let r = parse_region(st, |x,y| conv(x,y));
regions.push(r); regions.push(r);
} }
assert_eq!(next(st), '.'); 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) { match next(st) {
's' => ty::br_self, 'a' => {
'a' => { let id = parse_uint(st);
let id = parse_uint(st); assert_eq!(next(st), '|');
assert_eq!(next(st), '|'); ty::br_anon(id)
ty::br_anon(id) }
} '[' => {
'[' => ty::br_named(st.tcx.sess.ident_of(parse_str(st, ']'))), let def = parse_def(st, RegionParameter, |x,y| conv(x,y));
'c' => { let ident = st.tcx.sess.ident_of(parse_str(st, ']'));
let id = parse_uint(st) as int; ty::br_named(def, ident)
assert_eq!(next(st), '|'); }
ty::br_cap_avoid(id, @parse_bound_region(st)) 'f' => {
}, let id = parse_uint(st);
_ => fail!("parse_bound_region: bad input") 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) { match next(st) {
'b' => { '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' => { 'f' => {
assert_eq!(next(st), '['); assert_eq!(next(st), '[');
let id = parse_uint(st) as int; let id = parse_uint(st) as int;
assert_eq!(next(st), '|'); 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), ']'); assert_eq!(next(st), ']');
ty::re_free(ty::FreeRegion {scope_id: id, ty::re_free(ty::FreeRegion {scope_id: id,
bound_region: br}) bound_region: br})
@ -331,14 +351,14 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
assert_eq!(next(st), '['); assert_eq!(next(st), '[');
let def = parse_def(st, NominalType, |x,y| conv(x,y)); let def = parse_def(st, NominalType, |x,y| conv(x,y));
let substs = parse_substs(st, |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 mt = parse_mutability(st);
let bounds = parse_bounds(st, |x,y| conv(x,y)); let bounds = parse_bounds(st, |x,y| conv(x,y));
assert_eq!(next(st), ']'); assert_eq!(next(st), ']');
return ty::mk_trait(st.tcx, def, substs, store, mt, bounds.builtin_bounds); return ty::mk_trait(st.tcx, def, substs, store, mt, bounds.builtin_bounds);
} }
'p' => { '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); debug!("parsed ty_param: did={:?}", did);
return ty::mk_param(st.tcx, parse_uint(st), 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)), 'U' => return ty::mk_unboxed_vec(st.tcx, parse_mt(st, conv)),
'V' => { 'V' => {
let mt = parse_mt(st, conv); let mt = parse_mt(st, |x,y| conv(x,y));
let v = parse_vstore(st); let v = parse_vstore(st, |x,y| conv(x,y));
return ty::mk_evec(st.tcx, mt, v); return ty::mk_evec(st.tcx, mt, v);
} }
'v' => { 'v' => {
let v = parse_vstore(st); let v = parse_vstore(st, |x,y| conv(x,y));
return ty::mk_estr(st.tcx, v); return ty::mk_estr(st.tcx, v);
} }
'T' => { 'T' => {
@ -495,7 +515,7 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy {
let sigil = parse_sigil(st); let sigil = parse_sigil(st);
let purity = parse_purity(next(st)); let purity = parse_purity(next(st));
let onceness = parse_onceness(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 bounds = parse_bounds(st, |x,y| conv(x,y));
let sig = parse_sig(st, |x,y| conv(x,y)); let sig = parse_sig(st, |x,y| conv(x,y));
ty::ClosureTy { 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 { fn parse_bare_fn_ty(st: &mut PState, conv: conv_did) -> ty::BareFnTy {
let purity = parse_purity(next(st)); let purity = parse_purity(next(st));
let abi = parse_abi_set(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 { ty::BareFnTy {
purity: purity, purity: purity,
abis: abi, 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 { fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig {
assert_eq!(next(st), '['); assert_eq!(next(st), '[');
let id = parse_uint(st) as int;
assert_eq!(next(st), '|');
let mut inputs = ~[]; let mut inputs = ~[];
while peek(st) != ']' { while peek(st) != ']' {
inputs.push(parse_ty(st, |x,y| conv(x,y))); inputs.push(parse_ty(st, |x,y| conv(x,y)));
} }
st.pos += 1u; // eat the ']' st.pos += 1u; // eat the ']'
let variadic = if peek(st) == 'A' { let variadic = match next(st) {
st.pos += 1; // eat the 'A' 'V' => true,
true 'N' => false,
} else { false }; };
let ret_ty = parse_ty(st, conv); let ret_ty = parse_ty(st, |x,y| conv(x,y));
ty::FnSig { ty::FnSig {binder_id: id,
bound_lifetime_names: opt_vec::Empty, // FIXME(#4846) inputs: inputs,
inputs: inputs, output: ret_ty,
output: ret_ty, variadic: variadic}
variadic: variadic
}
} }
// Rust metadata parsing // Rust metadata parsing

View file

@ -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) { fn enc_region(w: @mut MemWriter, cx: @ctxt, r: ty::Region) {
match r { match r {
ty::re_bound(br) => { ty::re_fn_bound(id, br) => {
mywrite!(w, "b"); mywrite!(w, "b[{}|", id);
enc_bound_region(w, cx, br); 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) => { ty::re_free(ref fr) => {
mywrite!(w, "f[{}|", fr.scope_id); mywrite!(w, "f[{}|", fr.scope_id);
enc_bound_region(w, cx, fr.bound_region); enc_bound_region(w, cx, fr.bound_region);
mywrite!(w, "]"); mywrite!(w, "]");
} }
ty::re_scope(nid) => mywrite!(w, "s{}|", nid), ty::re_scope(nid) => {
ty::re_static => mywrite!(w, "t"), mywrite!(w, "s{}|", nid);
ty::re_empty => mywrite!(w, "e"), }
ty::re_static => {
mywrite!(w, "t");
}
ty::re_empty => {
mywrite!(w, "e");
}
ty::re_infer(_) => { ty::re_infer(_) => {
// these should not crop up after typeck // these should not crop up after typeck
cx.diag.handler().bug("Cannot encode region variables"); 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) { fn enc_bound_region(w: @mut MemWriter, cx: @ctxt, br: ty::bound_region) {
match br { match br {
ty::br_self => mywrite!(w, "s"), ty::br_anon(idx) => {
ty::br_anon(idx) => mywrite!(w, "a{}|", idx), mywrite!(w, "a{}|", idx);
ty::br_named(s) => mywrite!(w, "[{}]", cx.tcx.sess.str_of(s)), }
ty::br_cap_avoid(id, br) => { ty::br_named(d, s) => {
mywrite!(w, "c{}|", id); mywrite!(w, "[{}|{}]",
enc_bound_region(w, cx, *br); (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) { 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() { for ty in fsig.inputs.iter() {
enc_ty(w, cx, *ty); enc_ty(w, cx, *ty);
} }
mywrite!(w, "]"); mywrite!(w, "]");
if fsig.variadic { if fsig.variadic {
mywrite!(w, "A"); mywrite!(w, "V");
} else {
mywrite!(w, "N");
} }
enc_ty(w, cx, fsig.output); enc_ty(w, cx, fsig.output);
} }

View file

@ -15,7 +15,8 @@ use driver::session::Session;
use e = metadata::encoder; use e = metadata::encoder;
use metadata::decoder; use metadata::decoder;
use metadata::tydecode; use metadata::tydecode;
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter}; use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
RegionParameter};
use metadata::tyencode; use metadata::tyencode;
use middle::freevars::freevar_entry; use middle::freevars::freevar_entry;
use middle::typeck::{method_origin, method_map_entry}; use middle::typeck::{method_origin, method_map_entry};
@ -234,6 +235,12 @@ impl tr for ast::DefId {
} }
} }
impl tr for Option<ast::DefId> {
fn tr(&self, xcx: @ExtendedDecodeContext) -> Option<ast::DefId> {
self.map(|d| xcx.tr_def_id(d))
}
}
impl tr for Span { impl tr for Span {
fn tr(&self, xcx: @ExtendedDecodeContext) -> Span { fn tr(&self, xcx: @ExtendedDecodeContext) -> Span {
xcx.tr_span(*self) xcx.tr_span(*self)
@ -469,7 +476,11 @@ impl tr for ty::AutoRef {
impl tr for ty::Region { impl tr for ty::Region {
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::Region { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::Region {
match *self { 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_scope(id) => ty::re_scope(xcx.tr_id(id)),
ty::re_empty | ty::re_static | ty::re_infer(*) => *self, ty::re_empty | ty::re_static | ty::re_infer(*) => *self,
ty::re_free(ref fr) => { ty::re_free(ref fr) => {
@ -483,10 +494,10 @@ impl tr for ty::Region {
impl tr for ty::bound_region { impl tr for ty::bound_region {
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::bound_region { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::bound_region {
match *self { match *self {
ty::br_anon(_) | ty::br_named(_) | ty::br_self | ty::br_anon(_) |
ty::br_fresh(_) => *self, ty::br_fresh(_) => *self,
ty::br_cap_avoid(id, br) => ty::br_cap_avoid(xcx.tr_id(id), ty::br_named(id, ident) => ty::br_named(xcx.tr_def_id(id),
@br.tr(xcx)) ident),
} }
} }
} }
@ -821,8 +832,8 @@ impl ebml_writer_helpers for writer::Encoder {
this.emit_type_param_def(ecx, type_param_def); this.emit_type_param_def(ecx, type_param_def);
} }
} }
do this.emit_struct_field("region_param", 1) |this| { do this.emit_struct_field("region_param_defs", 1) |this| {
tpbt.generics.region_param.encode(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. // are not used during trans.
return do self.read_opaque |this, doc| { return do self.read_opaque |this, doc| {
debug!("read_ty({})", type_string(doc));
let ty = tydecode::parse_ty_data( let ty = tydecode::parse_ty_data(
*doc.data, *doc.data,
xcx.dcx.cdata.cnum, xcx.dcx.cdata.cnum,
@ -1093,10 +1106,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder {
xcx.dcx.tcx, xcx.dcx.tcx,
|s, a| this.convert_def_id(xcx, s, a)); |s, a| this.convert_def_id(xcx, s, a));
debug!("read_ty({}) = {}",
type_string(doc),
ty_to_str(xcx.dcx.tcx, ty));
ty ty
}; };
@ -1139,8 +1148,8 @@ impl ebml_decoder_decoder_helpers for reader::Decoder {
@this.read_to_vec(|this| @this.read_to_vec(|this|
this.read_type_param_def(xcx)) this.read_type_param_def(xcx))
}), }),
region_param: region_param_defs:
this.read_struct_field("region_param", this.read_struct_field("region_param_defs",
1, 1,
|this| { |this| {
Decodable::decode(this) Decodable::decode(this)
@ -1161,7 +1170,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder {
did: ast::DefId) did: ast::DefId)
-> ast::DefId { -> ast::DefId {
/*! /*!
*
* Converts a def-id that appears in a type. The correct * Converts a def-id that appears in a type. The correct
* translation will depend on what kind of def-id this is. * translation will depend on what kind of def-id this is.
* This is a subtle point: type definitions are not * 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 * However, *type parameters* are cloned along with the function
* they are attached to. So we should translate those def-ids * they are attached to. So we should translate those def-ids
* to refer to the new, cloned copy of the type parameter. * 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 { 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) TypeParameter => xcx.tr_intern_def_id(did)
}; };
debug!("convert_def_id(source={:?}, did={:?})={:?}", source, did, r); debug!("convert_def_id(source={:?}, did={:?})={:?}", source, did, r);

View file

@ -486,7 +486,8 @@ impl<'self> GatherLoanCtxt<'self> {
} }
ty::re_empty | ty::re_empty |
ty::re_bound(*) | ty::re_fn_bound(*) |
ty::re_type_bound(*) |
ty::re_infer(*) => { ty::re_infer(*) => {
self.tcx().sess.span_bug( self.tcx().sess.span_bug(
cmt.span, cmt.span,

View file

@ -540,7 +540,7 @@ pub fn check_cast_for_escaping_regions(
target_regions.push(r); target_regions.push(r);
} }
}, },
|_| true); |_| ());
// Check, based on the region associated with the trait, whether it can // Check, based on the region associated with the trait, whether it can
// possibly escape the enclosing fn item (note that all type parameters // 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 { fn is_re_scope(r: ty::Region) -> bool {

View file

@ -781,7 +781,7 @@ impl<'self> Visitor<()> for PrivacyVisitor<'self> {
debug!("privacy - list {}", pid.node.id); debug!("privacy - list {}", pid.node.id);
let seg = ast::PathSegment { let seg = ast::PathSegment {
identifier: pid.node.name, identifier: pid.node.name,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
}; };
let segs = ~[seg]; let segs = ~[seg];

View file

@ -4182,7 +4182,7 @@ impl Resolver {
if path.segments if path.segments
.iter() .iter()
.any(|s| s.lifetime.is_some()) { .any(|s| !s.lifetimes.is_empty()) {
self.session.span_err(path.span, self.session.span_err(path.span,
"lifetime parameters \ "lifetime parameters \
are not allowed on \ are not allowed on \

View file

@ -173,35 +173,30 @@ impl Subst for ty::Generics {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Generics { fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Generics {
ty::Generics { ty::Generics {
type_param_defs: self.type_param_defs.subst(tcx, substs), 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 { impl Subst for ty::Region {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Region { fn subst(&self, _tcx: ty::ctxt, substs: &ty::substs) -> ty::Region {
// Note: This routine only handles the self region, because it // Note: This routine only handles regions that are bound on
// is only concerned with substitutions of regions that appear // type declarationss and other outer declarations, not those
// in types. Region substitution of the bound regions that // bound in *fn types*. Region substitution of the bound
// appear in a function signature is done using the // regions that appear in a function signature is done using
// specialized routine // the specialized routine
// `middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig()`. // `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 { match self {
&ty::re_bound(ty::br_self) => { &ty::re_type_bound(_, i, _) => {
match substs.regions { match substs.regions {
ty::ErasedRegions => ty::re_static, ty::ErasedRegions => ty::re_static,
ty::NonerasedRegions(ref regions) => { ty::NonerasedRegions(ref regions) => *regions.get(i),
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)
}
} }
} }
_ => *self _ => *self

View file

@ -436,14 +436,17 @@ pub struct ClosureTy {
* Signature of a function type, which I have arbitrarily * Signature of a function type, which I have arbitrarily
* decided to use to refer to the input/output types. * 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. * - `inputs` is the list of arguments and their modes.
* - `output` is the return type. * - `output` is the return type.
* - `variadic` indicates whether this is a varidic function. (only true for foreign fns) * - `variadic` indicates whether this is a varidic function. (only true for foreign fns)
*/ */
#[deriving(Clone, Eq, IterBytes)] #[deriving(Clone, Eq, IterBytes)]
pub struct FnSig { pub struct FnSig {
bound_lifetime_names: OptVec<ast::Ident>, binder_id: ast::NodeId,
inputs: ~[t], inputs: ~[t],
output: t, output: t,
variadic: bool variadic: bool
@ -458,16 +461,13 @@ pub struct param_ty {
/// Representation of regions: /// Representation of regions:
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] #[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
pub enum Region { pub enum Region {
/// Bound regions are found (primarily) in function types. They indicate // Region bound in a type declaration (type/enum/struct/trait),
/// region parameters that have yet to be replaced with actual regions // which will be substituted when an instance of the type is accessed
/// (analogous to type parameters, except that due to the monomorphic re_type_bound(/* param id */ ast::NodeId, /*index*/ uint, ast::Ident),
/// nature of our type system, bound type parameters are always replaced
/// with fresh type variables whenever an item is referenced, so type // Region bound in a fn scope, which will be substituted when the
/// parameters only appear "free" in types. Regions in contrast can // fn is called.
/// appear free or bound.). When a function is called, all bound regions re_fn_bound(/* binder_id */ ast::NodeId, bound_region),
/// tied to that function's node-id are replaced with fresh region
/// variables whose value is then inferred.
re_bound(bound_region),
/// When checking a function body, the types of all arguments and so forth /// 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 /// that refer to bound region parameters are modified to refer to free
@ -496,42 +496,32 @@ pub enum Region {
impl Region { impl Region {
pub fn is_bound(&self) -> bool { pub fn is_bound(&self) -> bool {
match self { match self {
&re_bound(*) => true, &ty::re_type_bound(*) => true,
&ty::re_fn_bound(*) => true,
_ => false _ => false
} }
} }
} }
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] #[deriving(Clone, Eq, TotalOrd, TotalEq, IterBytes, Encodable, Decodable, ToStr)]
pub struct FreeRegion { pub struct FreeRegion {
scope_id: NodeId, scope_id: NodeId,
bound_region: bound_region bound_region: bound_region
} }
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)] #[deriving(Clone, Eq, TotalEq, TotalOrd, IterBytes, Encodable, Decodable, ToStr)]
pub enum bound_region { 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) /// An anonymous region parameter for a given fn (&T)
br_anon(uint), br_anon(uint),
/// Named region parameters for functions (a in &'a T) /// 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. /// Fresh bound identifiers created during GLB computations.
br_fresh(uint), 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 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. /// Analogous to ast::Generics.
#[deriving(Clone)] #[deriving(Clone)]
pub struct Generics { pub struct Generics {
/// List of type parameters declared on the item.
type_param_defs: @~[TypeParameterDef], type_param_defs: @~[TypeParameterDef],
region_param: Option<region_variance>,
/// List of region parameters declared on the item.
region_param_defs: @[RegionParameterDef],
} }
impl Generics { 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. /// A polytype.
/// ///
/// - `bounds`: The list of bounds for each type parameter. The length of the /// - `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)) 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); let input_args = input_tys.map(|t| *t);
mk_bare_fn(cx, mk_bare_fn(cx,
BareFnTy { BareFnTy {
purity: ast::impure_fn, purity: ast::impure_fn,
abis: AbiSet::Rust(), abis: AbiSet::Rust(),
sig: FnSig { sig: FnSig {
bound_lifetime_names: opt_vec::Empty, binder_id: binder_id,
inputs: input_args, inputs: input_args,
output: output, output: output,
variadic: false variadic: false
@ -4662,3 +4691,79 @@ pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: @str) -> u64 {
hash.result_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)
}
}
}

View file

@ -154,13 +154,11 @@ pub fn opt_ast_region_to_region<AC:AstConv,RS:RegionScope>(
fn ast_path_substs<AC:AstConv,RS:RegionScope>( fn ast_path_substs<AC:AstConv,RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
def_id: ast::DefId,
decl_generics: &ty::Generics, decl_generics: &ty::Generics,
self_ty: Option<ty::t>, self_ty: Option<ty::t>,
path: &ast::Path) -> ty::substs path: &ast::Path) -> ty::substs
{ {
/*! /*!
*
* Given a path `path` that refers to an item `I` with the * Given a path `path` that refers to an item `I` with the
* declared generics `decl_generics`, returns an appropriate * declared generics `decl_generics`, returns an appropriate
* set of substitutions for this particular reference to `I`. * set of substitutions for this particular reference to `I`.
@ -171,30 +169,28 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope>(
// If the type is parameterized by the this region, then replace this // If the type is parameterized by the this region, then replace this
// region with the current anon region binding (in other words, // region with the current anon region binding (in other words,
// whatever & would get replaced with). // whatever & would get replaced with).
let regions = match (&decl_generics.region_param, let expected_num_region_params = decl_generics.region_param_defs.len();
&path.segments.last().lifetime) { let supplied_num_region_params = path.segments.last().lifetimes.len();
(&None, &None) => { let regions = if expected_num_region_params == supplied_num_region_params {
opt_vec::Empty path.segments.last().lifetimes.map(
} |l| ast_region_to_region(this.tcx(), l))
(&None, &Some(_)) => { } 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( tcx.sess.span_err(
path.span, path.span,
format!("no region bound is allowed on `{}`, \ format!("wrong number of lifetime parameters: \
which is not declared as containing region pointers", expected {} but found {}",
ty::item_path_str(tcx, def_id))); expected_num_region_params,
opt_vec::Empty supplied_num_region_params));
} }
(&Some(_), &None) => {
let res = rscope.anon_region(path.span); match anon_regions {
let r = get_region_reporting_err(this.tcx(), path.span, &None, res); Some(v) => opt_vec::from(v),
opt_vec::with(r) None => opt_vec::from(vec::from_fn(expected_num_region_params,
} |_| ty::re_static)) // hokey
(&Some(_), &Some(_)) => {
opt_vec::with(
ast_region_to_region(this,
rscope,
path.span,
&path.segments.last().lifetime))
} }
}; };
@ -234,7 +230,7 @@ pub fn ast_path_to_substs_and_ty<AC:AstConv,
ty: decl_ty ty: decl_ty
} = this.get_item_ty(did); } = this.get_item_ty(did);
let substs = ast_path_substs(this, rscope, did, &generics, None, path); let substs = ast_path_substs(this, rscope, &generics, None, path);
let ty = ty::subst(tcx, &substs, decl_ty); let ty = ty::subst(tcx, &substs, decl_ty);
ty_param_substs_and_ty { substs: substs, ty: ty } ty_param_substs_and_ty { substs: substs, ty: ty }
} }
@ -252,7 +248,6 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope>(
ast_path_substs( ast_path_substs(
this, this,
rscope, rscope,
trait_def.trait_ref.def_id,
&trait_def.generics, &trait_def.generics,
self_ty, self_ty,
path); path);
@ -304,6 +299,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
constr: &fn(ty::mt) -> ty::t) -> ty::t constr: &fn(ty::mt) -> ty::t) -> ty::t
{ {
let tcx = this.tcx(); let tcx = this.tcx();
debug!("mk_pointer(vst={:?})", vst);
match a_seq_ty.ty.node { match a_seq_ty.ty.node {
ast::ty_vec(ref mt) => { ast::ty_vec(ref mt) => {
@ -311,6 +307,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
if a_seq_ty.mutbl == ast::MutMutable { if a_seq_ty.mutbl == ast::MutMutable {
mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl }; mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl };
} }
debug!("&[]: vst={:?}", vst);
return ty::mk_evec(tcx, mt, vst); return ty::mk_evec(tcx, mt, vst);
} }
ast::ty_path(ref path, ref bounds, id) => { ast::ty_path(ref path, ref bounds, id) => {
@ -369,7 +366,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
} }
if (flags & NO_REGIONS) != 0u { if (flags & NO_REGIONS) != 0u {
if path.segments.last().lifetime.is_some() { if !path.segments.last().lifetimes.is_empty() {
tcx.sess.span_err( tcx.sess.span_err(
path.span, path.span,
"region parameters are not allowed on this type"); "region parameters are not allowed on this type");
@ -422,8 +419,8 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
if bf.decl.variadic && !bf.abis.is_c() { if bf.decl.variadic && !bf.abis.is_c() {
tcx.sess.span_err(ast_ty.span, "variadic function must have C calling convention"); 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, ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.purity,
bf.abis, &bf.lifetimes, &bf.decl)) bf.abis, &bf.decl))
} }
ast::ty_closure(ref f) => { ast::ty_closure(ref f) => {
if f.sigil == ast::ManagedSigil { if f.sigil == ast::ManagedSigil {
@ -440,6 +437,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
}); });
let fn_decl = ty_of_closure(this, let fn_decl = ty_of_closure(this,
rscope, rscope,
ast_ty.id,
f.sigil, f.sigil,
f.purity, f.purity,
f.onceness, f.onceness,
@ -447,7 +445,6 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
&f.region, &f.region,
&f.decl, &f.decl,
None, None,
&f.lifetimes,
ast_ty.span); ast_ty.span);
ty::mk_closure(tcx, fn_decl) ty::mk_closure(tcx, fn_decl)
} }
@ -594,9 +591,8 @@ struct SelfInfo {
pub fn ty_of_method<AC:AstConv>( pub fn ty_of_method<AC:AstConv>(
this: &AC, this: &AC,
rscope: &RS, id: ast::NodeId,
purity: ast::purity, purity: ast::purity,
lifetimes: &OptVec<ast::Lifetime>,
untransformed_self_ty: ty::t, untransformed_self_ty: ty::t,
explicit_self: ast::explicit_self, explicit_self: ast::explicit_self,
decl: &ast::fn_decl) -> (Option<ty::t>, ty::BareFnTy) decl: &ast::fn_decl) -> (Option<ty::t>, ty::BareFnTy)
@ -606,33 +602,31 @@ pub fn ty_of_method<AC:AstConv>(
explicit_self: explicit_self explicit_self: explicit_self
}; };
let (a, b) = ty_of_method_or_bare_fn( 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) (a.unwrap(), b)
} }
pub fn ty_of_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>( pub fn ty_of_bare_fn<AC:AstConv>(
this: &AC, this: &AC,
rscope: &RS, id: ast::NodeId,
purity: ast::purity, purity: ast::purity,
abi: AbiSet, abi: AbiSet,
lifetimes: &OptVec<ast::Lifetime>,
decl: &ast::fn_decl) -> ty::BareFnTy decl: &ast::fn_decl) -> ty::BareFnTy
{ {
let (_, b) = ty_of_method_or_bare_fn( let (_, b) = ty_of_method_or_bare_fn(this, id, purity,
this, rscope, purity, abi, lifetimes, None, decl); abi, None, decl);
b b
} }
fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>( fn ty_of_method_or_bare_fn<AC:AstConv>(
this: &AC, this: &AC,
rscope: &RS, id: ast::NodeId,
purity: ast::purity, purity: ast::purity,
abi: AbiSet, abi: AbiSet,
lifetimes: &OptVec<ast::Lifetime>,
opt_self_info: Option<&SelfInfo>, opt_self_info: Option<&SelfInfo>,
decl: &ast::fn_decl) -> (Option<Option<ty::t>>, ty::BareFnTy) decl: &ast::fn_decl) -> (Option<Option<ty::t>>, 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 // new region names that appear inside of the fn decl are bound to
// that function type // that function type
@ -653,12 +647,10 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
ty::BareFnTy { ty::BareFnTy {
purity: purity, purity: purity,
abis: abi, abis: abi,
sig: ty::FnSig { sig: ty::FnSig {binder_id: id,
bound_lifetime_names: bound_lifetime_names, inputs: input_tys,
inputs: input_tys, output: output_ty,
output: output_ty, variadic: decl.variadic}
variadic: decl.variadic
}
}); });
fn transform_self_ty<AC:AstConv,RS:RegionScope>( fn transform_self_ty<AC:AstConv,RS:RegionScope>(
@ -697,6 +689,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
pub fn ty_of_closure<AC:AstConv,RS:RegionScope>( pub fn ty_of_closure<AC:AstConv,RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
id: ast::NodeId,
sigil: ast::Sigil, sigil: ast::Sigil,
purity: ast::purity, purity: ast::purity,
onceness: ast::Onceness, onceness: ast::Onceness,
@ -704,17 +697,10 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope>(
opt_lifetime: &Option<ast::Lifetime>, opt_lifetime: &Option<ast::Lifetime>,
decl: &ast::fn_decl, decl: &ast::fn_decl,
expected_sig: Option<ty::FnSig>, expected_sig: Option<ty::FnSig>,
lifetimes: &OptVec<ast::Lifetime>,
span: Span) span: Span)
-> ty::ClosureTy -> 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"); debug!("ty_of_fn_decl");
let _i = indenter();
// resolve the function bound region in the original region // resolve the function bound region in the original region
// scope `rscope`, not the scope of the function parameters // scope `rscope`, not the scope of the function parameters
@ -763,12 +749,10 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope>(
onceness: onceness, onceness: onceness,
region: bound_region, region: bound_region,
bounds: bounds, bounds: bounds,
sig: ty::FnSig { sig: ty::FnSig {binder_id: id,
bound_lifetime_names: bound_lifetime_names, inputs: input_tys,
inputs: input_tys, output: output_ty,
output: output_ty, variadic: decl.variadic}
variadic: decl.variadic
}
} }
} }

View file

@ -85,7 +85,6 @@ use middle::ty::*;
use middle::ty; use middle::ty;
use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{FnCtxt, impl_self_ty};
use middle::typeck::check::{structurally_resolved_type}; use middle::typeck::check::{structurally_resolved_type};
use middle::typeck::check::vtable::VtableContext;
use middle::typeck::check::vtable; use middle::typeck::check::vtable;
use middle::typeck::check; use middle::typeck::check;
use middle::typeck::infer; use middle::typeck::infer;
@ -99,7 +98,6 @@ use util::ppaux::Repr;
use std::hashmap::HashSet; use std::hashmap::HashSet;
use std::result; use std::result;
use std::vec; use std::vec;
use extra::list::Nil;
use syntax::ast::{DefId, sty_value, sty_region, sty_box}; use syntax::ast::{DefId, sty_value, sty_region, sty_box};
use syntax::ast::{sty_uniq, sty_static, NodeId}; use syntax::ast::{sty_uniq, sty_static, NodeId};
use syntax::ast::{MutMutable, MutImmutable}; use syntax::ast::{MutMutable, MutImmutable};
@ -265,8 +263,7 @@ impl<'self> LookupContext<'self> {
self.search_for_autosliced_method(self_ty, autoderefs) self.search_for_autosliced_method(self_ty, autoderefs)
} }
fn deref(&self, ty: ty::t) fn deref(&self, ty: ty::t) -> Option<ty::t> {
-> Option<ty::t> {
match ty::deref(self.tcx(), ty, false) { match ty::deref(self.tcx(), ty, false) {
None => None, None => None,
Some(t) => { Some(t) => {
@ -327,11 +324,10 @@ impl<'self> LookupContext<'self> {
ty_param(p) => { ty_param(p) => {
self.push_inherent_candidates_from_param(self_ty, 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 // Call is of the form "self.foo()" and appears in one
// of a trait's default method implementations. // of a trait's default method implementations.
self.push_inherent_candidates_from_self( self.push_inherent_candidates_from_self(self_ty);
self_ty, self_did);
} }
_ => { /* No bound methods in these types */ } _ => { /* No bound methods in these types */ }
} }
@ -448,32 +444,20 @@ impl<'self> LookupContext<'self> {
param_ty: param_ty) { param_ty: param_ty) {
debug!("push_inherent_candidates_from_param(param_ty={:?})", debug!("push_inherent_candidates_from_param(param_ty={:?})",
param_ty); param_ty);
let _indenter = indenter();
let tcx = self.tcx();
let type_param_def = match tcx.ty_param_defs.find(&param_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( 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)); param_numbered(param_ty.idx));
} }
fn push_inherent_candidates_from_self(&self, fn push_inherent_candidates_from_self(&self,
self_ty: ty::t, rcvr_ty: ty::t) {
did: DefId) { debug!("push_inherent_candidates_from_self()");
let tcx = self.tcx();
let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref;
self.push_inherent_candidates_from_bounds( 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, fn push_inherent_candidates_from_bounds(&self,
@ -574,10 +558,7 @@ impl<'self> LookupContext<'self> {
// determine the `self` of the impl with fresh // determine the `self` of the impl with fresh
// variables for each parameter: // variables for each parameter:
let location_info = &vtable::location_info_for_expr(self.self_expr); let location_info = &vtable::location_info_for_expr(self.self_expr);
let vcx = VtableContext { let vcx = self.fcx.vtable_context();
ccx: self.fcx.ccx,
infcx: self.fcx.infcx()
};
let ty::ty_param_substs_and_ty { let ty::ty_param_substs_and_ty {
substs: impl_substs, substs: impl_substs,
ty: impl_ty ty: impl_ty
@ -1010,7 +991,7 @@ impl<'self> LookupContext<'self> {
}; };
let (_, opt_transformed_self_ty, fn_sig) = let (_, opt_transformed_self_ty, fn_sig) =
replace_bound_regions_in_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( |br| self.fcx.infcx().next_region_var(
infer::BoundRegionInFnCall(self.expr.span, br))); infer::BoundRegionInFnCall(self.expr.span, br)));
let transformed_self_ty = opt_transformed_self_ty.unwrap(); let transformed_self_ty = opt_transformed_self_ty.unwrap();

View file

@ -81,10 +81,12 @@ use middle::const_eval;
use middle::pat_util::pat_id_map; use middle::pat_util::pat_id_map;
use middle::pat_util; use middle::pat_util;
use middle::lint::unreachable_code; use middle::lint::unreachable_code;
use middle::subst::Subst;
use middle::ty::{FnSig, VariantInfo}; use middle::ty::{FnSig, VariantInfo};
use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty}; use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
use middle::ty::{substs, param_ty, Disr, ExprTyProvider}; use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
use middle::ty; use middle::ty;
use middle::ty_fold::TypeFolder;
use middle::typeck::astconv::AstConv; use middle::typeck::astconv::AstConv;
use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty}; use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
use middle::typeck::astconv; use middle::typeck::astconv;
@ -99,22 +101,18 @@ use middle::typeck::check::vtable::{LocationInfo, VtableContext};
use middle::typeck::CrateCtxt; use middle::typeck::CrateCtxt;
use middle::typeck::infer::{resolve_type, force_tvar}; use middle::typeck::infer::{resolve_type, force_tvar};
use middle::typeck::infer; use middle::typeck::infer;
use middle::typeck::rscope::bound_self_region;
use middle::typeck::rscope::{RegionError};
use middle::typeck::rscope::RegionScope; 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::no_params;
use middle::typeck::{require_same_types, method_map, vtable_map}; use middle::typeck::{require_same_types, method_map, vtable_map};
use util::common::{block_query, indenter, loop_query}; use util::common::{block_query, indenter, loop_query};
use util::ppaux::{bound_region_ptr_to_str}; use util::ppaux::UserString;
use util::ppaux; use util::ppaux;
use std::hashmap::HashMap; use std::hashmap::HashMap;
use std::result; use std::result;
use std::util::replace; use std::util::replace;
use std::vec; use std::vec;
use extra::list::Nil;
use syntax::abi::AbiSet; use syntax::abi::AbiSet;
use syntax::ast::{provided, required}; use syntax::ast::{provided, required};
use syntax::ast; use syntax::ast;
@ -127,7 +125,6 @@ use syntax::codemap;
use syntax::opt_vec::OptVec; use syntax::opt_vec::OptVec;
use syntax::opt_vec; use syntax::opt_vec;
use syntax::parse::token; use syntax::parse::token;
use syntax::parse::token::special_idents;
use syntax::print::pprust; use syntax::print::pprust;
use syntax::visit; use syntax::visit;
use syntax::visit::Visitor; use syntax::visit::Visitor;
@ -157,9 +154,10 @@ pub struct SelfInfo {
/// Here, the function `foo()` and the closure passed to /// Here, the function `foo()` and the closure passed to
/// `bar()` will each have their own `FnCtxt`, but they will /// `bar()` will each have their own `FnCtxt`, but they will
/// share the inherited fields. /// share the inherited fields.
pub struct inherited { pub struct Inherited {
infcx: @mut infer::InferCtxt, infcx: @mut infer::InferCtxt,
locals: @mut HashMap<ast::NodeId, ty::t>, locals: @mut HashMap<ast::NodeId, ty::t>,
param_env: ty::ParameterEnvironment,
// Temporary tables: // Temporary tables:
node_types: @mut HashMap<ast::NodeId, ty::t>, node_types: @mut HashMap<ast::NodeId, ty::t>,
@ -249,22 +247,25 @@ pub struct FnCtxt {
// function return type. // function return type.
fn_kind: FnKind, fn_kind: FnKind,
in_scope_regions: isr_alist, inh: @Inherited,
inh: @inherited,
ccx: @mut CrateCtxt, ccx: @mut CrateCtxt,
} }
pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited { impl Inherited {
@inherited { fn new(tcx: ty::ctxt,
infcx: infer::new_infer_ctxt(ccx.tcx), param_env: ty::ParameterEnvironment)
locals: @mut HashMap::new(), -> Inherited {
node_types: @mut HashMap::new(), Inherited {
node_type_substs: @mut HashMap::new(), infcx: infer::new_infer_ctxt(tcx),
adjustments: @mut HashMap::new(), locals: @mut HashMap::new(),
method_map: @mut HashMap::new(), param_env: param_env,
vtable_map: @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(),
}
} }
} }
@ -272,17 +273,19 @@ pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited {
pub fn blank_fn_ctxt(ccx: @mut CrateCtxt, pub fn blank_fn_ctxt(ccx: @mut CrateCtxt,
rty: ty::t, rty: ty::t,
region_bnd: ast::NodeId) region_bnd: ast::NodeId)
-> @mut FnCtxt { -> @mut FnCtxt {
// It's kind of a kludge to manufacture a fake function context // 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 // 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 { @mut FnCtxt {
err_count_on_creation: ccx.tcx.sess.err_count(), err_count_on_creation: ccx.tcx.sess.err_count(),
ret_ty: rty, ret_ty: rty,
ps: PurityState::function(ast::impure_fn, 0), ps: PurityState::function(ast::impure_fn, 0),
region_lb: region_bnd, region_lb: region_bnd,
in_scope_regions: @Nil,
fn_kind: Vanilla, fn_kind: Vanilla,
inh: blank_inherited(ccx), inh: @Inherited::new(ccx.tcx, param_env),
ccx: ccx ccx: ccx
} }
} }
@ -315,14 +318,15 @@ pub fn check_bare_fn(ccx: @mut CrateCtxt,
decl: &ast::fn_decl, decl: &ast::fn_decl,
body: &ast::Block, body: &ast::Block,
id: ast::NodeId, id: ast::NodeId,
self_info: Option<SelfInfo>) { self_info: Option<SelfInfo>,
let fty = ty::node_id_to_type(ccx.tcx, id); fty: ty::t,
param_env: ty::ParameterEnvironment) {
match ty::get(fty).sty { match ty::get(fty).sty {
ty::ty_bare_fn(ref fn_ty) => { ty::ty_bare_fn(ref fn_ty) => {
let fcx = let fcx =
check_fn(ccx, self_info, fn_ty.purity, check_fn(ccx, self_info, fn_ty.purity,
&fn_ty.sig, decl, id, body, Vanilla, &fn_ty.sig, decl, id, body, Vanilla,
@Nil, blank_inherited(ccx));; @Inherited::new(ccx.tcx, param_env));
vtable::resolve_in_block(fcx, body); vtable::resolve_in_block(fcx, body);
regionck::regionck_fn(fcx, body); regionck::regionck_fn(fcx, body);
@ -411,39 +415,35 @@ pub fn check_fn(ccx: @mut CrateCtxt,
id: ast::NodeId, id: ast::NodeId,
body: &ast::Block, body: &ast::Block,
fn_kind: FnKind, 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 * Helper used by check_bare_fn and check_expr_fn. Does the
* grungy work of checking a function body and returns the * grungy work of checking a function body and returns the
* function context used for that purpose, since in the case of a * function context used for that purpose, since in the case of a
* fn item there is still a bit more to do. * 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) * - inherited: other fields inherited from the enclosing fn (if any)
*/ */
let tcx = ccx.tcx; let tcx = ccx.tcx;
let err_count_on_creation = tcx.sess.err_count(); let err_count_on_creation = tcx.sess.err_count();
// ______________________________________________________________________
// First, we have to replace any bound regions in the fn and self // First, we have to replace any bound regions in the fn and self
// types with free ones. The free region references will be bound // types with free ones. The free region references will be bound
// the node_id of the body block. // 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 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( 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, |br| ty::re_free(ty::FreeRegion {scope_id: body.id,
bound_region: br})); bound_region: br}));
let opt_self_info = let opt_self_info =
opt_self_info.map( opt_self_info.map(
|si| SelfInfo {self_ty: opt_self_ty.unwrap(), .. si}); |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); 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), ppaux::ty_to_str(tcx, ret_ty),
opt_self_info.map(|si| ppaux::ty_to_str(tcx, si.self_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, // Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context. // in the case of function expressions, based on the outer context.
let fcx: @mut FnCtxt = { let fcx: @mut FnCtxt = {
@ -465,7 +464,6 @@ pub fn check_fn(ccx: @mut CrateCtxt,
ret_ty: ret_ty, ret_ty: ret_ty,
ps: PurityState::function(purity, id), ps: PurityState::function(purity, id),
region_lb: body.id, region_lb: body.id,
in_scope_regions: isr,
fn_kind: fn_kind, fn_kind: fn_kind,
inh: inherited, inh: inherited,
ccx: ccx 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, pub fn check_no_duplicate_fields(tcx: ty::ctxt,
fields: ~[(ast::Ident, Span)]) { fields: ~[(ast::Ident, Span)]) {
let mut field_names = HashMap::new(); let mut field_names = HashMap::new();
@ -566,7 +544,7 @@ pub fn check_no_duplicate_fields(tcx: ty::ctxt,
match orig_sp { match orig_sp {
Some(orig_sp) => { Some(orig_sp) => {
tcx.sess.span_err(sp, format!("Duplicate field name {} in record type declaration", 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"); tcx.sess.span_note(orig_sp, "First declaration of this field occurred here");
break; break;
} }
@ -603,18 +581,32 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
it.id); it.id);
} }
ast::item_fn(ref decl, _, _, _, ref body) => { 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) => { ast::item_impl(_, ref opt_trait_ref, _, ref ms) => {
let rp = ccx.tcx.region_paramd_items.find(&it.id).map(|x| *x); debug!("item_impl {} with id {}", ccx.tcx.sess.str_of(it.ident), it.id);
debug!("item_impl {} with id {} rp {:?}",
ccx.tcx.sess.str_of(it.ident), it.id, rp); let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
for m in ms.iter() { for m in ms.iter() {
check_method(ccx, *m); check_method_body(ccx, &impl_tpt.generics, None, *m);
} }
vtable::resolve_impl(ccx, it); vtable::resolve_impl(ccx, it);
} }
ast::item_trait(_, _, ref trait_methods) => { 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() { for trait_method in (*trait_methods).iter() {
match *trait_method { match *trait_method {
required(*) => { required(*) => {
@ -622,7 +614,8 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
// bodies to check. // bodies to check.
} }
provided(m) => { 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, &param_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, &param_env.free_substs);
check_bare_fn(
ccx,
&method.decl,
&method.body,
method.id,
opt_self_info,
fty,
param_env);
}
impl AstConv for FnCtxt { impl AstConv for FnCtxt {
fn tcx(&self) -> ty::ctxt { self.ccx.tcx } fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
@ -682,48 +727,26 @@ impl FnCtxt {
pub fn infcx(&self) -> @mut infer::InferCtxt { pub fn infcx(&self) -> @mut infer::InferCtxt {
self.inh.infcx self.inh.infcx
} }
pub fn err_count_since_creation(&self) -> uint { pub fn err_count_since_creation(&self) -> uint {
self.ccx.tcx.sess.err_count() - self.err_count_on_creation self.ccx.tcx.sess.err_count() - self.err_count_on_creation
} }
pub fn search_in_scope_regions(&self,
span: Span, pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
br: ty::bound_region) VtableContext {
-> Result<ty::Region, RegionError> { infcx: self.infcx(),
let in_scope_regions = self.in_scope_regions; param_env: &self.inh.param_env
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))
}
})
}
}
} }
} }
} }
impl RegionScope for FnCtxt { impl RegionScope for @mut infer::InferCtxt {
fn anon_region(&self, span: Span) -> Result<ty::Region, RegionError> { fn anon_regions(&self,
result::Ok(self.infcx().next_region_var(infer::MiscVariable(span)))
}
fn self_region(&self, span: Span) -> Result<ty::Region, RegionError> {
self.search_in_scope_regions(span, ty::br_self)
}
fn named_region(&self,
span: Span, span: Span,
id: ast::Ident) -> Result<ty::Region, RegionError> { count: uint) -> Option<~[ty::Region]> {
self.search_in_scope_regions(span, ty::br_named(id)) 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 { 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 { pub fn pat_to_str(&self, pat: @ast::Pat) -> ~str {
@ -817,7 +840,7 @@ impl FnCtxt {
Some(&t) => t, Some(&t) => t,
None => { None => {
self.tcx().sess.bug(format!("no type for expr in fcx {}", self.tcx().sess.bug(format!("no type for expr in fcx {}",
self.tag())); self.tag()));
} }
} }
} }
@ -828,10 +851,10 @@ impl FnCtxt {
None => { None => {
self.tcx().sess.bug( self.tcx().sess.bug(
format!("no type for node {}: {} in fcx {}", format!("no type for node {}: {} in fcx {}",
id, ast_map::node_id_to_str( id, ast_map::node_id_to_str(
self.tcx().items, id, self.tcx().items, id,
token::get_ident_interner()), token::get_ident_interner()),
self.tag())); self.tag()));
} }
} }
} }
@ -842,10 +865,9 @@ impl FnCtxt {
None => { None => {
self.tcx().sess.bug( self.tcx().sess.bug(
format!("no type substs for node {}: {} in fcx {}", format!("no type substs for node {}: {} in fcx {}",
id, ast_map::node_id_to_str( id, ast_map::node_id_to_str(self.tcx().items, id,
self.tcx().items, id, token::get_ident_interner()),
token::get_ident_interner()), self.tag()));
self.tag()));
} }
} }
} }
@ -924,20 +946,6 @@ impl FnCtxt {
v v
} }
pub fn region_var_if_parameterized(&self,
rp: Option<ty::region_variance>,
span: Span)
-> OptVec<ty::Region> {
match rp {
None => opt_vec::Empty,
Some(_) => {
opt_vec::with(
self.infcx().next_region_var(
infer::BoundRegionInTypeOrImpl(span)))
}
}
}
pub fn type_error_message(&self, pub fn type_error_message(&self,
sp: Span, sp: Span,
mk_msg: &fn(~str) -> ~str, mk_msg: &fn(~str) -> ~str,
@ -1105,20 +1113,22 @@ pub fn impl_self_ty(vcx: &VtableContext,
-> ty_param_substs_and_ty { -> ty_param_substs_and_ty {
let tcx = vcx.tcx(); 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); 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() { let rps =
opt_vec::with(vcx.infcx.next_region_var( vcx.infcx.next_region_vars(
infer::BoundRegionInTypeOrImpl(location_info.span))) infer::BoundRegionInTypeOrImpl(location_info.span),
} else { n_rps);
opt_vec::Empty
});
let tps = vcx.infcx.next_ty_vars(n_tps); 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); let substd_ty = ty::subst(tcx, &substs, raw_ty);
ty_param_substs_and_ty { substs: substs, ty: substd_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 // Verify that no lifetimes or type parameters are present anywhere
// except the final two elements of the path. // except the final two elements of the path.
for i in range(0, path.segments.len() - 2) { for i in range(0, path.segments.len() - 2) {
match path.segments[i].lifetime { for lifetime in path.segments[i].lifetimes.iter() {
None => {} function_context.tcx()
Some(lifetime) => { .sess
function_context.tcx() .span_err(lifetime.span,
.sess "lifetime parameters may not \
.span_err(lifetime.span, appear here");
"lifetime parameters may not \ break;
appear here")
}
} }
for typ in path.segments[i].types.iter() { for typ in path.segments[i].types.iter() {
function_context.tcx() function_context.tcx()
.sess .sess
.span_err(typ.span, .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. // rest of typechecking will (attempt to) infer everything.
if path.segments if path.segments
.iter() .iter()
.all(|s| s.lifetime.is_none() && s.types.is_empty()) { .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
return 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 // Make sure lifetime parameterization agrees with the trait or
// implementation type. // implementation type.
match (generics.region_param, trait_segment.lifetime) { let trait_region_parameter_count = generics.region_param_defs.len();
(Some(_), None) => { let supplied_region_parameter_count = trait_segment.lifetimes.len();
function_context.tcx() if trait_region_parameter_count != supplied_region_parameter_count
.sess && supplied_region_parameter_count != 0 {
.span_err(path.span, function_context.tcx()
format!("this {} has a lifetime \ .sess
parameter but no \ .span_err(path.span,
lifetime was specified", format!("expected {} lifetime parameter(s), \
name)) found {} lifetime parameter(s)",
} trait_region_parameter_count,
(None, Some(_)) => { supplied_region_parameter_count));
function_context.tcx()
.sess
.span_err(path.span,
format!("this {} has no lifetime \
parameter but a lifetime \
was specified",
name))
}
(Some(_), Some(_)) | (None, None) => {}
} }
// Make sure the number of type parameters supplied on the trait // 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 // Verify that no lifetimes or type parameters are present on
// the penultimate segment of the path. // the penultimate segment of the path.
let segment = &path.segments[path.segments.len() - 2]; let segment = &path.segments[path.segments.len() - 2];
match segment.lifetime { for lifetime in segment.lifetimes.iter() {
None => {} function_context.tcx()
Some(lifetime) => { .sess
function_context.tcx() .span_err(lifetime.span,
.sess "lifetime parameters may not
.span_err(lifetime.span, appear here");
"lifetime parameters may not break;
appear here")
}
} }
for typ in segment.types.iter() { for typ in segment.types.iter() {
function_context.tcx() function_context.tcx()
@ -1292,10 +1290,7 @@ fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt,
.span_err(typ.span, .span_err(typ.span,
"type parameters may not appear \ "type parameters may not appear \
here"); here");
function_context.tcx() break;
.sess
.span_note(typ.span,
format!("this is a {:?}", def));
} }
} }
} }
@ -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 // In that case, we check each argument against "error" in order to
// set up all the node type bindings. // set up all the node type bindings.
let error_fn_sig = FnSig { let error_fn_sig = FnSig {
bound_lifetime_names: opt_vec::Empty, binder_id: ast::CRATE_NODE_ID,
inputs: err_args(args.len()), inputs: err_args(args.len()),
output: ty::mk_err(), output: ty::mk_err(),
variadic: false variadic: false
@ -1577,7 +1572,6 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
// signature with region variables // signature with region variables
let (_, _, fn_sig) = let (_, _, fn_sig) =
replace_bound_regions_in_fn_sig(fcx.tcx(), replace_bound_regions_in_fn_sig(fcx.tcx(),
@Nil,
None, None,
fn_sig, fn_sig,
|br| fcx.infcx() |br| fcx.infcx()
@ -1908,10 +1902,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
expected: Option<ty::t>) { expected: Option<ty::t>) {
let tcx = fcx.ccx.tcx; let tcx = fcx.ccx.tcx;
// Find the expected input/output types (if any). Careful to // Find the expected input/output types (if any). Substitute
// avoid capture of bound regions in the expected type. See // fresh bound regions for any bound regions we find in the
// def'n of br_cap_avoid() for a more lengthy explanation of // expected types so as to avoid capture.
// what's going on here. //
// Also try to pick up inferred purity and sigil, defaulting // Also try to pick up inferred purity and sigil, defaulting
// to impure and block. Note that we only will use those for // to impure and block. Note that we only will use those for
// block syntax lambdas; that is, lambdas without explicit // block syntax lambdas; that is, lambdas without explicit
@ -1927,11 +1921,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
expected_bounds) = { expected_bounds) = {
match expected_sty { match expected_sty {
Some(ty::ty_closure(ref cenv)) => { Some(ty::ty_closure(ref cenv)) => {
let id = expr.id;
let (_, _, sig) = let (_, _, sig) =
replace_bound_regions_in_fn_sig( replace_bound_regions_in_fn_sig(
tcx, @Nil, None, &cenv.sig, tcx, None, &cenv.sig,
|br| ty::re_bound(ty::br_cap_avoid(id, @br))); |_| fcx.inh.infcx.fresh_bound_region(expr.id));
(Some(sig), cenv.purity, cenv.sigil, (Some(sig), cenv.purity, cenv.sigil,
cenv.onceness, cenv.bounds) cenv.onceness, cenv.bounds)
} }
@ -1952,7 +1945,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
// construct the function type // construct the function type
let fn_ty = astconv::ty_of_closure(fcx, let fn_ty = astconv::ty_of_closure(fcx,
fcx, &fcx.infcx(),
expr.id,
sigil, sigil,
purity, purity,
expected_onceness, expected_onceness,
@ -1960,13 +1954,12 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
&None, &None,
decl, decl,
expected_sig, expected_sig,
&opt_vec::Empty,
expr.span); expr.span);
let fty_sig; let fty_sig;
let fty = if error_happened { let fty = if error_happened {
fty_sig = FnSig { fty_sig = FnSig {
bound_lifetime_names: opt_vec::Empty, binder_id: ast::CRATE_NODE_ID,
inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()), inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()),
output: ty::mk_err(), output: ty::mk_err(),
variadic: false variadic: false
@ -1989,7 +1982,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
sigil); sigil);
check_fn(fcx.ccx, None, inherited_purity, &fty_sig, 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 // Look up the number of type parameters and the raw type, and
// determine whether the class is region-parameterized. // determine whether the class is region-parameterized.
let type_parameter_count; let item_type = ty::lookup_item_type(tcx, class_id);
let region_parameterized; let type_parameter_count = item_type.generics.type_param_defs.len();
let raw_type; let region_parameter_count = item_type.generics.region_param_defs.len();
if class_id.crate == ast::LOCAL_CRATE { let raw_type = item_type.ty;
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;
}
// Generate the struct type. // Generate the struct type.
let regions = let regions = fcx.infcx().next_region_vars(
fcx.region_var_if_parameterized(region_parameterized, span); infer::BoundRegionInTypeOrImpl(span),
region_parameter_count);
let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
let substitutions = substs { let substitutions = substs {
regions: ty::NonerasedRegions(regions), regions: ty::NonerasedRegions(opt_vec::from(regions)),
self_ty: None, self_ty: None,
tps: type_parameters 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 // Look up the number of type parameters and the raw type, and
// determine whether the enum is region-parameterized. // determine whether the enum is region-parameterized.
let type_parameter_count; let item_type = ty::lookup_item_type(tcx, enum_id);
let region_parameterized; let type_parameter_count = item_type.generics.type_param_defs.len();
let raw_type; let region_parameter_count = item_type.generics.region_param_defs.len();
if enum_id.crate == ast::LOCAL_CRATE { let raw_type = item_type.ty;
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;
}
// Generate the enum type. // Generate the enum type.
let regions = let regions = fcx.infcx().next_region_vars(
fcx.region_var_if_parameterized(region_parameterized, span); infer::BoundRegionInTypeOrImpl(span),
region_parameter_count);
let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
let substitutions = substs { let substitutions = substs {
regions: ty::NonerasedRegions(regions), regions: ty::NonerasedRegions(opt_vec::from(regions)),
self_ty: None, self_ty: None,
tps: type_parameters tps: type_parameters
}; };
@ -3445,28 +3376,25 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
ty_param_count, ty_param_count,
ty_substs_len); 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 // (if any) and otherwise using a fresh region variable
let regions = match pth.segments.last().lifetime { let num_expected_regions = tpt.generics.region_param_defs.len();
Some(_) => { // user supplied a lifetime parameter... let num_supplied_regions = pth.segments.last().lifetimes.len();
match tpt.generics.region_param { let regions = if num_expected_regions == num_supplied_regions {
None => { // ...but the type is not lifetime parameterized! pth.segments.last().lifetimes.map(
fcx.ccx.tcx.sess.span_err |l| ast_region_to_region(fcx.tcx(), l))
(span, "this item is not region-parameterized"); } else {
opt_vec::Empty if num_supplied_regions != 0 {
} fcx.ccx.tcx.sess.span_err(
Some(_) => { // ...and the type is lifetime parameterized, ok. span,
opt_vec::with( format!("expected {} lifetime parameter(s), \
ast_region_to_region(fcx, found {} lifetime parameter(s)",
fcx, num_expected_regions, num_supplied_regions));
span,
&pth.segments.last().lifetime))
}
}
}
None => { // no lifetime parameter supplied, insert default
fcx.region_var_if_parameterized(tpt.generics.region_param, span)
} }
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 // 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; } if tps.len() == 0u { return; }
let mut tps_used = vec::from_elem(tps.len(), false); let mut tps_used = vec::from_elem(tps.len(), false);
ty::walk_regions_and_ty( ty::walk_ty(ty, |t| {
ccx.tcx, ty,
|_r| {},
|t| {
match ty::get(t).sty { match ty::get(t).sty {
ty::ty_param(param_ty {idx, _}) => { ty::ty_param(param_ty {idx, _}) => {
debug!("Found use of ty param \\#{}", idx); debug!("Found use of ty param \\#{}", idx);
tps_used[idx] = true; tps_used[idx] = true;
} }
_ => () _ => ()
} }
true
}); });
for (i, b) in tps_used.iter().enumerate() { 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 //We only care about the operation here
match split[1] { match split[1] {
"cxchg" => (0, ~[ty::mk_mut_rptr(tcx, "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(),
ty::mk_int() ty::mk_int()
], ty::mk_int()), ], ty::mk_int()),
"load" => (0, "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()), ty::mk_int()),
"store" => (0, "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_int()
], ],
ty::mk_nil()), 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" | "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
"min" | "umax" | "umin" => { "min" | "umax" | "umin" => {
(0, ~[ty::mk_mut_rptr(tcx, (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()), ty::mk_int() ], ty::mk_int())
} }
"fence" => { "fence" => {
@ -3726,7 +3650,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
"move_val" | "move_val_init" => { "move_val" | "move_val_init" => {
(1u, (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) param(ccx, 0u)
], ],
ty::mk_nil()) 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" => { "atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => {
(0, (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()
], ],
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, Ok(t) => t,
Err(s) => { tcx.sess.span_fatal(it.span, s); } 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) { let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
Ok((_, vot)) => vot, Ok((_, vot)) => vot,
Err(s) => { tcx.sess.span_fatal(it.span, s); } 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 { let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
purity: ast::unsafe_fn, purity: ast::unsafe_fn,
abis: AbiSet::Intrinsic(), abis: AbiSet::Intrinsic(),
sig: FnSig { sig: FnSig {binder_id: it.id,
bound_lifetime_names: opt_vec::Empty, inputs: inputs,
inputs: inputs, output: output,
output: output, variadic: false}
variadic: false
}
}); });
let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
let i_n_tps = i_ty.generics.type_param_defs.len(); 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))); ppaux::ty_to_str(ccx.tcx, fty)));
} }
} }

View file

@ -535,8 +535,14 @@ fn constrain_call(rcx: &mut Rcx,
//! appear in the arguments appropriately. //! appear in the arguments appropriately.
let tcx = rcx.fcx.tcx(); let tcx = rcx.fcx.tcx();
debug!("constrain_call(call_expr={}, implicitly_ref_args={:?})", debug!("constrain_call(call_expr={}, \
call_expr.repr(tcx), implicitly_ref_args); 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); let callee_ty = rcx.resolve_node_type(callee_id);
if ty::type_is_error(callee_ty) { if ty::type_is_error(callee_ty) {
// Bail, as function type is unknown // Bail, as function type is unknown
@ -552,6 +558,8 @@ fn constrain_call(rcx: &mut Rcx,
let callee_region = ty::re_scope(callee_scope); let callee_region = ty::re_scope(callee_scope);
for &arg_expr in arg_exprs.iter() { for &arg_expr in arg_exprs.iter() {
debug!("Argument");
// ensure that any regions appearing in the argument type are // ensure that any regions appearing in the argument type are
// valid for at least the lifetime of the function: // valid for at least the lifetime of the function:
constrain_regions_in_type_of_node( constrain_regions_in_type_of_node(
@ -569,6 +577,7 @@ fn constrain_call(rcx: &mut Rcx,
// as loop above, but for receiver // as loop above, but for receiver
for &r in receiver.iter() { for &r in receiver.iter() {
debug!("Receiver");
constrain_regions_in_type_of_node( constrain_regions_in_type_of_node(
rcx, r.id, callee_region, infer::CallRcvr(r.span)); rcx, r.id, callee_region, infer::CallRcvr(r.span));
if implicitly_ref_args { if implicitly_ref_args {
@ -727,9 +736,9 @@ fn constrain_regions_in_type(
ty_to_str(tcx, ty)); ty_to_str(tcx, ty));
do relate_nested_regions(tcx, Some(minimum_lifetime), ty) |r_sub, r_sup| { do relate_nested_regions(tcx, Some(minimum_lifetime), ty) |r_sub, r_sup| {
debug!("relate(r_sub={}, r_sup={})", debug!("relate_nested_regions(r_sub={}, r_sup={})",
region_to_str(tcx, "", false, r_sub), r_sub.repr(tcx),
region_to_str(tcx, "", false, r_sup)); r_sup.repr(tcx));
if r_sup.is_bound() || r_sub.is_bound() { if r_sup.is_bound() || r_sub.is_bound() {
// a bound region is one which appears inside an fn type. // a bound region is one which appears inside an fn type.

View file

@ -10,155 +10,41 @@
// #[warn(deprecated_mode)]; // #[warn(deprecated_mode)];
use middle::ty; use middle::ty;
use middle::ty_fold;
use middle::typeck::isr_alist; use middle::ty_fold::TypeFolder;
use util::common::indenter; use std::hashmap::HashMap;
use util::ppaux::region_to_str; use util::ppaux::Repr;
use util::ppaux; use util::ppaux;
use extra::list::Cons;
// Helper functions related to manipulating region types. // Helper functions related to manipulating region types.
pub fn replace_bound_regions_in_fn_sig( pub fn replace_bound_regions_in_fn_sig(
tcx: ty::ctxt, tcx: ty::ctxt,
isr: isr_alist,
opt_self_ty: Option<ty::t>, opt_self_ty: Option<ty::t>,
fn_sig: &ty::FnSig, fn_sig: &ty::FnSig,
mapf: &fn(ty::bound_region) -> ty::Region) mapf: &fn(ty::bound_region) -> ty::Region)
-> (isr_alist, Option<ty::t>, ty::FnSig) -> (HashMap<ty::bound_region,ty::Region>, Option<ty::t>, 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) } let mut map = HashMap::new();
let (fn_sig, opt_self_ty) = {
debug!("replace_bound_regions_in_fn_sig(self_ty={:?}, fn_sig={}, \ let mut f = ty_fold::RegionFolder::regions(tcx, |r| {
all_tys={:?})", debug!("region r={}", r.to_str());
opt_self_ty.map(|t| ppaux::ty_to_str(tcx, t)), match r {
ppaux::fn_sig_to_str(tcx, fn_sig), ty::re_fn_bound(s, br) if s == fn_sig.binder_id => {
all_tys.map(|t| ppaux::ty_to_str(tcx, *t))); *map.find_or_insert_with(br, |_| mapf(br))
let _i = indenter(); }
_ => r
let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| { }});
debug!("br={:?}", br); (ty_fold::super_fold_sig(&mut f, fn_sig),
mapf(br) ty_fold::fold_opt_ty(&mut f, opt_self_ty))
}; };
let new_fn_sig = ty::fold_sig(fn_sig, |t| { debug!("resulting map: {}", map.to_str());
replace_bound_regions(tcx, isr, t) (map, opt_self_ty, fn_sig)
});
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
}
}
} }
pub fn relate_nested_regions( pub fn relate_nested_regions(
@ -168,7 +54,6 @@ pub fn relate_nested_regions(
relate_op: &fn(ty::Region, ty::Region)) relate_op: &fn(ty::Region, ty::Region))
{ {
/*! /*!
*
* This rather specialized function walks each region `r` that appear * This rather specialized function walks each region `r` that appear
* in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl` * 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 * 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`. * Hence, in the second example above, `'r2` must be a subregion of `'r3`.
*/ */
let mut the_stack = ~[]; let mut rr = RegionRelator { tcx: tcx,
for &r in opt_region.iter() { the_stack.push(r); } stack: ~[],
walk_ty(tcx, &mut the_stack, ty, relate_op); 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, struct RegionRelator<'self> {
the_stack: &mut ~[ty::Region], tcx: ty::ctxt,
ty: ty::t, stack: ~[ty::Region],
relate_op: &fn(ty::Region, ty::Region)) relate_op: &'self fn(ty::Region, ty::Region),
{ }
match ty::get(ty).sty {
ty::ty_rptr(r, ref mt) | // FIXME we should define more precisely when a
ty::ty_evec(ref mt, ty::vstore_slice(r)) => { // region is considered "nested" and take variance into account.
relate(*the_stack, r, |x,y| relate_op(x,y)); //
the_stack.push(r); // I can't decide whether skipping closure parameter types and
walk_ty(tcx, the_stack, mt.ty, |x,y| relate_op(x,y)); // so on is necessary or not. What is the difference, after all,
the_stack.pop(); // 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
ty::fold_regions_and_ty( // all such cases until it "proves necessary")
tcx,
ty, impl<'self> TypeFolder for RegionRelator<'self> {
|r| { relate( *the_stack, r, |x,y| relate_op(x,y)); r }, fn tcx(&self) -> ty::ctxt {
|t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t }, self.tcx
|t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t }); }
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], impl<'self> RegionRelator<'self> {
r_sub: ty::Region, fn relate(&mut self, r_sub: ty::Region) {
relate_op: &fn(ty::Region, ty::Region)) for &r in self.stack.iter() {
{ if !r.is_bound() && !r_sub.is_bound() {
for &r in the_stack.iter() { (self.relate_op)(r, r_sub);
if !r.is_bound() && !r_sub.is_bound() { }
relate_op(r, r_sub);
} }
} }
} }

View file

@ -11,6 +11,7 @@
use middle::ty::param_ty; use middle::ty::param_ty;
use middle::ty; use middle::ty;
use middle::ty_fold::TypeFolder;
use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{FnCtxt, impl_self_ty};
use middle::typeck::check::{structurally_resolved_type}; use middle::typeck::check::{structurally_resolved_type};
use middle::typeck::infer::fixup_err_to_str; 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 /// A vtable context includes an inference context, a crate context, and a
/// callback function to call in case of type error. /// callback function to call in case of type error.
pub struct VtableContext { pub struct VtableContext<'self> {
ccx: @mut CrateCtxt, infcx: @mut infer::InferCtxt,
infcx: @mut infer::InferCtxt param_env: &'self ty::ParameterEnvironment,
} }
impl VtableContext { impl<'self> VtableContext<'self> {
pub fn tcx(&self) -> ty::ctxt { self.ccx.tcx } pub fn tcx(&self) -> ty::ctxt { self.infcx.tcx }
} }
fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool { fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool {
@ -95,7 +96,6 @@ fn lookup_vtables(vcx: &VtableContext,
substs.repr(vcx.tcx())); substs.repr(vcx.tcx()));
let _i = indenter(); let _i = indenter();
// We do this backwards for reasons discussed above. // We do this backwards for reasons discussed above.
assert_eq!(substs.tps.len(), type_param_defs.len()); assert_eq!(substs.tps.len(), type_param_defs.len());
let mut result = let mut result =
@ -233,8 +233,6 @@ fn lookup_vtable(vcx: &VtableContext,
vcx.infcx.trait_ref_to_str(trait_ref)); vcx.infcx.trait_ref_to_str(trait_ref));
let _i = indenter(); let _i = indenter();
let tcx = vcx.tcx();
let ty = match fixup_ty(vcx, location_info, ty, is_early) { let ty = match fixup_ty(vcx, location_info, ty, is_early) {
Some(ty) => ty, Some(ty) => ty,
None => { None => {
@ -250,18 +248,21 @@ fn lookup_vtable(vcx: &VtableContext,
// If the type is self or a param, we look at the trait/supertrait // 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. // bounds to see if they include the trait we are looking for.
let vtable_opt = match ty::get(ty).sty { let vtable_opt = match ty::get(ty).sty {
ty::ty_param(param_ty {idx: n, def_id: did}) => { ty::ty_param(param_ty {idx: n, _}) => {
let type_param_def = tcx.ty_param_defs.get(&did.node); let type_param_bounds: &[@ty::TraitRef] =
lookup_vtable_from_bounds(vcx, location_info, vcx.param_env.type_param_bounds[n].trait_bounds;
type_param_def.bounds.trait_bounds, lookup_vtable_from_bounds(vcx,
location_info,
type_param_bounds,
param_numbered(n), param_numbered(n),
trait_ref) trait_ref)
} }
ty::ty_self(trait_id) => { ty::ty_self(_) => {
let self_trait_ref = ty::lookup_trait_def(tcx, trait_id).trait_ref; let self_param_bound = vcx.param_env.self_param_bound.unwrap();
lookup_vtable_from_bounds(vcx, location_info, lookup_vtable_from_bounds(vcx,
&[self_trait_ref], location_info,
[self_param_bound],
param_self, param_self,
trait_ref) trait_ref)
} }
@ -285,7 +286,7 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext,
bounds: &[@ty::TraitRef], bounds: &[@ty::TraitRef],
param: param_index, param: param_index,
trait_ref: @ty::TraitRef) trait_ref: @ty::TraitRef)
-> Option<vtable_origin> { -> Option<vtable_origin> {
let tcx = vcx.tcx(); let tcx = vcx.tcx();
let mut n_bound = 0; let mut n_bound = 0;
@ -317,8 +318,7 @@ fn search_for_vtable(vcx: &VtableContext,
ty: ty::t, ty: ty::t,
trait_ref: @ty::TraitRef, trait_ref: @ty::TraitRef,
is_early: bool) is_early: bool)
-> Option<vtable_origin> -> Option<vtable_origin> {
{
let tcx = vcx.tcx(); let tcx = vcx.tcx();
let mut found = ~[]; let mut found = ~[];
@ -494,7 +494,8 @@ fn fixup_substs(vcx: &VtableContext,
fn fixup_ty(vcx: &VtableContext, fn fixup_ty(vcx: &VtableContext,
location_info: &LocationInfo, location_info: &LocationInfo,
ty: ty::t, ty: ty::t,
is_early: bool) -> Option<ty::t> { is_early: bool)
-> Option<ty::t> {
let tcx = vcx.tcx(); let tcx = vcx.tcx();
match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) { match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) {
Ok(new_type) => Some(new_type), Ok(new_type) => Some(new_type),
@ -515,8 +516,7 @@ fn connect_trait_tps(vcx: &VtableContext,
location_info: &LocationInfo, location_info: &LocationInfo,
impl_substs: &ty::substs, impl_substs: &ty::substs,
trait_ref: @ty::TraitRef, trait_ref: @ty::TraitRef,
impl_did: ast::DefId) impl_did: ast::DefId) {
{
let tcx = vcx.tcx(); let tcx = vcx.tcx();
let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) { 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) { if has_trait_bounds(*item_ty.generics.type_param_defs) {
debug!("early_resolve_expr: looking up vtables for type params {}", debug!("early_resolve_expr: looking up vtables for type params {}",
item_ty.generics.type_param_defs.repr(fcx.tcx())); 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), let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex),
*item_ty.generics.type_param_defs, *item_ty.generics.type_param_defs,
substs, is_early); substs, is_early);
@ -599,7 +599,7 @@ pub fn early_resolve_expr(ex: @ast::Expr,
ex.repr(fcx.tcx())); ex.repr(fcx.tcx()));
if has_trait_bounds(*type_param_defs) { if has_trait_bounds(*type_param_defs) {
let substs = fcx.node_ty_substs(callee_id); 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), let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex),
*type_param_defs, &substs, is_early); *type_param_defs, &substs, is_early);
if !is_early { if !is_early {
@ -642,10 +642,7 @@ pub fn early_resolve_expr(ex: @ast::Expr,
(&ty::ty_rptr(_, mt), ty::RegionTraitStore(*)) => { (&ty::ty_rptr(_, mt), ty::RegionTraitStore(*)) => {
let location_info = let location_info =
&location_info_for_expr(ex); &location_info_for_expr(ex);
let vcx = VtableContext { let vcx = fcx.vtable_context();
ccx: fcx.ccx,
infcx: fcx.infcx()
};
let target_trait_ref = @ty::TraitRef { let target_trait_ref = @ty::TraitRef {
def_id: target_def_id, def_id: target_def_id,
substs: ty::substs { substs: ty::substs {
@ -726,48 +723,58 @@ fn resolve_expr(fcx: @mut FnCtxt,
visit::walk_expr(&mut fcx, ex, ()); visit::walk_expr(&mut fcx, ex, ());
} }
pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { pub fn resolve_impl(ccx: @mut CrateCtxt,
let def_id = ast_util::local_def(impl_item.id); impl_item: @ast::item,
match ty::impl_trait_ref(ccx.tcx, def_id) { impl_generics: &ty::Generics,
None => {}, impl_trait_ref: &ty::TraitRef) {
Some(trait_ref) => { let param_env = ty::construct_parameter_environment(
let infcx = infer::new_infer_ctxt(ccx.tcx); ccx.tcx,
let vcx = VtableContext { ccx: ccx, infcx: infcx }; None,
let loc_info = location_info_for_item(impl_item); *impl_generics.type_param_defs,
[],
impl_generics.region_param_defs,
impl_item.id);
// First, check that the impl implements any trait bounds let impl_trait_ref = @impl_trait_ref.subst(ccx.tcx, &param_env.free_substs);
// 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);
// Now, locate the vtable for the impl itself. The real let infcx = infer::new_infer_ctxt(ccx.tcx);
// purpose of this is to check for supertrait impls, let vcx = VtableContext { infcx: infcx, param_env: &param_env };
// but that falls out of doing this. let loc_info = location_info_for_item(impl_item);
let param_bounds = ty::ParamBounds {
builtin_bounds: ty::EmptyBuiltinBounds(), // First, check that the impl implements any trait bounds
trait_bounds: ~[trait_ref] // on the trait.
}; let trait_def = ty::lookup_trait_def(ccx.tcx, impl_trait_ref.def_id);
let t = ty::node_id_to_type(ccx.tcx, impl_item.id); let vtbls = lookup_vtables(&vcx,
debug!("=== Doing a self lookup now."); &loc_info,
// Right now, we don't have any place to store this. *trait_def.generics.type_param_defs,
// We will need to make one so we can use this information &impl_trait_ref.substs,
// for compiling default methods that refer to supertraits. false);
let self_vtable_res =
lookup_vtables_for_param(&vcx, &loc_info, None, // Now, locate the vtable for the impl itself. The real
&param_bounds, t, false); // 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, &param_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,
&param_bounds, t, false);
let res = impl_res { let res = impl_res {
trait_vtables: vtbls, trait_vtables: vtbls,
self_vtables: self_vtable_res self_vtables: self_vtable_res
}; };
ccx.tcx.impl_vtables.insert(def_id, 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 { impl visit::Visitor<()> for @mut FnCtxt {

View file

@ -357,8 +357,8 @@ impl CoherenceChecker {
@vec::append( @vec::append(
(*impl_poly_type.generics.type_param_defs).clone(), (*impl_poly_type.generics.type_param_defs).clone(),
*new_method_ty.generics.type_param_defs), *new_method_ty.generics.type_param_defs),
region_param: region_param_defs:
impl_poly_type.generics.region_param impl_poly_type.generics.region_param_defs
}; };
let new_polytype = ty::ty_param_bounds_and_ty { let new_polytype = ty::ty_param_bounds_and_ty {
generics: new_generics, generics: new_generics,
@ -482,20 +482,17 @@ impl CoherenceChecker {
pub fn universally_quantify_polytype(&self, pub fn universally_quantify_polytype(&self,
polytype: ty_param_bounds_and_ty) polytype: ty_param_bounds_and_ty)
-> UniversalQuantificationResult { -> UniversalQuantificationResult {
let regions = match polytype.generics.region_param { let region_parameter_count = polytype.generics.region_param_defs.len();
None => opt_vec::Empty, let region_parameters =
Some(_) => { self.inference_context.next_region_vars(
opt_vec::with( infer::BoundRegionInCoherence,
self.inference_context.next_region_var( region_parameter_count);
infer::BoundRegionInCoherence))
}
};
let bounds_count = polytype.generics.type_param_defs.len(); let bounds_count = polytype.generics.type_param_defs.len();
let type_parameters = self.inference_context.next_ty_vars(bounds_count); let type_parameters = self.inference_context.next_ty_vars(bounds_count);
let substitutions = substs { let substitutions = substs {
regions: ty::NonerasedRegions(regions), regions: ty::NonerasedRegions(opt_vec::from(region_parameters)),
self_ty: None, self_ty: None,
tps: type_parameters tps: type_parameters
}; };

View file

@ -39,15 +39,10 @@ use middle::subst::Subst;
use middle::typeck::astconv::{AstConv, ty_of_arg}; use middle::typeck::astconv::{AstConv, ty_of_arg};
use middle::typeck::astconv::{ast_ty_to_ty}; use middle::typeck::astconv::{ast_ty_to_ty};
use middle::typeck::astconv; use middle::typeck::astconv;
use middle::typeck::infer;
use middle::typeck::rscope::*; use middle::typeck::rscope::*;
use middle::typeck::rscope;
use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
use util::common::pluralize;
use util::ppaux; use util::ppaux;
use util::ppaux::UserString;
use std::result;
use std::vec; use std::vec;
use syntax::abi::AbiSet; use syntax::abi::AbiSet;
use syntax::ast::{RegionTyParamBound, TraitTyParamBound}; use syntax::ast::{RegionTyParamBound, TraitTyParamBound};
@ -56,10 +51,9 @@ use syntax::ast_map;
use syntax::ast_util::{local_def, split_trait_methods}; use syntax::ast_util::{local_def, split_trait_methods};
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::codemap; 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::visit;
use syntax::opt_vec::OptVec; use syntax::opt_vec::OptVec;
use syntax::opt_vec;
use syntax::parse::token::special_idents; use syntax::parse::token::special_idents;
struct CollectItemTypesVisitor { struct CollectItemTypesVisitor {
@ -97,19 +91,11 @@ pub fn collect_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) {
} }
pub trait ToTy { pub trait ToTy {
fn to_ty<RS:RegionScope + Clone + 'static>( fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t;
&self,
rs: &RS,
ast_ty: &ast::Ty)
-> ty::t;
} }
impl ToTy for CrateCtxt { impl ToTy for CrateCtxt {
fn to_ty<RS:RegionScope + Clone + 'static>( fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t {
&self,
rs: &RS,
ast_ty: &ast::Ty)
-> ty::t {
ast_ty_to_ty(self, rs, ast_ty) ast_ty_to_ty(self, rs, ast_ty)
} }
} }
@ -149,59 +135,45 @@ impl AstConv for CrateCtxt {
pub fn get_enum_variant_types(ccx: &CrateCtxt, pub fn get_enum_variant_types(ccx: &CrateCtxt,
enum_ty: ty::t, enum_ty: ty::t,
variants: &[ast::variant], variants: &[ast::variant],
generics: &ast::Generics, generics: &ast::Generics) {
rp: Option<ty::region_variance>) {
let tcx = ccx.tcx; let tcx = ccx.tcx;
// Create a set of parameter types shared among all the variants. // Create a set of parameter types shared among all the variants.
for variant in variants.iter() { 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 // Nullary enum constructors get turned into constants; n-ary enum
// constructors get turned into functions. // constructors get turned into functions.
let result_ty; let scope = variant.node.id;
match variant.node.kind { let result_ty = match variant.node.kind {
ast::tuple_variant_kind(ref args) if args.len() > 0 => { 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)); 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(_) => { ast::tuple_variant_kind(_) => {
result_ty = Some(enum_ty); enum_ty
} }
ast::struct_variant_kind(struct_def) => { ast::struct_variant_kind(struct_def) => {
let tpt = ty_param_bounds_and_ty { let tpt = ty_param_bounds_and_ty {
generics: ty_generics(ccx, rp, generics, 0), generics: ty_generics(ccx, generics, 0),
ty: enum_ty ty: enum_ty
}; };
convert_struct(ccx, convert_struct(ccx, struct_def, tpt, variant.node.id);
rp,
struct_def,
generics,
tpt,
variant.node.id);
let input_tys = struct_def.fields.map( let input_tys = struct_def.fields.map(
|f| ty::node_id_to_type(ccx.tcx, f.node.id)); |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 { let tpt = ty_param_bounds_and_ty {
None => {} generics: ty_generics(ccx, generics, 0),
Some(result_ty) => { ty: result_ty
let tpt = ty_param_bounds_and_ty { };
generics: ty_generics(ccx, rp, generics, 0), tcx.tcache.insert(local_def(variant.node.id), tpt);
ty: result_ty write_ty_to_tcx(tcx, variant.node.id, 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) trait_id: ast::NodeId)
{ {
let tcx = ccx.tcx; let tcx = ccx.tcx;
let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|x| *x);
match tcx.items.get_copy(&trait_id) { match tcx.items.get_copy(&trait_id) {
ast_map::node_item(@ast::item { ast_map::node_item(@ast::item {
node: ast::item_trait(ref generics, _, ref ms), 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 // For each method, construct a suitable ty::Method and
// store it into the `tcx.methods` table: // store it into the `tcx.methods` table:
@ -223,14 +195,14 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
let ty_method = @match m { let ty_method = @match m {
&ast::required(ref m) => { &ast::required(ref m) => {
ty_method_of_trait_method( 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.id, &m.ident, &m.explicit_self,
&m.generics, &m.purity, &m.decl) &m.generics, &m.purity, &m.decl)
} }
&ast::provided(ref m) => { &ast::provided(ref m) => {
ty_method_of_trait_method( 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.id, &m.ident, &m.explicit_self,
&m.generics, &m.purity, &m.decl) &m.generics, &m.purity, &m.decl)
} }
@ -264,13 +236,13 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
trait_ty_generics: &ty::Generics) { trait_ty_generics: &ty::Generics) {
// If declaration is // If declaration is
// //
// trait<A,B,C> { // trait<'a,'b,'c,A,B,C> {
// fn foo<D,E,F>(...) -> Self; // fn foo<'d,'e,'f,D,E,F>(...) -> Self;
// } // }
// //
// and we will create a function like // and we will create a function like
// //
// fn foo<A',B',C',D',E',F',G'>(...) -> 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 // Note that `Self` is replaced with an explicit type
// parameter D' that is sandwiched in between the trait params // 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) 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 // build up the substitution from
// A,B,C => A',B',C' // A,B,C => A',B',C'
// Self => D' // Self => D'
// D,E,F => E',F',G' // D,E,F => E',F',G'
let substs = substs { let substs = substs {
regions: ty::NonerasedRegions(opt_vec::Empty), regions: ty::NonerasedRegions(rps_from_trait),
self_ty: Some(self_param), self_ty: Some(self_param),
tps: non_shifted_trait_tps + shifted_method_tps tps: non_shifted_trait_tps + shifted_method_tps
}; };
@ -357,7 +336,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
ty_param_bounds_and_ty { ty_param_bounds_and_ty {
generics: ty::Generics { generics: ty::Generics {
type_param_defs: @new_type_param_defs, type_param_defs: @new_type_param_defs,
region_param: trait_ty_generics.region_param region_param_defs: @[], // fn items
}, },
ty: ty ty: ty
}); });
@ -365,8 +344,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
fn ty_method_of_trait_method(this: &CrateCtxt, fn ty_method_of_trait_method(this: &CrateCtxt,
trait_id: ast::NodeId, trait_id: ast::NodeId,
trait_rp: Option<ty::region_variance>, trait_generics: &ty::Generics,
trait_generics: &ast::Generics,
m_id: &ast::NodeId, m_id: &ast::NodeId,
m_ident: &ast::Ident, m_ident: &ast::Ident,
m_explicit_self: &ast::explicit_self, m_explicit_self: &ast::explicit_self,
@ -375,14 +353,14 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
m_decl: &ast::fn_decl) -> ty::Method m_decl: &ast::fn_decl) -> ty::Method
{ {
let trait_self_ty = ty::mk_self(this.tcx, local_def(trait_id)); 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) = 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); 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( ty::Method::new(
*m_ident, *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, transformed_self_ty,
fty, fty,
m_explicit_self.node, m_explicit_self.node,
@ -398,9 +376,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
pub fn ensure_supertraits(ccx: &CrateCtxt, pub fn ensure_supertraits(ccx: &CrateCtxt,
id: ast::NodeId, id: ast::NodeId,
sp: codemap::Span, sp: codemap::Span,
rp: Option<ty::region_variance>, ast_trait_refs: &[ast::trait_ref])
ast_trait_refs: &[ast::trait_ref], -> ty::BuiltinBounds
generics: &ast::Generics) -> ty::BuiltinBounds
{ {
let tcx = ccx.tcx; 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 // 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 // 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. // 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, let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, self_ty);
generics, self_ty);
if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) { if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) {
// FIXME(#5527) Could have same trait multiple times // FIXME(#5527) Could have same trait multiple times
@ -720,91 +696,68 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt,
} // fn } // fn
pub fn convert_field(ccx: &CrateCtxt, pub fn convert_field(ccx: &CrateCtxt,
rp: Option<ty::region_variance>, struct_generics: &ty::Generics,
type_param_defs: @~[ty::TypeParameterDef], v: &ast::struct_field) {
v: &ast::struct_field, let tt = ccx.to_ty(&ExplicitRscope, &v.node.ty);
generics: &ast::Generics) {
let region_parameterization =
RegionParameterization::from_variance_and_generics(rp, generics);
let tt = ccx.to_ty(&TypeRscope(region_parameterization), &v.node.ty);
write_ty_to_tcx(ccx.tcx, v.node.id, tt); write_ty_to_tcx(ccx.tcx, v.node.id, tt);
/* add the field to the tcache */ /* add the field to the tcache */
ccx.tcx.tcache.insert(local_def(v.node.id), ccx.tcx.tcache.insert(local_def(v.node.id),
ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty {
generics: ty::Generics { generics: struct_generics.clone(),
type_param_defs: type_param_defs,
region_param: rp
},
ty: tt ty: tt
}); });
} }
pub struct ConvertedMethod { fn convert_methods(ccx: &CrateCtxt,
mty: @ty::Method, container: MethodContainer,
id: ast::NodeId, ms: &[@ast::method],
span: Span, untransformed_rcvr_ty: ty::t,
body_id: ast::NodeId rcvr_ty_generics: &ty::Generics,
} rcvr_ast_generics: &ast::Generics,
rcvr_visibility: ast::visibility)
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]
{ {
let tcx = ccx.tcx; 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 num_rcvr_ty_params = rcvr_ty_generics.type_param_defs.len();
let m_ty_generics = let m_ty_generics = ty_generics(ccx, &m.generics, num_rcvr_ty_params);
ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics,
num_rcvr_ty_params);
let mty = @ty_of_method(ccx, let mty = @ty_of_method(ccx,
container, container,
*m, *m,
rcvr_ty_generics.region_param,
untransformed_rcvr_ty, untransformed_rcvr_ty,
rcvr_ast_generics, rcvr_ast_generics,
rcvr_visibility, rcvr_visibility);
&m.generics);
let fty = ty::mk_bare_fn(tcx, mty.fty.clone()); 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( tcx.tcache.insert(
local_def(m.id), local_def(m.id),
// n.b.: the type of a method is parameterized by both // 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 { ty_param_bounds_and_ty {
generics: ty::Generics { generics: ty::Generics {
type_param_defs: @vec::append( type_param_defs: @vec::append(
(*rcvr_ty_generics.type_param_defs).clone(), (*rcvr_ty_generics.type_param_defs).clone(),
*m_ty_generics.type_param_defs), *m_ty_generics.type_param_defs),
region_param: rcvr_ty_generics.region_param region_param_defs: rcvr_ty_generics.region_param_defs,
}, },
ty: fty ty: fty
}); });
write_ty_to_tcx(tcx, m.id, fty); write_ty_to_tcx(tcx, m.id, fty);
tcx.methods.insert(mty.def_id, mty); 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, fn ty_of_method(ccx: &CrateCtxt,
container: MethodContainer, container: MethodContainer,
m: &ast::method, m: &ast::method,
rp: Option<ty::region_variance>,
untransformed_rcvr_ty: ty::t, untransformed_rcvr_ty: ty::t,
rcvr_generics: &ast::Generics, rcvr_generics: &ast::Generics,
rcvr_visibility: ast::visibility, rcvr_visibility: ast::visibility) -> ty::Method
method_generics: &ast::Generics) -> ty::Method
{ {
let rscope = MethodRscope::new(m.explicit_self.node,
rp,
rcvr_generics);
let (transformed_self_ty, fty) = let (transformed_self_ty, fty) =
astconv::ty_of_method(ccx, &rscope, m.purity, astconv::ty_of_method(ccx, m.id, m.purity,
&method_generics.lifetimes,
untransformed_rcvr_ty, untransformed_rcvr_ty,
m.explicit_self, &m.decl); 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(); let num_rcvr_type_params = rcvr_generics.ty_params.len();
ty::Method::new( ty::Method::new(
m.ident, 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, transformed_self_ty,
fty, fty,
m.explicit_self.node, 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) { pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
let tcx = ccx.tcx; let tcx = ccx.tcx;
let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x); debug!("convert: item {} with id {}", tcx.sess.str_of(it.ident), it.id);
debug!("convert: item {} with id {} rp {:?}",
tcx.sess.str_of(it.ident), it.id, rp);
match it.node { match it.node {
// These don't define types. // These don't define types.
ast::item_foreign_mod(_) | ast::item_mod(_) => {} ast::item_foreign_mod(_) | ast::item_mod(_) => {}
ast::item_enum(ref enum_definition, ref generics) => { ast::item_enum(ref enum_definition, ref generics) => {
ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration"); ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration");
let tpt = ty_of_item(ccx, it); let tpt = ty_of_item(ccx, it);
write_ty_to_tcx(tcx, it.id, tpt.ty); write_ty_to_tcx(tcx, it.id, tpt.ty);
get_enum_variant_types(ccx, get_enum_variant_types(ccx,
tpt.ty, tpt.ty,
enum_definition.variants, enum_definition.variants,
generics, generics);
rp); }
}
ast::item_impl(ref generics, ref opt_trait_ref, ref selfty, ref ms) => { ast::item_impl(ref generics, ref opt_trait_ref, ref selfty, ref ms) => {
let i_ty_generics = ty_generics(ccx, rp, generics, 0); let i_ty_generics = ty_generics(ccx, generics, 0);
let region_parameterization = let selfty = ccx.to_ty(&ExplicitRscope, selfty);
RegionParameterization::from_variance_and_generics(rp, generics);
let selfty = ccx.to_ty(&TypeRscope(region_parameterization), selfty);
write_ty_to_tcx(tcx, it.id, selfty); write_ty_to_tcx(tcx, it.id, selfty);
tcx.tcache.insert(local_def(it.id), tcx.tcache.insert(local_def(it.id),
ty_param_bounds_and_ty { ty_param_bounds_and_ty {
@ -883,17 +832,19 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
it.vis it.vis
}; };
let cms = convert_methods(ccx, convert_methods(ccx,
ImplContainer(local_def(it.id)), ImplContainer(local_def(it.id)),
*ms, *ms,
selfty, selfty,
&i_ty_generics, &i_ty_generics,
generics, generics,
parent_visibility); parent_visibility);
for t in opt_trait_ref.iter() {
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. // 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_ref.def_id).is_some() {
if tcx.lang_items.to_builtin_kind(trait_def_id).is_some() {
tcx.sess.span_err(it.span, tcx.sess.span_err(it.span,
"cannot provide an explicit implementation \ "cannot provide an explicit implementation \
for a builtin kind"); for a builtin kind");
@ -903,21 +854,19 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
} }
} }
ast::item_trait(ref generics, _, ref trait_methods) => { 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. // Run convert_methods on the provided methods.
let (_, provided_methods) = let (_, provided_methods) =
split_trait_methods(*trait_methods); split_trait_methods(*trait_methods);
let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id)); let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id));
let (ty_generics, _) = mk_item_substs(ccx, generics, rp, convert_methods(ccx,
Some(untransformed_rcvr_ty)); TraitContainer(local_def(it.id)),
let _ = convert_methods(ccx, provided_methods,
TraitContainer(local_def(it.id)), untransformed_rcvr_ty,
provided_methods, &trait_def.generics,
untransformed_rcvr_ty, generics,
&ty_generics, it.vis);
generics,
it.vis);
// We need to do this *after* converting methods, since // We need to do this *after* converting methods, since
// convert_methods produces a tcache entry that is wrong for // 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); write_ty_to_tcx(tcx, it.id, tpt.ty);
tcx.tcache.insert(local_def(it.id), tpt); 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) => { ast::item_ty(_, ref generics) => {
ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); 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, pub fn convert_struct(ccx: &CrateCtxt,
rp: Option<ty::region_variance>,
struct_def: &ast::struct_def, struct_def: &ast::struct_def,
generics: &ast::Generics,
tpt: ty::ty_param_bounds_and_ty, tpt: ty::ty_param_bounds_and_ty,
id: ast::NodeId) { id: ast::NodeId) {
let tcx = ccx.tcx; let tcx = ccx.tcx;
// Write the type of each of the members // Write the type of each of the members
for f in struct_def.fields.iter() { 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); let selfty = ty::mk_struct(tcx, local_def(id), substs);
// If this struct is enum-like or tuple-like, create the type of its // 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( struct_def.fields.map(
|field| ccx.tcx.tcache.get( |field| ccx.tcx.tcache.get(
&local_def(field.node.id)).ty); &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); write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty);
tcx.tcache.insert(local_def(ctor_id), ty_param_bounds_and_ty { tcx.tcache.insert(local_def(ctor_id), ty_param_bounds_and_ty {
generics: tpt.generics, generics: tpt.generics,
@ -1014,8 +961,6 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::foreign_item) {
pub fn instantiate_trait_ref(ccx: &CrateCtxt, pub fn instantiate_trait_ref(ccx: &CrateCtxt,
ast_trait_ref: &ast::trait_ref, ast_trait_ref: &ast::trait_ref,
rp: Option<ty::region_variance>,
generics: &ast::Generics,
self_ty: ty::t) -> @ty::TraitRef 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. * trait. Fails if the type is a type other than an trait type.
*/ */
let rp = RegionParameterization::from_variance_and_generics(rp, generics); let rscope = ExplicitRscope; // FIXME
let rscope = TypeRscope(rp);
match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) { match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) {
ast::DefTrait(trait_did) => { 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, Some(&def) => return def,
_ => {} _ => {}
} }
let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x);
match it.node { match it.node {
ast::item_trait(ref generics, ref supertraits, _) => { ast::item_trait(ref generics, ref supertraits, _) => {
let self_ty = ty::mk_self(tcx, def_id); let self_ty = ty::mk_self(tcx, def_id);
let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, let ty_generics = ty_generics(ccx, generics, 0);
Some(self_ty)); let substs = mk_item_substs(ccx, &ty_generics, Some(self_ty));
let bounds = ensure_supertraits(ccx, it.id, it.span, rp, let bounds = ensure_supertraits(ccx, it.id, it.span, *supertraits);
*supertraits, generics);
let trait_ref = @ty::TraitRef {def_id: def_id, let trait_ref = @ty::TraitRef {def_id: def_id,
substs: substs}; substs: substs};
let trait_def = @ty::TraitDef {generics: ty_generics, 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) 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 def_id = local_def(it.id);
let tcx = ccx.tcx; let tcx = ccx.tcx;
match tcx.tcache.find(&def_id) { 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 { match it.node {
ast::item_static(ref t, _, _) => { ast::item_static(ref t, _, _) => {
let typ = ccx.to_ty(&EmptyRscope, t); let typ = ccx.to_ty(&ExplicitRscope, t);
let tpt = no_params(typ); let tpt = no_params(typ);
tcx.tcache.insert(local_def(it.id), tpt); tcx.tcache.insert(local_def(it.id), tpt);
return 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_fn(ref decl, purity, abi, ref generics, _) => {
let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x); let ty_generics = ty_generics(ccx, generics, 0);
let region_parameterization = let tofd = astconv::ty_of_bare_fn(ccx,
RegionParameterization::from_variance_and_generics(rp, generics); it.id,
let tpt = { purity,
let ty = ccx.to_ty(&TypeRscope(region_parameterization), t); abi,
ty_param_bounds_and_ty { decl);
generics: ty_generics(ccx, rp, generics, 0), let tpt = ty_param_bounds_and_ty {
ty: 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); let tpt = {
return tpt; let ty = ccx.to_ty(&ExplicitRscope, t);
} ty_param_bounds_and_ty {
ast::item_enum(_, ref generics) => { generics: ty_generics(ccx, generics, 0),
// Create a new generic polytype. ty: ty
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, tcx.tcache.insert(local_def(it.id), tpt);
ty: t return tpt;
}; }
tcx.tcache.insert(local_def(it.id), tpt); ast::item_enum(_, ref generics) => {
return tpt; // Create a new generic polytype.
} let ty_generics = ty_generics(ccx, generics, 0);
ast::item_trait(*) => { let substs = mk_item_substs(ccx, &ty_generics, None);
tcx.sess.span_bug( let t = ty::mk_enum(tcx, local_def(it.id), substs);
it.span, let tpt = ty_param_bounds_and_ty {
format!("Invoked ty_of_item on trait")); generics: ty_generics,
} ty: t
ast::item_struct(_, ref generics) => { };
let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None); tcx.tcache.insert(local_def(it.id), tpt);
let t = ty::mk_struct(tcx, local_def(it.id), substs); return tpt;
let tpt = ty_param_bounds_and_ty { }
generics: ty_generics, ast::item_trait(*) => {
ty: t tcx.sess.span_bug(
}; it.span,
tcx.tcache.insert(local_def(it.id), tpt); format!("Invoked ty_of_item on trait"));
return tpt; }
} ast::item_struct(_, ref generics) => {
ast::item_impl(*) | ast::item_mod(_) | let ty_generics = ty_generics(ccx, generics, 0);
ast::item_foreign_mod(_) => fail!(), let substs = mk_item_substs(ccx, &ty_generics, None);
ast::item_mac(*) => fail!("item macros unimplemented") 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 { ty::ty_param_bounds_and_ty {
generics: ty::Generics { generics: ty::Generics {
type_param_defs: @~[], 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, pub fn ty_generics(ccx: &CrateCtxt,
rp: Option<ty::region_variance>,
generics: &ast::Generics, generics: &ast::Generics,
base_index: uint) -> ty::Generics { base_index: uint) -> ty::Generics {
return 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| { type_param_defs: @generics.ty_params.mapi_to_vec(|offset, param| {
match ccx.tcx.ty_param_defs.find(&param.id) { match ccx.tcx.ty_param_defs.find(&param.id) {
Some(&def) => def, Some(&def) => def,
None => { None => {
let param_ty = ty::param_ty {idx: base_index + offset, let param_ty = ty::param_ty {idx: base_index + offset,
def_id: local_def(param.id)}; def_id: local_def(param.id)};
let bounds = @compute_bounds(ccx, rp, generics, let bounds = @compute_bounds(ccx, param_ty, &param.bounds);
param_ty, &param.bounds);
let def = ty::TypeParameterDef { let def = ty::TypeParameterDef {
ident: param.ident, ident: param.ident,
def_id: local_def(param.id), def_id: local_def(param.id),
@ -1234,13 +1172,10 @@ pub fn ty_generics(ccx: &CrateCtxt,
fn compute_bounds( fn compute_bounds(
ccx: &CrateCtxt, ccx: &CrateCtxt,
rp: Option<ty::region_variance>,
generics: &ast::Generics,
param_ty: ty::param_ty, param_ty: ty::param_ty,
ast_bounds: &OptVec<ast::TyParamBound>) -> ty::ParamBounds ast_bounds: &OptVec<ast::TyParamBound>) -> ty::ParamBounds
{ {
/*! /*!
*
* Translate the AST's notion of ty param bounds (which are an * Translate the AST's notion of ty param bounds (which are an
* enum consisting of a newtyped Ty or a region) to ty's * enum consisting of a newtyped Ty or a region) to ty's
* notion of ty param bounds, which can either be user-defined * notion of ty param bounds, which can either be user-defined
@ -1256,7 +1191,7 @@ pub fn ty_generics(ccx: &CrateCtxt,
match *ast_bound { match *ast_bound {
TraitTyParamBound(ref b) => { TraitTyParamBound(ref b) => {
let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id); 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( if !ty::try_add_builtin_trait(
ccx.tcx, trait_ref.def_id, ccx.tcx, trait_ref.def_id,
&mut param_bounds.builtin_bounds) &mut param_bounds.builtin_bounds)
@ -1282,9 +1217,8 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
ast_generics: &ast::Generics, ast_generics: &ast::Generics,
abis: AbiSet) abis: AbiSet)
-> ty::ty_param_bounds_and_ty { -> ty::ty_param_bounds_and_ty {
let ty_generics = ty_generics(ccx, None, ast_generics, 0); let ty_generics = ty_generics(ccx, ast_generics, 0);
let region_param_names = RegionParamNames::from_generics(ast_generics); let rb = BindingRscope::new(def_id.node);
let rb = in_binding_rscope(&EmptyRscope, region_param_names);
let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, &rb, a, None) ); 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); 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 { ty::BareFnTy {
abis: abis, abis: abis,
purity: ast::unsafe_fn, purity: ast::unsafe_fn,
sig: ty::FnSig { sig: ty::FnSig {binder_id: def_id.node,
bound_lifetime_names: opt_vec::Empty, inputs: input_tys,
inputs: input_tys, output: output_ty,
output: output_ty, variadic: decl.variadic}
variadic: decl.variadic
}
}); });
let tpt = ty_param_bounds_and_ty { let tpt = ty_param_bounds_and_ty {
generics: ty_generics, generics: ty_generics,
@ -1309,19 +1241,18 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
} }
pub fn mk_item_substs(ccx: &CrateCtxt, pub fn mk_item_substs(ccx: &CrateCtxt,
ast_generics: &ast::Generics, ty_generics: &ty::Generics,
rp: Option<ty::region_variance>, self_ty: Option<ty::t>) -> ty::substs
self_ty: Option<ty::t>) -> (ty::Generics, ty::substs)
{ {
let mut i = 0; let params: ~[ty::t] =
let ty_generics = ty_generics(ccx, rp, ast_generics, 0); ty_generics.type_param_defs.iter().enumerate().map(
let params = ast_generics.ty_params.map_to_vec(|atp| { |(i, t)| ty::mk_param(ccx.tcx, i, t.def_id)).collect();
let t = ty::mk_param(ccx.tcx, i, local_def(atp.id));
i += 1u; let regions: OptVec<ty::Region> =
t ty_generics.region_param_defs.iter().enumerate().map(
}); |(i, l)| ty::re_type_bound(l.def_id.node, i, l.ident)).collect();
let regions = rscope::bound_self_region(rp);
(ty_generics, substs {regions: ty::NonerasedRegions(regions), substs {regions: ty::NonerasedRegions(regions),
self_ty: self_ty, self_ty: self_ty,
tps: params}) tps: params}
} }

View file

@ -429,23 +429,20 @@ pub fn super_fn_sigs<C:Combine>(this: &C, a: &ty::FnSig, b: &ty::FnSig) -> cres<
return Err(ty::terr_variadic_mismatch(expected_found(this, a.variadic, b.variadic))); return Err(ty::terr_variadic_mismatch(expected_found(this, a.variadic, b.variadic)));
} }
do argvecs(this, a.inputs, b.inputs) let inputs = if_ok!(argvecs(this, a.inputs, b.inputs));
.and_then |inputs| { let output = if_ok!(this.tys(a.output, b.output));
do this.tys(a.output, b.output).and_then |output| { Ok(FnSig {binder_id: a.binder_id,
Ok(FnSig { inputs: inputs,
bound_lifetime_names: opt_vec::Empty, // FIXME(#4846) output: output,
inputs: inputs.clone(), variadic: a.variadic})
output: output,
variadic: a.variadic
})
}
}
} }
pub fn super_tys<C:Combine>( pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
let tcx = this.infcx().tcx; 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: // The "subtype" ought to be handling cases involving bot or var:
(&ty::ty_bot, _) | (&ty::ty_bot, _) |
(_, &ty::ty_bot) | (_, &ty::ty_bot) |
@ -494,6 +491,7 @@ pub fn super_tys<C:Combine>(
unify_float_variable(this, !this.a_is_expected(), v_id, v) unify_float_variable(this, !this.a_is_expected(), v_id, v)
} }
(&ty::ty_char, _) |
(&ty::ty_nil, _) | (&ty::ty_nil, _) |
(&ty::ty_bool, _) | (&ty::ty_bool, _) |
(&ty::ty_int(_), _) | (&ty::ty_int(_), _) |

View file

@ -20,15 +20,13 @@ use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt}; use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::{TypeTrace, Subtype}; use middle::typeck::infer::{TypeTrace, Subtype};
use middle::typeck::infer::fold_regions_in_sig; 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::{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 syntax::ast::{Onceness, purity};
use std::hashmap::HashMap;
use util::common::{indenter}; use util::common::{indenter};
use util::ppaux::mt_to_str; use util::ppaux::mt_to_str;
use extra::list;
pub struct Glb(CombineFields); // "greatest lower bound" (common subtype) pub struct Glb(CombineFields); // "greatest lower bound" (common subtype)
impl Combine for Glb { impl Combine for Glb {
@ -132,14 +130,14 @@ impl Combine for Glb {
let snapshot = self.infcx.region_vars.start_snapshot(); let snapshot = self.infcx.region_vars.start_snapshot();
// Instantiate each bound region with a fresh region variable. // 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.infcx.replace_bound_regions_with_fresh_regions(
self.trace, a); self.trace, a);
let a_vars = var_ids(self, a_isr); let a_vars = var_ids(self, &a_map);
let (b_with_fresh, b_isr) = let (b_with_fresh, b_map) =
self.infcx.replace_bound_regions_with_fresh_regions( self.infcx.replace_bound_regions_with_fresh_regions(
self.trace, b); self.trace, b);
let b_vars = var_ids(self, b_isr); let b_vars = var_ids(self, &b_map);
// Collect constraints. // Collect constraints.
let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh)); 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( fold_regions_in_sig(
self.infcx.tcx, self.infcx.tcx,
&sig0, &sig0,
|r, _in_fn| generalize_region(self, snapshot, |r| generalize_region(self, snapshot,
new_vars, a_isr, a_vars, b_vars, new_vars, sig0.binder_id,
r)); &a_map, a_vars, b_vars,
r));
debug!("sig1 = {}", sig1.inf_str(self.infcx)); debug!("sig1 = {}", sig1.inf_str(self.infcx));
return Ok(sig1); return Ok(sig1);
fn generalize_region(this: &Glb, fn generalize_region(this: &Glb,
snapshot: uint, snapshot: uint,
new_vars: &[RegionVid], new_vars: &[RegionVid],
a_isr: isr_alist, new_binder_id: NodeId,
a_map: &HashMap<ty::bound_region, ty::Region>,
a_vars: &[RegionVid], a_vars: &[RegionVid],
b_vars: &[RegionVid], b_vars: &[RegionVid],
r0: ty::Region) -> ty::Region { r0: ty::Region) -> ty::Region {
if !is_var_in_set(new_vars, r0) { if !is_var_in_set(new_vars, r0) {
assert!(!r0.is_bound());
return r0; return r0;
} }
@ -177,13 +178,13 @@ impl Combine for Glb {
for r in tainted.iter() { for r in tainted.iter() {
if is_var_in_set(a_vars, *r) { if is_var_in_set(a_vars, *r) {
if a_r.is_some() { if a_r.is_some() {
return fresh_bound_variable(this); return fresh_bound_variable(this, new_binder_id);
} else { } else {
a_r = Some(*r); a_r = Some(*r);
} }
} else if is_var_in_set(b_vars, *r) { } else if is_var_in_set(b_vars, *r) {
if b_r.is_some() { if b_r.is_some() {
return fresh_bound_variable(this); return fresh_bound_variable(this, new_binder_id);
} else { } else {
b_r = Some(*r); b_r = Some(*r);
} }
@ -192,57 +193,57 @@ impl Combine for Glb {
} }
} }
// NB---I do not believe this algorithm computes // NB---I do not believe this algorithm computes
// (necessarily) the GLB. As written it can // (necessarily) the GLB. As written it can
// spuriously fail. In particular, if there is a case // spuriously fail. In particular, if there is a case
// like: &fn(fn(&a)) and fn(fn(&b)), where a and b are // 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 // free, it will return fn(&c) where c = GLB(a,b). If
// however this GLB is not defined, then the result is // however this GLB is not defined, then the result is
// an error, even though something like // an error, even though something like
// "fn<X>(fn(&X))" where X is bound would be a // "fn<X>(fn(&X))" where X is bound would be a
// subtype of both of those. // subtype of both of those.
// //
// The problem is that if we were to return a bound // The problem is that if we were to return a bound
// variable, we'd be computing a lower-bound, but not // variable, we'd be computing a lower-bound, but not
// necessarily the *greatest* lower-bound. // 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 { if a_r.is_some() && b_r.is_some() && only_new_vars {
// Related to exactly one bound variable from each fn: // 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() { } else if a_r.is_none() && b_r.is_none() {
// Not related to bound variables from either fn: // Not related to bound variables from either fn:
assert!(!r0.is_bound());
return r0; return r0;
} else { } else {
// Other: // Other:
return fresh_bound_variable(this); return fresh_bound_variable(this, new_binder_id);
} }
} }
fn rev_lookup(this: &Glb, fn rev_lookup(this: &Glb,
a_isr: isr_alist, a_map: &HashMap<ty::bound_region, ty::Region>,
new_binder_id: NodeId,
r: ty::Region) -> ty::Region r: ty::Region) -> ty::Region
{ {
let mut ret = None; for (a_br, a_r) in a_map.iter() {
do list::each(a_isr) |pair| { if *a_r == r {
let (a_br, a_r) = *pair; return ty::re_fn_bound(new_binder_id, *a_br);
if a_r == r {
ret = Some(ty::re_bound(a_br));
false
} else {
true
} }
};
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 { fn fresh_bound_variable(this: &Glb, binder_id: NodeId) -> ty::Region {
this.infcx.region_vars.new_bound() this.infcx.region_vars.new_bound(binder_id)
} }
} }
} }

View file

@ -35,7 +35,6 @@
use middle::ty::{RegionVid, TyVar, Vid}; use middle::ty::{RegionVid, TyVar, Vid};
use middle::ty; use middle::ty;
use middle::typeck::isr_alist;
use middle::typeck::infer::*; use middle::typeck::infer::*;
use middle::typeck::infer::combine::*; use middle::typeck::infer::combine::*;
use middle::typeck::infer::glb::Glb; 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::unify::*;
use middle::typeck::infer::sub::Sub; use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::to_str::InferStr;
use std::hashmap::HashMap;
use util::common::indenter; use util::common::indenter;
use extra::list;
pub trait LatticeValue { pub trait LatticeValue {
fn sub(cf: &CombineFields, a: &Self, b: &Self) -> ures; fn sub(cf: &CombineFields, a: &Self, b: &Self) -> ures;
fn lub(cf: &CombineFields, a: &Self, b: &Self) -> cres<Self>; fn lub(cf: &CombineFields, a: &Self, b: &Self) -> cres<Self>;
@ -366,14 +364,13 @@ impl TyLatticeDir for Glb {
} }
} }
pub fn super_lattice_tys<L:LatticeDir + TyLatticeDir + Combine>( pub fn super_lattice_tys<L:LatticeDir+TyLatticeDir+Combine>(this: &L,
this: &L, a: ty::t,
a: ty::t, b: ty::t)
b: ty::t) -> cres<ty::t> { -> cres<ty::t> {
debug!("{}.lattice_tys({}, {})", this.tag(), debug!("{}.lattice_tys({}, {})", this.tag(),
a.inf_str(this.infcx()), a.inf_str(this.infcx()),
b.inf_str(this.infcx())); b.inf_str(this.infcx()));
let _r = indenter();
if a == b { if a == b {
return Ok(a); return Ok(a);
@ -524,20 +521,17 @@ pub fn lattice_var_and_t<L:LatticeDir + Combine,
// Random utility functions used by LUB/GLB when computing LUB/GLB of // Random utility functions used by LUB/GLB when computing LUB/GLB of
// fn types // fn types
pub fn var_ids<T:Combine>(this: &T, isr: isr_alist) -> ~[RegionVid] { pub fn var_ids<T:Combine>(this: &T,
let mut result = ~[]; map: &HashMap<ty::bound_region, ty::Region>)
do list::each(isr) |pair| { -> ~[RegionVid] {
match pair.second() { map.iter().map(|(_, r)| match *r {
ty::re_infer(ty::ReVar(r)) => { result.push(r); } ty::re_infer(ty::ReVar(r)) => { r }
r => { r => {
this.infcx().tcx.sess.span_bug( this.infcx().tcx.sess.span_bug(
this.trace().origin.span(), this.trace().origin.span(),
format!("Found non-region-vid: {:?}", r)); format!("Found non-region-vid: {:?}", r));
} }
} }).collect()
true
};
result
} }
pub fn is_var_in_set(new_vars: &[RegionVid], r: ty::Region) -> bool { pub fn is_var_in_set(new_vars: &[RegionVid], r: ty::Region) -> bool {

View file

@ -20,13 +20,11 @@ use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt}; use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::fold_regions_in_sig; use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::infer::{TypeTrace, Subtype}; use middle::typeck::infer::{TypeTrace, Subtype};
use middle::typeck::isr_alist; use std::hashmap::HashMap;
use util::ppaux::mt_to_str; use syntax::ast::{Many, Once, extern_fn, impure_fn, NodeId};
use extra::list;
use syntax::ast::{Many, Once, extern_fn, impure_fn};
use syntax::ast::{unsafe_fn}; use syntax::ast::{unsafe_fn};
use syntax::ast::{Onceness, purity}; use syntax::ast::{Onceness, purity};
use util::ppaux::mt_to_str;
pub struct Lub(CombineFields); // least-upper-bound: common supertype 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(); let snapshot = self.infcx.region_vars.start_snapshot();
// Instantiate each bound region with a fresh region variable. // 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.infcx.replace_bound_regions_with_fresh_regions(
self.trace, a); self.trace, a);
let (b_with_fresh, _) = let (b_with_fresh, _) =
@ -143,17 +141,20 @@ impl Combine for Lub {
fold_regions_in_sig( fold_regions_in_sig(
self.infcx.tcx, self.infcx.tcx,
&sig0, &sig0,
|r, _in_fn| generalize_region(self, snapshot, new_vars, |r| generalize_region(self, snapshot, new_vars,
a_isr, r)); sig0.binder_id, &a_map, r));
return Ok(sig1); return Ok(sig1);
fn generalize_region(this: &Lub, fn generalize_region(this: &Lub,
snapshot: uint, snapshot: uint,
new_vars: &[RegionVid], new_vars: &[RegionVid],
a_isr: isr_alist, new_scope: NodeId,
r0: ty::Region) -> ty::Region { a_map: &HashMap<ty::bound_region, ty::Region>,
r0: ty::Region)
-> ty::Region {
// Regions that pre-dated the LUB computation stay as they are. // Regions that pre-dated the LUB computation stay as they are.
if !is_var_in_set(new_vars, r0) { if !is_var_in_set(new_vars, r0) {
assert!(!r0.is_bound());
debug!("generalize_region(r0={:?}): not new variable", r0); debug!("generalize_region(r0={:?}): not new variable", r0);
return r0; return r0;
} }
@ -167,6 +168,7 @@ impl Combine for Lub {
debug!("generalize_region(r0={:?}): \ debug!("generalize_region(r0={:?}): \
non-new-variables found in {:?}", non-new-variables found in {:?}",
r0, tainted); r0, tainted);
assert!(!r0.is_bound());
return r0; return r0;
} }
@ -175,27 +177,19 @@ impl Combine for Lub {
// in both A and B. Replace the variable with the "first" // in both A and B. Replace the variable with the "first"
// bound region from A that we find it to be associated // bound region from A that we find it to be associated
// with. // with.
let mut ret = None; for (a_br, a_r) in a_map.iter() {
do list::each(a_isr) |pair| { if tainted.iter().any(|x| x == a_r) {
let (a_br, a_r) = *pair;
if tainted.iter().any(|x| x == &a_r) {
debug!("generalize_region(r0={:?}): \ debug!("generalize_region(r0={:?}): \
replacing with {:?}, tainted={:?}", replacing with {:?}, tainted={:?}",
r0, a_br, tainted); r0, *a_br, tainted);
ret = Some(ty::re_bound(a_br)); return ty::re_fn_bound(new_scope, *a_br);
false
} else {
true
} }
};
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))
} }
} }

View file

@ -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_nested_tvar};
pub use middle::typeck::infer::resolve::{resolve_rvar}; pub use middle::typeck::infer::resolve::{resolve_rvar};
use extra::smallintmap::SmallIntMap;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid}; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid};
use middle::ty; 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::check::regionmanip::{replace_bound_regions_in_fn_sig};
use middle::typeck::infer::coercion::Coerce; use middle::typeck::infer::coercion::Coerce;
use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys}; 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::to_str::InferStr;
use middle::typeck::infer::unify::{ValsAndBindings, Root}; use middle::typeck::infer::unify::{ValsAndBindings, Root};
use middle::typeck::infer::error_reporting::ErrorReporting; use middle::typeck::infer::error_reporting::ErrorReporting;
use middle::typeck::isr_alist; use std::hashmap::HashMap;
use util::common::indent;
use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str, Repr,
UserString};
use std::result; use std::result;
use std::vec; use std::vec;
use extra::list::Nil;
use extra::smallintmap::SmallIntMap;
use syntax::ast::{MutImmutable, MutMutable}; use syntax::ast::{MutImmutable, MutMutable};
use syntax::ast; use syntax::ast;
use syntax::codemap; use syntax::codemap;
use syntax::codemap::Span; 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 doc;
pub mod macros; pub mod macros;
@ -225,8 +225,6 @@ pub enum RegionVariableOrigin {
BoundRegionInTypeOrImpl(Span), BoundRegionInTypeOrImpl(Span),
BoundRegionInCoherence, BoundRegionInCoherence,
BoundRegionError(Span),
} }
pub enum fixup_err { pub enum fixup_err {
@ -568,15 +566,16 @@ impl InferCtxt {
/// Execute `f`, unroll bindings on failure /// Execute `f`, unroll bindings on failure
pub fn try<T,E>(@mut self, f: &fn() -> Result<T,E>) -> Result<T,E> { pub fn try<T,E>(@mut self, f: &fn() -> Result<T,E>) -> Result<T,E> {
debug!("try()"); debug!("try()");
do indent { let snapshot = self.start_snapshot();
let snapshot = self.start_snapshot(); let r = f();
let r = f(); match r {
match r { Ok(_) => { debug!("success"); }
Ok(_) => (), Err(ref e) => {
Err(_) => self.rollback_to(&snapshot) debug!("error: {:?}", *e);
self.rollback_to(&snapshot)
} }
r
} }
r
} }
/// Execute `f` then unroll any bindings it creates /// 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))) 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) { pub fn resolve_regions(@mut self) {
let errors = self.region_vars.resolve_regions(); let errors = self.region_vars.resolve_regions();
self.report_region_errors(&errors); // see error_reporting.rs 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, pub fn replace_bound_regions_with_fresh_regions(&mut self,
trace: TypeTrace, trace: TypeTrace,
fsig: &ty::FnSig) fsig: &ty::FnSig)
-> (ty::FnSig, isr_alist) { -> (ty::FnSig,
let(isr, _, fn_sig) = HashMap<ty::bound_region,
replace_bound_regions_in_fn_sig(self.tcx, @Nil, None, fsig, |br| { ty::Region>) {
let (map, _, fn_sig) =
replace_bound_regions_in_fn_sig(self.tcx, None, fsig, |br| {
let rvar = self.next_region_var( let rvar = self.next_region_var(
BoundRegionInFnType(trace.origin.span(), br)); BoundRegionInFnType(trace.origin.span(), br));
debug!("Bound region {} maps to {:?}", debug!("Bound region {} maps to {:?}",
@ -797,18 +809,16 @@ impl InferCtxt {
rvar); rvar);
rvar rvar
}); });
(fn_sig, isr) (fn_sig, map)
} }
} }
pub fn fold_regions_in_sig( pub fn fold_regions_in_sig(
tcx: ty::ctxt, tcx: ty::ctxt,
fn_sig: &ty::FnSig, 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::RegionFolder::regions(tcx, fldr).fold_sig(fn_sig)
ty::fold_regions(tcx, t, |r, in_fn| fldr(r, in_fn))
}
} }
impl TypeTrace { impl TypeTrace {
@ -910,7 +920,6 @@ impl RegionVariableOrigin {
BoundRegionInFnType(a, _) => a, BoundRegionInFnType(a, _) => a,
BoundRegionInTypeOrImpl(a) => a, BoundRegionInTypeOrImpl(a) => a,
BoundRegionInCoherence => codemap::dummy_sp(), BoundRegionInCoherence => codemap::dummy_sp(),
BoundRegionError(a) => a,
} }
} }
} }
@ -931,7 +940,6 @@ impl Repr for RegionVariableOrigin {
BoundRegionInTypeOrImpl(a) => format!("BoundRegionInTypeOrImpl({})", BoundRegionInTypeOrImpl(a) => format!("BoundRegionInTypeOrImpl({})",
a.repr(tcx)), a.repr(tcx)),
BoundRegionInCoherence => format!("BoundRegionInCoherence"), BoundRegionInCoherence => format!("BoundRegionInCoherence"),
BoundRegionError(a) => format!("BoundRegionError({})", a.repr(tcx)),
} }
} }
} }

View file

@ -13,7 +13,8 @@
use middle::ty; use middle::ty;
use middle::ty::{FreeRegion, Region, RegionVid}; 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::ty::{re_scope, ReVar, ReSkolemized, br_fresh};
use middle::typeck::infer::cres; use middle::typeck::infer::cres;
use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin}; use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin};
@ -192,24 +193,33 @@ impl RegionVarBindings {
re_infer(ReSkolemized(sc, br)) 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. // Creates a fresh bound variable for use in GLB computations.
// See discussion of GLB computation in the large comment at // See discussion of GLB computation in the large comment at
// the top of this file for more details. // the top of this file for more details.
// //
// This computation is mildly wrong in the face of rollover. // This computation is potentially wrong in the face of
// It's conceivable, if unlikely, that one might wind up with // rollover. It's conceivable, if unlikely, that one might
// accidental capture for nested functions in that case, if // wind up with accidental capture for nested functions in
// the outer function had bound regions created a very long // that case, if the outer function had bound regions created
// time before and the inner function somehow wound up rolling // a very long time before and the inner function somehow
// over such that supposedly fresh identifiers were in fact // wound up rolling over such that supposedly fresh
// shadowed. We should convert our bound_region // identifiers were in fact shadowed. For now, we just assert
// representation to use deBruijn indices or something like // that there is no rollover -- eventually we should try to be
// that to eliminate that possibility. // 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; let sc = self.bound_count;
self.bound_count += 1; 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, pub fn add_constraint(&mut self,
@ -236,6 +246,16 @@ impl RegionVarBindings {
debug!("RegionVarBindings: make_subregion({:?}, {:?})", sub, sup); debug!("RegionVarBindings: make_subregion({:?}, {:?})", sub, sup);
match (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))) => { (re_infer(ReVar(sub_id)), re_infer(ReVar(sup_id))) => {
self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin);
} }
@ -245,16 +265,6 @@ impl RegionVarBindings {
(re_infer(ReVar(sub_id)), r) => { (re_infer(ReVar(sub_id)), r) => {
self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); 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); self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
} }
@ -485,6 +495,16 @@ impl RegionVarBindings {
fn lub_concrete_regions(&self, a: Region, b: Region) -> Region { fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
match (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: LUB({}, {})",
a.repr(self.tcx),
b.repr(self.tcx)));
}
(re_static, _) | (_, re_static) => { (re_static, _) | (_, re_static) => {
re_static // nothing lives longer than static re_static // nothing lives longer than static
} }
@ -536,12 +556,7 @@ impl RegionVarBindings {
// For these types, we cannot define any additional // For these types, we cannot define any additional
// relationship: // relationship:
(re_infer(ReSkolemized(*)), _) | (re_infer(ReSkolemized(*)), _) |
(_, 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(_)) => {
if a == b {a} else {re_static} if a == b {a} else {re_static}
} }
} }
@ -584,6 +599,16 @@ impl RegionVarBindings {
-> cres<Region> { -> cres<Region> {
debug!("glb_concrete_regions({:?}, {:?})", a, b); debug!("glb_concrete_regions({:?}, {:?})", a, b);
match (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) => { (re_static, r) | (r, re_static) => {
// static lives longer than everything else // static lives longer than everything else
Ok(r) Ok(r)
@ -627,12 +652,7 @@ impl RegionVarBindings {
// For these types, we cannot define any additional // For these types, we cannot define any additional
// relationship: // relationship:
(re_infer(ReSkolemized(*)), _) | (re_infer(ReSkolemized(*)), _) |
(_, 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(_)) => {
if a == b { if a == b {
Ok(a) Ok(a)
} else { } else {

View file

@ -50,6 +50,7 @@
use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid};
use middle::ty::{type_is_bot, IntType, UintType}; use middle::ty::{type_is_bot, IntType, UintType};
use middle::ty; use middle::ty;
use middle::ty_fold;
use middle::typeck::infer::{Bounds, cyclic_ty, fixup_err, fres, InferCtxt}; 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::{region_var_bound_by_region_var, unresolved_ty};
use middle::typeck::infer::to_str::InferStr; 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 { impl ResolveState {
pub fn should(&mut self, mode: uint) -> bool { pub fn should(&mut self, mode: uint) -> bool {
(self.modes & mode) == mode (self.modes & mode) == mode
@ -166,11 +181,7 @@ impl ResolveState {
typ typ
} else { } else {
self.type_depth += 1; self.type_depth += 1;
let result = ty::fold_regions_and_ty( let result = ty_fold::super_fold_ty(self, typ);
self.infcx.tcx, typ,
|r| self.resolve_region(r),
|t| self.resolve_type(t),
|t| self.resolve_type(t));
self.type_depth -= 1; self.type_depth -= 1;
result result
} }

View file

@ -24,8 +24,6 @@ use middle::typeck::infer::{TypeTrace, Subtype};
use util::common::{indenter}; use util::common::{indenter};
use util::ppaux::bound_region_to_str; use util::ppaux::bound_region_to_str;
use extra::list::Nil;
use extra::list;
use syntax::ast::{Onceness, purity}; use syntax::ast::{Onceness, purity};
pub struct Sub(CombineFields); // "subtype", "subregion" etc 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 // Second, we instantiate each bound region in the supertype with a
// fresh concrete region. // fresh concrete region.
let (skol_isr, _, b_sig) = { let (skol_map, _, b_sig) = {
do replace_bound_regions_in_fn_sig(self.infcx.tcx, @Nil, do replace_bound_regions_in_fn_sig(self.infcx.tcx, None, b) |br| {
None, b) |br| {
let skol = self.infcx.region_vars.new_skolemized(br); let skol = self.infcx.region_vars.new_skolemized(br);
debug!("Bound region {} skolemized to {:?}", debug!("Bound region {} skolemized to {:?}",
bound_region_to_str(self.infcx.tcx, "", false, br), bound_region_to_str(self.infcx.tcx, "", false, br),
@ -189,10 +186,7 @@ impl Combine for Sub {
// that the skolemized regions do not "leak". // that the skolemized regions do not "leak".
let new_vars = let new_vars =
self.infcx.region_vars.vars_created_since_snapshot(snapshot); self.infcx.region_vars.vars_created_since_snapshot(snapshot);
for (&skol_br, &skol) in skol_map.iter() {
let mut ret = Ok(sig);
do list::each(skol_isr) |pair| {
let (skol_br, skol) = *pair;
let tainted = self.infcx.region_vars.tainted(snapshot, skol); let tainted = self.infcx.region_vars.tainted(snapshot, skol);
for tainted_region in tainted.iter() { for tainted_region in tainted.iter() {
// Each skolemized should only be relatable to itself // Each skolemized should only be relatable to itself
@ -208,19 +202,16 @@ impl Combine for Sub {
// A is not as polymorphic as B: // A is not as polymorphic as B:
if self.a_is_expected { if self.a_is_expected {
ret = Err(ty::terr_regions_insufficiently_polymorphic( return Err(ty::terr_regions_insufficiently_polymorphic(
skol_br, *tainted_region)); skol_br, *tainted_region));
break
} else { } else {
ret = Err(ty::terr_regions_overly_polymorphic( return Err(ty::terr_regions_overly_polymorphic(
skol_br, *tainted_region)); skol_br, *tainted_region));
break
} }
} }
ret.is_ok() }
};
ret return Ok(sig);
} }
} }

View file

@ -64,7 +64,6 @@ use extra::list;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::print::pprust::*; use syntax::print::pprust::*;
use syntax::{ast, ast_map, abi}; use syntax::{ast, ast_map, abi};
use syntax::opt_vec;
pub mod check; pub mod check;
pub mod rscope; 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 { pub fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty {
generics: ty::Generics {type_param_defs: @~[], generics: ty::Generics {type_param_defs: @~[],
region_param: None}, region_param_defs: @[]},
ty: t ty: t
} }
} }
@ -354,7 +353,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
purity: ast::impure_fn, purity: ast::impure_fn,
abis: abi::AbiSet::Rust(), abis: abi::AbiSet::Rust(),
sig: ty::FnSig { sig: ty::FnSig {
bound_lifetime_names: opt_vec::Empty, binder_id: main_id,
inputs: ~[], inputs: ~[],
output: ty::mk_nil(), output: ty::mk_nil(),
variadic: false variadic: false
@ -400,7 +399,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
purity: ast::impure_fn, purity: ast::impure_fn,
abis: abi::AbiSet::Rust(), abis: abi::AbiSet::Rust(),
sig: ty::FnSig { sig: ty::FnSig {
bound_lifetime_names: opt_vec::Empty, binder_id: start_id,
inputs: ~[ inputs: ~[
ty::mk_int(), ty::mk_int(),
ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8())) ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8()))

View file

@ -11,10 +11,10 @@
use metadata::encoder; use metadata::encoder;
use middle::ty::{ReSkolemized, ReVar}; 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::{br_fresh, ctxt, field};
use middle::ty::{mt, t, param_ty}; 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}; re_empty};
use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; 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}; 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); let (msg, opt_span) = explain_span(cx, "block", blk.span);
(format!("{} {}", prefix, msg), opt_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 => { Some(_) | None => {
// this really should not happen // this really should not happen
(format!("{} node {}", prefix, fr.scope_id), None) (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, // I believe these cases should not occur (except when debugging,
// perhaps) // perhaps)
re_infer(_) | re_bound(_) => { ty::re_infer(_) | ty::re_type_bound(*) | ty::re_fn_bound(*) => {
(format!("lifetime {:?}", region), None) (format!("lifetime {:?}", region), None)
} }
}; };
@ -154,14 +159,15 @@ pub fn bound_region_to_str(cx: ctxt,
br: bound_region) -> ~str { br: bound_region) -> ~str {
let space_str = if space { " " } else { "" }; 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 { match br {
br_named(id) => format!("{}'{}{}", prefix, cx.sess.str_of(id), space_str), br_named(_, ident) => format!("{}'{}{}", prefix,
br_self => format!("{}'self{}", prefix, space_str), cx.sess.str_of(ident), space_str),
br_anon(_) => prefix.to_str(), br_anon(_) => prefix.to_str(),
br_fresh(_) => 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 { "" }; let space_str = if space { " " } else { "" };
if cx.sess.verbose() { 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 // 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 // to fit that into a short string. Hence the recommendation to use
// `explain_region()` or `note_and_explain_region()`. // `explain_region()` or `note_and_explain_region()`.
match region { match region {
re_scope(_) => prefix.to_str(), ty::re_scope(_) => prefix.to_str(),
re_bound(br) => bound_region_to_str(cx, prefix, space, br), ty::re_type_bound(_, _, ident) => cx.sess.str_of(ident).to_owned(),
re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region), ty::re_fn_bound(_, br) => bound_region_to_str(cx, prefix, space, br),
re_infer(ReSkolemized(_, 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) bound_region_to_str(cx, prefix, space, br)
} }
re_infer(ReVar(_)) => prefix.to_str(), ty::re_infer(ReVar(_)) => prefix.to_str(),
re_static => format!("{}'static{}", prefix, space_str), ty::re_static => format!("{}'static{}", prefix, space_str),
re_empty => format!("{}'<empty>{}", prefix, space_str) ty::re_empty => format!("{}'<empty>{}", 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 { pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str {
format!("fn{} -> {}", format!("fn{}{} -> {}",
tys_to_str(cx, typ.inputs.map(|a| *a)), typ.binder_id,
ty_to_str(cx, typ.output)) typ.inputs.repr(cx),
typ.output.repr(cx))
} }
pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str { pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str {
@ -594,8 +602,17 @@ impl<T:Repr> Repr for ~[T] {
impl Repr for ty::TypeParameterDef { impl Repr for ty::TypeParameterDef {
fn repr(&self, tcx: ctxt) -> ~str { fn repr(&self, tcx: ctxt) -> ~str {
format!("TypeParameterDef \\{{:?}, bounds: {}\\}", format!("TypeParameterDef({:?}, {})",
self.def_id, self.bounds.repr(tcx)) 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 { impl Repr for ast::Pat {
fn repr(&self, tcx: ctxt) -> ~str { fn repr(&self, tcx: ctxt) -> ~str {
format!("pat({}: {})", format!("pat({}: {})",
@ -665,13 +691,56 @@ impl Repr for ast::Pat {
impl Repr for ty::bound_region { impl Repr for ty::bound_region {
fn repr(&self, tcx: ctxt) -> ~str { 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 { impl Repr for ty::Region {
fn repr(&self, tcx: ctxt) -> ~str { 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 { impl Repr for ty::Generics {
fn repr(&self, tcx: ctxt) -> ~str { fn repr(&self, tcx: ctxt) -> ~str {
format!("Generics \\{type_param_defs: {}, region_param: {:?}\\}", format!("Generics(type_param_defs: {}, region_param_defs: {})",
self.type_param_defs.repr(tcx), self.type_param_defs.repr(tcx),
self.region_param) 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 { impl Repr for ty::Method {
fn repr(&self, tcx: ctxt) -> ~str { fn repr(&self, tcx: ctxt) -> ~str {
format!("method \\{ident: {}, generics: {}, transformed_self_ty: {}, \ format!("method(ident: {}, generics: {}, transformed_self_ty: {}, \
fty: {}, explicit_self: {}, vis: {}, def_id: {}\\}", fty: {}, explicit_self: {}, vis: {}, def_id: {})",
self.ident.repr(tcx), self.ident.repr(tcx),
self.generics.repr(tcx), self.generics.repr(tcx),
self.transformed_self_ty.repr(tcx), self.transformed_self_ty.repr(tcx),
self.fty.repr(tcx), self.fty.repr(tcx),
self.explicit_self.repr(tcx), self.explicit_self.repr(tcx),
self.vis.repr(tcx), self.vis.repr(tcx),
self.def_id.repr(tcx)) self.def_id.repr(tcx))
} }
} }

View file

@ -835,7 +835,7 @@ impl Clean<Path> for ast::Path {
#[deriving(Clone, Encodable, Decodable)] #[deriving(Clone, Encodable, Decodable)]
pub struct PathSegment { pub struct PathSegment {
name: ~str, name: ~str,
lifetime: Option<Lifetime>, lifetimes: ~[Lifetime],
types: ~[Type], types: ~[Type],
} }
@ -843,7 +843,7 @@ impl Clean<PathSegment> for ast::PathSegment {
fn clean(&self) -> PathSegment { fn clean(&self) -> PathSegment {
PathSegment { PathSegment {
name: self.identifier.clean(), name: self.identifier.clean(),
lifetime: self.lifetime.clean(), lifetimes: self.lifetimes.clean(),
types: self.types.clean() types: self.types.clean()
} }
} }

View file

@ -92,16 +92,17 @@ impl fmt::Default for clean::Path {
if i > 0 { f.buf.write("::".as_bytes()) } if i > 0 { f.buf.write("::".as_bytes()) }
f.buf.write(seg.name.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("&lt;".as_bytes()); f.buf.write("&lt;".as_bytes());
match seg.lifetime { let mut comma = false;
Some(ref lifetime) => write!(f.buf, "{}", *lifetime), for lifetime in seg.lifetimes.iter() {
None => {} if comma { f.buf.write(", ".as_bytes()); }
comma = true;
write!(f.buf, "{}", *lifetime);
} }
for (i, ty) in seg.types.iter().enumerate() { for ty in seg.types.iter() {
if i > 0 || seg.lifetime.is_some() { if comma { f.buf.write(", ".as_bytes()); }
f.buf.write(", ".as_bytes()); comma = true;
}
write!(f.buf, "{}", *ty); write!(f.buf, "{}", *ty);
} }
f.buf.write("&gt;".as_bytes()); f.buf.write("&gt;".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 // The generics will get written to both the title and link
let mut generics = ~""; let mut generics = ~"";
let last = path.segments.last(); 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("&lt;"); generics.push_str("&lt;");
match last.lifetime { for lifetime in last.lifetimes.iter() {
Some(ref lifetime) => generics.push_str(format!("{}", *lifetime)), if counter > 0 { generics.push_str(", "); }
None => {} counter += 1;
generics.push_str(format!("{}", *lifetime));
} }
for (i, ty) in last.types.iter().enumerate() { for ty in last.types.iter() {
if i > 0 || last.lifetime.is_some() { if counter > 0 { generics.push_str(", "); }
generics.push_str(", "); counter += 1;
}
generics.push_str(format!("{}", *ty)); generics.push_str(format!("{}", *ty));
} }
generics.push_str("&gt;"); generics.push_str("&gt;");
@ -495,7 +497,7 @@ impl fmt::Default for clean::ViewListIdent {
global: false, global: false,
segments: ~[clean::PathSegment { segments: ~[clean::PathSegment {
name: v.name.clone(), name: v.name.clone(),
lifetime: None, lifetimes: ~[],
types: ~[], types: ~[],
}] }]
}; };

View file

@ -12,7 +12,7 @@
use clone::Clone; use clone::Clone;
use container::Container; use container::Container;
use iter::Iterator; use iter::{Iterator, FromIterator};
use option::{Option, Some, None}; use option::{Option, Some, None};
use mem; use mem;
use unstable::raw::Repr; use unstable::raw::Repr;
@ -134,6 +134,17 @@ impl<T> Clone for @[T] {
} }
} }
impl<A> FromIterator<A> for @[A] {
fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> @[A] {
let (lower, _) = iterator.size_hint();
do build(Some(lower)) |push| {
for x in *iterator {
push(x);
}
}
}
}
#[cfg(not(test))] #[cfg(not(test))]
#[allow(missing_doc)] #[allow(missing_doc)]
pub mod traits { pub mod traits {

View file

@ -28,7 +28,7 @@ use extra::serialize::{Encodable, Decodable, Encoder, Decoder};
// table) and a SyntaxContext to track renaming and // table) and a SyntaxContext to track renaming and
// macro expansion per Flatt et al., "Macros // macro expansion per Flatt et al., "Macros
// That Work Together" // That Work Together"
#[deriving(Clone, IterBytes, ToStr)] #[deriving(Clone, IterBytes, ToStr, TotalEq, TotalOrd)]
pub struct Ident { name: Name, ctxt: SyntaxContext } pub struct Ident { name: Name, ctxt: SyntaxContext }
impl Ident { impl Ident {
@ -110,6 +110,7 @@ pub enum SyntaxContext_ {
/// A name is a part of an identifier, representing a string or gensym. It's /// A name is a part of an identifier, representing a string or gensym. It's
/// the result of interning. /// the result of interning.
pub type Name = uint; pub type Name = uint;
/// A mark represents a unique id associated with a macro expansion /// A mark represents a unique id associated with a macro expansion
pub type Mrk = uint; pub type Mrk = uint;
@ -156,9 +157,8 @@ pub struct Path {
pub struct PathSegment { pub struct PathSegment {
/// The identifier portion of this path segment. /// The identifier portion of this path segment.
identifier: Ident, identifier: Ident,
/// The lifetime parameter for this path segment. Currently only one /// The lifetime parameters for this path segment.
/// lifetime parameter is allowed. lifetimes: OptVec<Lifetime>,
lifetime: Option<Lifetime>,
/// The type parameters for this path segment, if present. /// The type parameters for this path segment, if present.
types: OptVec<Ty>, types: OptVec<Ty>,
} }
@ -167,7 +167,7 @@ pub type CrateNum = int;
pub type NodeId = int; pub type NodeId = int;
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes, ToStr)] #[deriving(Clone, TotalEq, TotalOrd, Eq, Encodable, Decodable, IterBytes, ToStr)]
pub struct DefId { pub struct DefId {
crate: CrateNum, crate: CrateNum,
node: NodeId, node: NodeId,

View file

@ -488,3 +488,15 @@ pub fn node_item_query<Result>(items: map, id: NodeId,
_ => fail!("{}", error_msg) _ => 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))
}
}
}

View file

@ -225,7 +225,7 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
segments: ~[ segments: ~[
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetime: None, lifetimes: opt_vec::Empty,
types: 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() { for (idx,seg) in a.iter().enumerate() {
if (seg.identifier.name != b[idx].identifier.name) if (seg.identifier.name != b[idx].identifier.name)
// FIXME #7743: ident -> name problems in lifetime comparison? // FIXME #7743: ident -> name problems in lifetime comparison?
|| (seg.lifetime != b[idx].lifetime) || (seg.lifetimes != b[idx].lifetimes)
// can types contain idents? // can types contain idents?
|| (seg.types != b[idx].types) { || (seg.types != b[idx].types) {
return false; return false;
@ -966,7 +966,9 @@ mod test {
use std::hashmap::HashMap; use std::hashmap::HashMap;
fn ident_to_segment(id : &Ident) -> PathSegment { 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() { #[test] fn idents_name_eq_test() {

View file

@ -38,7 +38,7 @@ pub trait AstBuilder {
fn path_all(&self, sp: Span, fn path_all(&self, sp: Span,
global: bool, global: bool,
idents: ~[ast::Ident], idents: ~[ast::Ident],
rp: Option<ast::Lifetime>, lifetimes: OptVec<ast::Lifetime>,
types: ~[ast::Ty]) types: ~[ast::Ty])
-> ast::Path; -> ast::Path;
@ -237,19 +237,19 @@ pub trait AstBuilder {
impl AstBuilder for @ExtCtxt { impl AstBuilder for @ExtCtxt {
fn path(&self, span: Span, strs: ~[ast::Ident]) -> ast::Path { 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 { fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path {
self.path(span, ~[id]) self.path(span, ~[id])
} }
fn path_global(&self, span: Span, strs: ~[ast::Ident]) -> ast::Path { 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, fn path_all(&self,
sp: Span, sp: Span,
global: bool, global: bool,
mut idents: ~[ast::Ident], mut idents: ~[ast::Ident],
rp: Option<ast::Lifetime>, lifetimes: OptVec<ast::Lifetime>,
types: ~[ast::Ty]) types: ~[ast::Ty])
-> ast::Path { -> ast::Path {
let last_identifier = idents.pop(); let last_identifier = idents.pop();
@ -257,13 +257,13 @@ impl AstBuilder for @ExtCtxt {
.map(|ident| { .map(|ident| {
ast::PathSegment { ast::PathSegment {
identifier: ident, identifier: ident,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
}).collect(); }).collect();
segments.push(ast::PathSegment { segments.push(ast::PathSegment {
identifier: last_identifier, identifier: last_identifier,
lifetime: rp, lifetimes: lifetimes,
types: opt_vec::from(types), types: opt_vec::from(types),
}); });
ast::Path { ast::Path {
@ -327,7 +327,7 @@ impl AstBuilder for @ExtCtxt {
self.ident_of("option"), self.ident_of("option"),
self.ident_of("Option") self.ident_of("Option")
], ],
None, opt_vec::Empty,
~[ ty ]), None) ~[ ty ]), None)
} }

View file

@ -43,7 +43,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
segments: ~[ segments: ~[
ast::PathSegment { ast::PathSegment {
identifier: res, identifier: res,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
] ]

View file

@ -375,14 +375,10 @@ impl<'self> TraitDef<'self> {
cx.ty_ident(trait_span, ty_param.ident) cx.ty_ident(trait_span, ty_param.ident)
}; };
let self_lifetime = if generics.lifetimes.is_empty() { let self_lifetimes = generics.lifetimes.clone();
None
} else {
Some(*generics.lifetimes.get(0))
};
// Create the type of `self`. // 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); opt_vec::take_vec(self_ty_params)), None);
let doc_attr = cx.attribute( let doc_attr = cx.attribute(

View file

@ -14,6 +14,7 @@ use codemap::Span;
use ext::base::ExtCtxt; use ext::base::ExtCtxt;
use ext::build::{AstBuilder}; use ext::build::{AstBuilder};
use ext::deriving::generic::*; use ext::deriving::generic::*;
use opt_vec;
pub fn expand_deriving_rand(cx: @ExtCtxt, pub fn expand_deriving_rand(cx: @ExtCtxt,
span: Span, span: Span,
@ -77,7 +78,7 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
let rand_name = cx.path_all(span, let rand_name = cx.path_all(span,
true, true,
rand_ident.clone(), rand_ident.clone(),
None, opt_vec::Empty,
~[]); ~[]);
let rand_name = cx.expr_path(rand_name); let rand_name = cx.expr_path(rand_name);

View file

@ -19,6 +19,7 @@ use ext::base::ExtCtxt;
use ext::build::AstBuilder; use ext::build::AstBuilder;
use codemap::{Span,respan}; use codemap::{Span,respan};
use opt_vec; use opt_vec;
use opt_vec::OptVec;
/// The types of pointers /// The types of pointers
pub enum PtrTy<'self> { pub enum PtrTy<'self> {
@ -71,7 +72,7 @@ impl<'self> Path<'self> {
self_generics: &Generics) self_generics: &Generics)
-> ast::Path { -> ast::Path {
let idents = self.path.map(|s| cx.ident_of(*s) ); 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)); let tys = self.params.map(|t| t.to_ty(cx, span, self_ty, self_generics));
cx.path_all(span, self.global, idents, lt, tys) cx.path_all(span, self.global, idents, lt, tys)
@ -116,6 +117,13 @@ fn mk_lifetime(cx: @ExtCtxt, span: Span, lt: &Option<&str>) -> Option<ast::Lifet
} }
} }
fn mk_lifetimes(cx: @ExtCtxt, span: Span, lt: &Option<&str>) -> OptVec<ast::Lifetime> {
match *lt {
Some(ref s) => opt_vec::with(cx.lifetime(span, cx.ident_of(*s))),
None => opt_vec::Empty
}
}
impl<'self> Ty<'self> { impl<'self> Ty<'self> {
pub fn to_ty(&self, pub fn to_ty(&self,
cx: @ExtCtxt, cx: @ExtCtxt,
@ -166,13 +174,9 @@ impl<'self> Ty<'self> {
let self_params = do self_generics.ty_params.map |ty_param| { let self_params = do self_generics.ty_params.map |ty_param| {
cx.ty_ident(span, ty_param.ident) cx.ty_ident(span, ty_param.ident)
}; };
let lifetime = if self_generics.lifetimes.is_empty() { let lifetimes = self_generics.lifetimes.clone();
None
} else {
Some(*self_generics.lifetimes.get(0))
};
cx.path_all(span, false, ~[self_ty], lifetime, cx.path_all(span, false, ~[self_ty], lifetimes,
opt_vec::take_vec(self_params)) opt_vec::take_vec(self_params))
} }
Literal(ref p) => { Literal(ref p) => {

View file

@ -169,7 +169,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
segments: ~[ segments: ~[
ast::PathSegment { ast::PathSegment {
identifier: ident, identifier: ident,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
], ],
@ -628,7 +628,7 @@ impl Visitor<()> for NewNameFinderContext {
segments: [ segments: [
ast::PathSegment { ast::PathSegment {
identifier: id, identifier: id,
lifetime: _, lifetimes: _,
types: _ types: _
} }
] ]

View file

@ -15,7 +15,7 @@ use ext::base;
use ext::build::AstBuilder; use ext::build::AstBuilder;
use rsparse = parse; use rsparse = parse;
use parse::token; use parse::token;
use opt_vec;
use std::fmt::parse; use std::fmt::parse;
use std::hashmap::{HashMap, HashSet}; use std::hashmap::{HashMap, HashSet};
use std::vec; use std::vec;
@ -464,7 +464,7 @@ impl Context {
sp, sp,
true, true,
rtpath("Method"), rtpath("Method"),
Some(life), opt_vec::with(life),
~[] ~[]
), None); ), None);
let st = ast::item_static(ty, ast::MutImmutable, method); let st = ast::item_static(ty, ast::MutImmutable, method);
@ -582,7 +582,8 @@ impl Context {
self.ecx.ident_of("rt"), self.ecx.ident_of("rt"),
self.ecx.ident_of("Piece"), 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); ), None);
let ty = ast::ty_fixed_length_vec( let ty = ast::ty_fixed_length_vec(

View file

@ -144,7 +144,7 @@ pub trait ast_fold {
ident: self.fold_ident(m.ident), ident: self.fold_ident(m.ident),
attrs: m.attrs.map(|a| fold_attribute_(*a, self)), attrs: m.attrs.map(|a| fold_attribute_(*a, self)),
generics: fold_generics(&m.generics, self), generics: fold_generics(&m.generics, self),
explicit_self: m.explicit_self, explicit_self: self.fold_explicit_self(&m.explicit_self),
purity: m.purity, purity: m.purity,
decl: fold_fn_decl(&m.decl, self), decl: fold_fn_decl(&m.decl, self),
body: self.fold_block(&m.body), 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_uniq(ref mt) => ty_uniq(fold_mt(mt, self)),
ty_vec(ref mt) => ty_vec(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_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(ref f) => {
ty_closure(@TyClosure { ty_closure(@TyClosure {
sigil: f.sigil, sigil: f.sigil,
purity: f.purity, purity: f.purity,
region: f.region, region: fold_opt_lifetime(&f.region, self),
onceness: f.onceness, onceness: f.onceness,
bounds: fold_opt_bounds(&f.bounds, self), bounds: fold_opt_bounds(&f.bounds, self),
decl: fold_fn_decl(&f.decl, self), decl: fold_fn_decl(&f.decl, self),
@ -349,7 +351,7 @@ pub trait ast_fold {
global: p.global, global: p.global,
segments: p.segments.map(|segment| ast::PathSegment { segments: p.segments.map(|segment| ast::PathSegment {
identifier: self.fold_ident(segment.identifier), 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)), types: segment.types.map(|typ| self.fold_ty(typ)),
}) })
} }
@ -389,6 +391,24 @@ pub trait ast_fold {
fn new_span(&self, sp: Span) -> Span { fn new_span(&self, sp: Span) -> Span {
sp 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*/ /* some little folds that probably aren't useful to have in ast_fold itself*/
@ -505,6 +525,11 @@ pub fn fold_lifetimes<T:ast_fold>(lts: &OptVec<Lifetime>, fld: &T)
lts.map(|l| fold_lifetime(l, fld)) lts.map(|l| fold_lifetime(l, fld))
} }
pub fn fold_opt_lifetime<T:ast_fold>(o_lt: &Option<Lifetime>, fld: &T)
-> Option<Lifetime> {
o_lt.as_ref().map(|lt| fold_lifetime(lt, fld))
}
pub fn fold_generics<T:ast_fold>(generics: &Generics, fld: &T) -> Generics { pub fn fold_generics<T:ast_fold>(generics: &Generics, fld: &T) -> Generics {
Generics {ty_params: fold_ty_params(&generics.ty_params, fld), Generics {ty_params: fold_ty_params(&generics.ty_params, fld),
lifetimes: fold_lifetimes(&generics.lifetimes, fld)} lifetimes: fold_lifetimes(&generics.lifetimes, fld)}
@ -675,7 +700,7 @@ pub fn noop_fold_type_method<T:ast_fold>(m: &TypeMethod, fld: &T)
purity: m.purity, purity: m.purity,
decl: fold_fn_decl(&m.decl, fld), decl: fold_fn_decl(&m.decl, fld),
generics: fold_generics(&m.generics, 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), id: fld.new_id(m.id),
span: fld.new_span(m.span), span: fld.new_span(m.span),
} }

View file

@ -165,3 +165,13 @@ impl<'self, T> Iterator<&'self T> for OptVecIterator<'self, T> {
} }
} }
} }
impl<A> FromIterator<A> for OptVec<A> {
fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> OptVec<A> {
let mut r = Empty;
for x in *iterator {
r.push(x);
}
r
}
}

View file

@ -368,7 +368,7 @@ mod test {
segments: ~[ segments: ~[
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("a"), identifier: str_to_ident("a"),
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
], ],
@ -387,12 +387,12 @@ mod test {
segments: ~[ segments: ~[
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("a"), identifier: str_to_ident("a"),
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
}, },
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("b"), identifier: str_to_ident("b"),
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
] ]
@ -592,7 +592,7 @@ mod test {
segments: ~[ segments: ~[
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("d"), identifier: str_to_ident("d"),
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
], ],
@ -614,7 +614,7 @@ mod test {
segments: ~[ segments: ~[
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("b"), identifier: str_to_ident("b"),
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
], ],
@ -641,7 +641,7 @@ mod test {
segments: ~[ segments: ~[
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("b"), identifier: str_to_ident("b"),
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
], ],
@ -669,7 +669,7 @@ mod test {
ast::PathSegment { ast::PathSegment {
identifier: identifier:
str_to_ident("int"), str_to_ident("int"),
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
], ],
@ -687,7 +687,7 @@ mod test {
ast::PathSegment { ast::PathSegment {
identifier: identifier:
str_to_ident("b"), str_to_ident("b"),
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
], ],
@ -724,8 +724,8 @@ mod test {
identifier: identifier:
str_to_ident( str_to_ident(
"b"), "b"),
lifetime: lifetimes:
None, opt_vec::Empty,
types: types:
opt_vec::Empty opt_vec::Empty
} }

View file

@ -1490,7 +1490,7 @@ impl Parser {
segments.push(PathSegmentAndBoundSet { segments.push(PathSegmentAndBoundSet {
segment: ast::PathSegment { segment: ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
}, },
bound_set: bound_set bound_set: bound_set
@ -1499,46 +1499,21 @@ impl Parser {
} }
// Parse the `<` before the lifetime and types, if applicable. // Parse the `<` before the lifetime and types, if applicable.
let (any_lifetime_or_types, optional_lifetime, types) = let (any_lifetime_or_types, lifetimes, types) = {
if mode != NoTypesAllowed && self.eat(&token::LT) { if mode != NoTypesAllowed && self.eat(&token::LT) {
// Parse an optional lifetime. let (lifetimes, types) =
let optional_lifetime = match *self.token { self.parse_generic_values_after_lt();
token::LIFETIME(*) => Some(self.parse_lifetime()), (true, lifetimes, opt_vec::from(types))
_ => None, } else {
}; (false, opt_vec::Empty, opt_vec::Empty)
// 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))
} }
(true, optional_lifetime, types)
} else {
(false, None, opt_vec::Empty)
}; };
// Assemble and push the result. // Assemble and push the result.
segments.push(PathSegmentAndBoundSet { segments.push(PathSegmentAndBoundSet {
segment: ast::PathSegment { segment: ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetime: optional_lifetime, lifetimes: lifetimes,
types: types, types: types,
}, },
bound_set: bound_set bound_set: bound_set
@ -1609,11 +1584,11 @@ impl Parser {
pub fn parse_lifetime(&self) -> ast::Lifetime { pub fn parse_lifetime(&self) -> ast::Lifetime {
match *self.token { match *self.token {
token::LIFETIME(i) => { token::LIFETIME(i) => {
let span = self.span; let span = *self.span;
self.bump(); self.bump();
return ast::Lifetime { return ast::Lifetime {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
span: *span, span: span,
ident: i ident: i
}; };
} }
@ -4856,7 +4831,7 @@ impl Parser {
segments: path.move_iter().map(|identifier| { segments: path.move_iter().map(|identifier| {
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
}).collect() }).collect()
@ -4892,7 +4867,7 @@ impl Parser {
segments: path.move_iter().map(|identifier| { segments: path.move_iter().map(|identifier| {
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
}).collect() }).collect()
@ -4910,7 +4885,7 @@ impl Parser {
segments: path.move_iter().map(|identifier| { segments: path.move_iter().map(|identifier| {
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
}).collect() }).collect()
@ -4932,7 +4907,7 @@ impl Parser {
segments: path.move_iter().map(|identifier| { segments: path.move_iter().map(|identifier| {
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetime: None, lifetimes: opt_vec::Empty,
types: opt_vec::Empty, types: opt_vec::Empty,
} }
}).collect() }).collect()

View file

@ -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 { if colons_before_params {
word(s.s, "::") word(s.s, "::")
} }
word(s.s, "<"); word(s.s, "<");
for lifetime in segment.lifetime.iter() { for lifetime in segment.lifetimes.iter() {
print_lifetime(s, lifetime); print_lifetime(s, lifetime);
if !segment.types.is_empty() { if !segment.types.is_empty() {
word_space(s, ",") 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) { pub fn print_view_path(s: @ps, vp: &ast::view_path) {
match vp.node { match vp.node {
ast::view_path_simple(ident, ref path, _) => { 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); print_ident(s, ident);
space(s.s); space(s.s);
word_space(s, "="); word_space(s, "=");