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: ~[
ast::PathSegment {
identifier: self.sess.ident_of("std"),
lifetime: None,
lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
},
ast::PathSegment {
identifier: self.sess.ident_of("prelude"),
lifetime: None,
lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
},
],

View File

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

View File

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

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_extra: uint = 0x89;
pub static tag_region_param_def: uint = 0x100;
pub static tag_region_param_def_ident: uint = 0x101;
pub static tag_region_param_def_def_id: uint = 0x102;
pub struct LinkMeta {
name: @str,
vers: @str,

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

View File

@ -25,7 +25,7 @@ use middle::ty;
use middle::typeck;
use middle::astencode::vtable_decoder_helpers;
use std::at_vec;
use std::u64;
use std::rt::io;
use std::rt::io::extensions::u64_from_be_bytes;
@ -252,9 +252,11 @@ fn item_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: Cmd) -> ty::TraitRef {
doc_trait_ref(tp, tcx, cdata)
}
fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: Cmd,
fn item_ty_param_defs(item: ebml::Doc,
tcx: ty::ctxt,
cdata: Cmd,
tag: uint)
-> @~[ty::TypeParameterDef] {
-> @~[ty::TypeParameterDef] {
let mut bounds = ~[];
do reader::tagged_docs(item, tag) |p| {
let bd = parse_type_param_def_data(
@ -266,10 +268,23 @@ fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: Cmd,
@bounds
}
fn item_ty_region_param(item: ebml::Doc) -> Option<ty::region_variance> {
do reader::maybe_get_doc(item, tag_region_param).map |doc| {
let mut decoder = reader::Decoder(doc);
Decodable::decode(&mut decoder)
fn item_region_param_defs(item_doc: ebml::Doc,
tcx: ty::ctxt,
cdata: Cmd)
-> @[ty::RegionParameterDef] {
do at_vec::build(None) |push| {
do reader::tagged_docs(item_doc, tag_region_param_def) |rp_doc| {
let ident_str_doc = reader::get_doc(rp_doc,
tag_region_param_def_ident);
let ident = item_name(tcx.sess.intr(), ident_str_doc);
let def_id_doc = reader::get_doc(rp_doc,
tag_region_param_def_def_id);
let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
let def_id = translate_def_id(cdata, def_id);
push(ty::RegionParameterDef { ident: ident,
def_id: def_id });
true
};
}
}
@ -393,7 +408,7 @@ pub fn get_trait_def(cdata: Cmd,
let item_doc = lookup_item(item_id, cdata.data);
let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
tag_items_data_item_ty_param_bounds);
let rp = item_ty_region_param(item_doc);
let rp_defs = item_region_param_defs(item_doc, tcx, cdata);
let mut bounds = ty::EmptyBuiltinBounds();
// Collect the builtin bounds from the encoded supertraits.
// FIXME(#8559): They should be encoded directly.
@ -407,7 +422,7 @@ pub fn get_trait_def(cdata: Cmd,
};
ty::TraitDef {
generics: ty::Generics {type_param_defs: tp_defs,
region_param: rp},
region_param_defs: rp_defs},
bounds: bounds,
trait_ref: @item_trait_ref(item_doc, tcx, cdata)
}
@ -417,33 +432,27 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt)
-> ty::ty_param_bounds_and_ty {
let item = lookup_item(id, cdata.data);
let t = item_type(ast::DefId { crate: cdata.cnum, node: id }, item, tcx,
cdata);
let tp_defs = if family_has_type_params(item_family(item)) {
item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds)
} else { @~[] };
let rp = item_ty_region_param(item);
let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds);
let rp_defs = item_region_param_defs(item, tcx, cdata);
ty::ty_param_bounds_and_ty {
generics: ty::Generics {type_param_defs: tp_defs,
region_param: rp},
region_param_defs: rp_defs},
ty: t
}
}
pub fn get_region_param(cdata: Cmd, id: ast::NodeId)
-> Option<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 {
item_ty_param_count(lookup_item(id, data))
}
pub fn get_impl_trait(cdata: Cmd,
id: ast::NodeId,
tcx: ty::ctxt) -> Option<@ty::TraitRef>
id: ast::NodeId,
tcx: ty::ctxt) -> Option<@ty::TraitRef>
{
let item_doc = lookup_item(id, cdata.data);
do reader::maybe_get_doc(item_doc, tag_item_trait_ref).map |tp| {
@ -1044,6 +1053,7 @@ pub fn get_method(intr: @ident_interner, cdata: Cmd, id: ast::NodeId,
let name = item_name(intr, method_doc);
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps);
let rp_defs = item_region_param_defs(method_doc, tcx, cdata);
let transformed_self_ty = doc_transformed_self_ty(method_doc, tcx, cdata);
let fty = doc_method_fty(method_doc, tcx, cdata);
let vis = item_visibility(method_doc);
@ -1054,7 +1064,7 @@ pub fn get_method(intr: @ident_interner, cdata: Cmd, id: ast::NodeId,
name,
ty::Generics {
type_param_defs: type_param_defs,
region_param: None
region_param_defs: rp_defs,
},
transformed_self_ty,
fty,

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));
}
fn encode_region_param(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
it: @ast::item) {
let opt_rp = ecx.tcx.region_paramd_items.find(&it.id);
for rp in opt_rp.iter() {
ebml_w.start_tag(tag_region_param);
rp.encode(ebml_w);
ebml_w.end_tag();
}
}
#[deriving(Clone)]
struct entry<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,
ecx: &EncodeContext,
tpt: &ty::ty_param_bounds_and_ty) {
encode_ty_type_param_defs(ebml_w, ecx, tpt.generics.type_param_defs,
tag_items_data_item_ty_param_bounds);
encode_region_param_defs(ebml_w, ecx, tpt.generics.region_param_defs);
encode_type(ecx, ebml_w, tpt.ty);
}
@ -976,7 +983,6 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(ecx, ebml_w, item.ident);
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
encode_region_param(ecx, ebml_w, item);
encode_visibility(ebml_w, vis);
ebml_w.end_tag();
}
@ -994,7 +1000,6 @@ fn encode_info_for_item(ecx: &EncodeContext,
}
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
encode_region_param(ecx, ebml_w, item);
// Encode inherent implementations for this enumeration.
encode_inherent_implementations(ecx, ebml_w, def_id);
@ -1030,7 +1035,6 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs);
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
encode_region_param(ecx, ebml_w, item);
encode_visibility(ebml_w, vis);
/* Encode def_ids for each field and method
@ -1075,7 +1079,6 @@ fn encode_info_for_item(ecx: &EncodeContext,
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'i');
encode_region_param(ecx, ebml_w, item);
encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs);
@ -1135,7 +1138,6 @@ fn encode_info_for_item(ecx: &EncodeContext,
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'I');
encode_region_param(ecx, ebml_w, item);
let trait_def = ty::lookup_trait_def(tcx, def_id);
encode_ty_type_param_defs(ebml_w, ecx,
trait_def.generics.type_param_defs,

View File

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

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

View File

@ -15,7 +15,8 @@ use driver::session::Session;
use e = metadata::encoder;
use metadata::decoder;
use metadata::tydecode;
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter};
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
RegionParameter};
use metadata::tyencode;
use middle::freevars::freevar_entry;
use middle::typeck::{method_origin, method_map_entry};
@ -234,6 +235,12 @@ impl tr for ast::DefId {
}
}
impl tr for Option<ast::DefId> {
fn tr(&self, xcx: @ExtendedDecodeContext) -> Option<ast::DefId> {
self.map(|d| xcx.tr_def_id(d))
}
}
impl tr for Span {
fn tr(&self, xcx: @ExtendedDecodeContext) -> Span {
xcx.tr_span(*self)
@ -469,7 +476,11 @@ impl tr for ty::AutoRef {
impl tr for ty::Region {
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::Region {
match *self {
ty::re_bound(br) => ty::re_bound(br.tr(xcx)),
ty::re_fn_bound(id, br) => ty::re_fn_bound(xcx.tr_id(id),
br.tr(xcx)),
ty::re_type_bound(id, index, ident) => ty::re_type_bound(xcx.tr_id(id),
index,
ident),
ty::re_scope(id) => ty::re_scope(xcx.tr_id(id)),
ty::re_empty | ty::re_static | ty::re_infer(*) => *self,
ty::re_free(ref fr) => {
@ -483,10 +494,10 @@ impl tr for ty::Region {
impl tr for ty::bound_region {
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::bound_region {
match *self {
ty::br_anon(_) | ty::br_named(_) | ty::br_self |
ty::br_anon(_) |
ty::br_fresh(_) => *self,
ty::br_cap_avoid(id, br) => ty::br_cap_avoid(xcx.tr_id(id),
@br.tr(xcx))
ty::br_named(id, ident) => ty::br_named(xcx.tr_def_id(id),
ident),
}
}
}
@ -821,8 +832,8 @@ impl ebml_writer_helpers for writer::Encoder {
this.emit_type_param_def(ecx, type_param_def);
}
}
do this.emit_struct_field("region_param", 1) |this| {
tpbt.generics.region_param.encode(this);
do this.emit_struct_field("region_param_defs", 1) |this| {
tpbt.generics.region_param_defs.encode(this);
}
}
}
@ -1086,6 +1097,8 @@ impl ebml_decoder_decoder_helpers for reader::Decoder {
// are not used during trans.
return do self.read_opaque |this, doc| {
debug!("read_ty({})", type_string(doc));
let ty = tydecode::parse_ty_data(
*doc.data,
xcx.dcx.cdata.cnum,
@ -1093,10 +1106,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder {
xcx.dcx.tcx,
|s, a| this.convert_def_id(xcx, s, a));
debug!("read_ty({}) = {}",
type_string(doc),
ty_to_str(xcx.dcx.tcx, ty));
ty
};
@ -1139,8 +1148,8 @@ impl ebml_decoder_decoder_helpers for reader::Decoder {
@this.read_to_vec(|this|
this.read_type_param_def(xcx))
}),
region_param:
this.read_struct_field("region_param",
region_param_defs:
this.read_struct_field("region_param_defs",
1,
|this| {
Decodable::decode(this)
@ -1161,7 +1170,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder {
did: ast::DefId)
-> ast::DefId {
/*!
*
* Converts a def-id that appears in a type. The correct
* translation will depend on what kind of def-id this is.
* This is a subtle point: type definitions are not
@ -1172,10 +1180,25 @@ impl ebml_decoder_decoder_helpers for reader::Decoder {
* However, *type parameters* are cloned along with the function
* they are attached to. So we should translate those def-ids
* to refer to the new, cloned copy of the type parameter.
* We only see references to free type parameters in the body of
* an inlined function. In such cases, we need the def-id to
* be a local id so that the TypeContents code is able to lookup
* the relevant info in the ty_param_defs table.
*
* *Region parameters*, unfortunately, are another kettle of fish.
* In such cases, def_id's can appear in types to distinguish
* shadowed bound regions and so forth. It doesn't actually
* matter so much what we do to these, since regions are erased
* at trans time, but it's good to keep them consistent just in
* case. We translate them with `tr_def_id()` which will map
* the crate numbers back to the original source crate.
*
* It'd be really nice to refactor the type repr to not include
* def-ids so that all these distinctions were unnecessary.
*/
let r = match source {
NominalType | TypeWithId => xcx.tr_def_id(did),
NominalType | TypeWithId | RegionParameter => xcx.tr_def_id(did),
TypeParameter => xcx.tr_intern_def_id(did)
};
debug!("convert_def_id(source={:?}, did={:?})={:?}", source, did, r);

View File

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

View File

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

View File

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

View File

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

View File

@ -173,35 +173,30 @@ impl Subst for ty::Generics {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Generics {
ty::Generics {
type_param_defs: self.type_param_defs.subst(tcx, substs),
region_param: self.region_param
region_param_defs: self.region_param_defs.subst(tcx, substs),
}
}
}
impl Subst for ty::RegionParameterDef {
fn subst(&self, _: ty::ctxt, _: &ty::substs) -> ty::RegionParameterDef {
*self
}
}
impl Subst for ty::Region {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Region {
// Note: This routine only handles the self region, because it
// is only concerned with substitutions of regions that appear
// in types. Region substitution of the bound regions that
// appear in a function signature is done using the
// specialized routine
fn subst(&self, _tcx: ty::ctxt, substs: &ty::substs) -> ty::Region {
// Note: This routine only handles regions that are bound on
// type declarationss and other outer declarations, not those
// bound in *fn types*. Region substitution of the bound
// regions that appear in a function signature is done using
// the specialized routine
// `middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig()`.
// As we transition to the new region syntax this distinction
// will most likely disappear.
match self {
&ty::re_bound(ty::br_self) => {
&ty::re_type_bound(_, i, _) => {
match substs.regions {
ty::ErasedRegions => ty::re_static,
ty::NonerasedRegions(ref regions) => {
if regions.len() != 1 {
tcx.sess.bug(
format!("ty::Region\\#subst(): \
Reference to self region when \
given substs with no self region: {}",
substs.repr(tcx)));
}
*regions.get(0)
}
ty::NonerasedRegions(ref regions) => *regions.get(i),
}
}
_ => *self

View File

@ -436,14 +436,17 @@ pub struct ClosureTy {
* Signature of a function type, which I have arbitrarily
* decided to use to refer to the input/output types.
*
* - `lifetimes` is the list of region names bound in this fn.
* - `binder_id` is the node id where this fn type appeared;
* it is used to identify all the bound regions appearing
* in the input/output types that are bound by this fn type
* (vs some enclosing or enclosed fn type)
* - `inputs` is the list of arguments and their modes.
* - `output` is the return type.
* - `variadic` indicates whether this is a varidic function. (only true for foreign fns)
*/
#[deriving(Clone, Eq, IterBytes)]
pub struct FnSig {
bound_lifetime_names: OptVec<ast::Ident>,
binder_id: ast::NodeId,
inputs: ~[t],
output: t,
variadic: bool
@ -458,16 +461,13 @@ pub struct param_ty {
/// Representation of regions:
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
pub enum Region {
/// Bound regions are found (primarily) in function types. They indicate
/// region parameters that have yet to be replaced with actual regions
/// (analogous to type parameters, except that due to the monomorphic
/// nature of our type system, bound type parameters are always replaced
/// with fresh type variables whenever an item is referenced, so type
/// parameters only appear "free" in types. Regions in contrast can
/// appear free or bound.). When a function is called, all bound regions
/// tied to that function's node-id are replaced with fresh region
/// variables whose value is then inferred.
re_bound(bound_region),
// Region bound in a type declaration (type/enum/struct/trait),
// which will be substituted when an instance of the type is accessed
re_type_bound(/* param id */ ast::NodeId, /*index*/ uint, ast::Ident),
// Region bound in a fn scope, which will be substituted when the
// fn is called.
re_fn_bound(/* binder_id */ ast::NodeId, bound_region),
/// When checking a function body, the types of all arguments and so forth
/// that refer to bound region parameters are modified to refer to free
@ -496,42 +496,32 @@ pub enum Region {
impl Region {
pub fn is_bound(&self) -> bool {
match self {
&re_bound(*) => true,
&ty::re_type_bound(*) => true,
&ty::re_fn_bound(*) => true,
_ => false
}
}
}
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
#[deriving(Clone, Eq, TotalOrd, TotalEq, IterBytes, Encodable, Decodable, ToStr)]
pub struct FreeRegion {
scope_id: NodeId,
bound_region: bound_region
}
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
#[deriving(Clone, Eq, TotalEq, TotalOrd, IterBytes, Encodable, Decodable, ToStr)]
pub enum bound_region {
/// The self region for structs, impls (&T in a type defn or &'self T)
br_self,
/// An anonymous region parameter for a given fn (&T)
br_anon(uint),
/// Named region parameters for functions (a in &'a T)
br_named(ast::Ident),
///
/// The def-id is needed to distinguish free regions in
/// the event of shadowing.
br_named(ast::DefId, ast::Ident),
/// Fresh bound identifiers created during GLB computations.
br_fresh(uint),
/**
* Handles capture-avoiding substitution in a rather subtle case. If you
* have a closure whose argument types are being inferred based on the
* expected type, and the expected type includes bound regions, then we
* will wrap those bound regions in a br_cap_avoid() with the id of the
* fn expression. This ensures that the names are not "captured" by the
* enclosing scope, which may define the same names. For an example of
* where this comes up, see src/test/compile-fail/regions-ret-borrowed.rs
* and regions-ret-borrowed-1.rs. */
br_cap_avoid(ast::NodeId, @bound_region),
}
/**
@ -868,12 +858,21 @@ pub struct TypeParameterDef {
bounds: @ParamBounds
}
/// Information about the type/lifetime parametesr associated with an item.
#[deriving(Encodable, Decodable, Clone)]
pub struct RegionParameterDef {
ident: ast::Ident,
def_id: ast::DefId,
}
/// Information about the type/lifetime parameters associated with an item.
/// Analogous to ast::Generics.
#[deriving(Clone)]
pub struct Generics {
/// List of type parameters declared on the item.
type_param_defs: @~[TypeParameterDef],
region_param: Option<region_variance>,
/// List of region parameters declared on the item.
region_param_defs: @[RegionParameterDef],
}
impl Generics {
@ -882,6 +881,33 @@ impl Generics {
}
}
/// When type checking, we use the `ParameterEnvironment` to track
/// details about the type/lifetime parameters that are in scope.
/// It primarily stores the bounds information.
///
/// Note: This information might seem to be redundant with the data in
/// `tcx.ty_param_defs`, but it is not. That table contains the
/// parameter definitions from an "outside" perspective, but this
/// struct will contain the bounds for a parameter as seen from inside
/// the function body. Currently the only real distinction is that
/// bound lifetime parameters are replaced with free ones, but in the
/// future I hope to refine the representation of types so as to make
/// more distinctions clearer.
pub struct ParameterEnvironment {
/// A substitution that can be applied to move from
/// the "outer" view of a type or method to the "inner" view.
/// In general, this means converting from bound parameters to
/// free parameters. Since we currently represent bound/free type
/// parameters in the same way, this only has an affect on regions.
free_substs: ty::substs,
/// Bound on the Self parameter
self_param_bound: Option<@TraitRef>,
/// Bounds on each numbered type parameter
type_param_bounds: ~[ParamBounds],
}
/// A polytype.
///
/// - `bounds`: The list of bounds for each type parameter. The length of the
@ -1255,14 +1281,17 @@ pub fn mk_bare_fn(cx: ctxt, fty: BareFnTy) -> t {
mk_t(cx, ty_bare_fn(fty))
}
pub fn mk_ctor_fn(cx: ctxt, input_tys: &[ty::t], output: ty::t) -> t {
pub fn mk_ctor_fn(cx: ctxt,
binder_id: ast::NodeId,
input_tys: &[ty::t],
output: ty::t) -> t {
let input_args = input_tys.map(|t| *t);
mk_bare_fn(cx,
BareFnTy {
purity: ast::impure_fn,
abis: AbiSet::Rust(),
sig: FnSig {
bound_lifetime_names: opt_vec::Empty,
binder_id: binder_id,
inputs: input_args,
output: output,
variadic: false
@ -4662,3 +4691,79 @@ pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: @str) -> u64 {
hash.result_u64()
}
pub fn construct_parameter_environment(
tcx: ctxt,
self_bound: Option<@TraitRef>,
item_type_params: &[TypeParameterDef],
method_type_params: &[TypeParameterDef],
item_region_params: &[RegionParameterDef],
free_id: ast::NodeId)
-> ParameterEnvironment
{
/*! See `ParameterEnvironment` struct def'n for details */
//
// Construct the free substs.
//
// map Self => Self
let self_ty = self_bound.map(|t| ty::mk_self(tcx, t.def_id));
// map A => A
let num_item_type_params = item_type_params.len();
let num_method_type_params = method_type_params.len();
let num_type_params = num_item_type_params + num_method_type_params;
let type_params = vec::from_fn(num_type_params, |i| {
let def_id = if i < num_item_type_params {
item_type_params[i].def_id
} else {
method_type_params[i - num_item_type_params].def_id
};
ty::mk_param(tcx, i, def_id)
});
// map bound 'a => free 'a
let region_params = item_region_params.iter().
map(|r| ty::re_free(ty::FreeRegion {
scope_id: free_id,
bound_region: ty::br_named(r.def_id, r.ident)})).
collect();
let free_substs = substs {
self_ty: self_ty,
tps: type_params,
regions: ty::NonerasedRegions(region_params)
};
//
// Compute the bounds on Self and the type parameters.
//
let self_bound_substd = self_bound.map(|b| b.subst(tcx, &free_substs));
let type_param_bounds_substd = vec::from_fn(num_type_params, |i| {
if i < num_item_type_params {
(*item_type_params[i].bounds).subst(tcx, &free_substs)
} else {
let j = i - num_item_type_params;
(*method_type_params[j].bounds).subst(tcx, &free_substs)
}
});
ty::ParameterEnvironment {
free_substs: free_substs,
self_param_bound: self_bound_substd,
type_param_bounds: type_param_bounds_substd,
}
}
impl substs {
pub fn empty() -> substs {
substs {
self_ty: None,
tps: ~[],
regions: NonerasedRegions(opt_vec::Empty)
}
}
}

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

View File

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

View File

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

View File

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

View File

@ -10,155 +10,41 @@
// #[warn(deprecated_mode)];
use middle::ty;
use middle::typeck::isr_alist;
use util::common::indenter;
use util::ppaux::region_to_str;
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
use std::hashmap::HashMap;
use util::ppaux::Repr;
use util::ppaux;
use extra::list::Cons;
// Helper functions related to manipulating region types.
pub fn replace_bound_regions_in_fn_sig(
tcx: ty::ctxt,
isr: isr_alist,
opt_self_ty: Option<ty::t>,
fn_sig: &ty::FnSig,
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) }
debug!("replace_bound_regions_in_fn_sig(self_ty={:?}, fn_sig={}, \
all_tys={:?})",
opt_self_ty.map(|t| ppaux::ty_to_str(tcx, t)),
ppaux::fn_sig_to_str(tcx, fn_sig),
all_tys.map(|t| ppaux::ty_to_str(tcx, *t)));
let _i = indenter();
let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| {
debug!("br={:?}", br);
mapf(br)
let mut map = HashMap::new();
let (fn_sig, opt_self_ty) = {
let mut f = ty_fold::RegionFolder::regions(tcx, |r| {
debug!("region r={}", r.to_str());
match r {
ty::re_fn_bound(s, br) if s == fn_sig.binder_id => {
*map.find_or_insert_with(br, |_| mapf(br))
}
_ => r
}});
(ty_fold::super_fold_sig(&mut f, fn_sig),
ty_fold::fold_opt_ty(&mut f, opt_self_ty))
};
let new_fn_sig = ty::fold_sig(fn_sig, |t| {
replace_bound_regions(tcx, isr, t)
});
let new_self_ty = opt_self_ty.map(|t| replace_bound_regions(tcx, isr, t));
debug!("result of replace_bound_regions_in_fn_sig: \
new_self_ty={:?}, \
fn_sig={}",
new_self_ty.map(|t| ppaux::ty_to_str(tcx, t)),
ppaux::fn_sig_to_str(tcx, &new_fn_sig));
return (isr, new_self_ty, new_fn_sig);
// Takes `isr`, a (possibly empty) mapping from in-scope region
// names ("isr"s) to their corresponding regions; `tys`, a list of
// types, and `to_r`, a closure that takes a bound_region and
// returns a region. Returns an updated version of `isr`,
// extended with the in-scope region names from all of the bound
// regions appearing in the types in the `tys` list (if they're
// not in `isr` already), with each of those in-scope region names
// mapped to a region that's the result of applying `to_r` to
// itself.
fn create_bound_region_mapping(
tcx: ty::ctxt,
isr: isr_alist,
tys: ~[ty::t],
to_r: &fn(ty::bound_region) -> ty::Region) -> isr_alist {
// Takes `isr` (described above), `to_r` (described above),
// and `r`, a region. If `r` is anything other than a bound
// region, or if it's a bound region that already appears in
// `isr`, then we return `isr` unchanged. If `r` is a bound
// region that doesn't already appear in `isr`, we return an
// updated isr_alist that now contains a mapping from `r` to
// the result of calling `to_r` on it.
fn append_isr(isr: isr_alist,
to_r: &fn(ty::bound_region) -> ty::Region,
r: ty::Region) -> isr_alist {
match r {
ty::re_empty | ty::re_free(*) | ty::re_static | ty::re_scope(_) |
ty::re_infer(_) => {
isr
}
ty::re_bound(br) => {
match isr.find(br) {
Some(_) => isr,
None => @Cons((br, to_r(br)), isr)
}
}
}
}
// For each type `ty` in `tys`...
do tys.iter().fold(isr) |isr, ty| {
let mut isr = isr;
// Using fold_regions is inefficient, because it
// constructs new types, but it avoids code duplication in
// terms of locating all the regions within the various
// kinds of types. This had already caused me several
// bugs so I decided to switch over.
do ty::fold_regions(tcx, *ty) |r, in_fn| {
if !in_fn { isr = append_isr(isr, |br| to_r(br), r); }
r
};
isr
}
}
// Takes `isr`, a mapping from in-scope region names ("isr"s) to
// their corresponding regions; and `ty`, a type. Returns an
// updated version of `ty`, in which bound regions in `ty` have
// been replaced with the corresponding bindings in `isr`.
fn replace_bound_regions(
tcx: ty::ctxt,
isr: isr_alist,
ty: ty::t) -> ty::t {
do ty::fold_regions(tcx, ty) |r, in_fn| {
let r1 = match r {
// As long as we are not within a fn() type, `&T` is
// mapped to the free region anon_r. But within a fn
// type, it remains bound.
ty::re_bound(ty::br_anon(_)) if in_fn => r,
ty::re_bound(br) => {
match isr.find(br) {
// In most cases, all named, bound regions will be
// mapped to some free region.
Some(fr) => fr,
// But in the case of a fn() type, there may be
// named regions within that remain bound:
None if in_fn => r,
None => {
tcx.sess.bug(
format!("Bound region not found in \
in_scope_regions list: {}",
region_to_str(tcx, "", false, r)));
}
}
}
// Free regions like these just stay the same:
ty::re_empty |
ty::re_static |
ty::re_scope(_) |
ty::re_free(*) |
ty::re_infer(_) => r
};
r1
}
}
debug!("resulting map: {}", map.to_str());
(map, opt_self_ty, fn_sig)
}
pub fn relate_nested_regions(
@ -168,7 +54,6 @@ pub fn relate_nested_regions(
relate_op: &fn(ty::Region, ty::Region))
{
/*!
*
* This rather specialized function walks each region `r` that appear
* in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl`
* here is the region of any enclosing `&'r T` pointer. If there is
@ -194,41 +79,66 @@ pub fn relate_nested_regions(
* Hence, in the second example above, `'r2` must be a subregion of `'r3`.
*/
let mut the_stack = ~[];
for &r in opt_region.iter() { the_stack.push(r); }
walk_ty(tcx, &mut the_stack, ty, relate_op);
let mut rr = RegionRelator { tcx: tcx,
stack: ~[],
relate_op: relate_op };
match opt_region {
Some(o_r) => { rr.stack.push(o_r); }
None => {}
}
rr.fold_ty(ty);
fn walk_ty(tcx: ty::ctxt,
the_stack: &mut ~[ty::Region],
ty: ty::t,
relate_op: &fn(ty::Region, ty::Region))
{
match ty::get(ty).sty {
ty::ty_rptr(r, ref mt) |
ty::ty_evec(ref mt, ty::vstore_slice(r)) => {
relate(*the_stack, r, |x,y| relate_op(x,y));
the_stack.push(r);
walk_ty(tcx, the_stack, mt.ty, |x,y| relate_op(x,y));
the_stack.pop();
}
_ => {
ty::fold_regions_and_ty(
tcx,
ty,
|r| { relate( *the_stack, r, |x,y| relate_op(x,y)); r },
|t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t },
|t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t });
struct RegionRelator<'self> {
tcx: ty::ctxt,
stack: ~[ty::Region],
relate_op: &'self fn(ty::Region, ty::Region),
}
// FIXME we should define more precisely when a
// region is considered "nested" and take variance into account.
//
// I can't decide whether skipping closure parameter types and
// so on is necessary or not. What is the difference, after all,
// between `&'a |&'b T|` and `&'a Fn<&'b T>`? And yet in the
// latter case I'm inclined to think we should probably track
// the relationship (but then again maybe we should just skip
// all such cases until it "proves necessary")
impl<'self> TypeFolder for RegionRelator<'self> {
fn tcx(&self) -> ty::ctxt {
self.tcx
}
fn fold_ty(&mut self, ty: ty::t) -> ty::t {
match ty::get(ty).sty {
ty::ty_rptr(r, ref mt) |
ty::ty_evec(ref mt, ty::vstore_slice(r)) => {
self.relate(r);
self.stack.push(r);
ty_fold::super_fold_ty(self, mt.ty);
self.stack.pop();
}
_ => {
ty_fold::super_fold_ty(self, ty);
}
}
ty
}
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
self.relate(r);
r
}
}
fn relate(the_stack: &[ty::Region],
r_sub: ty::Region,
relate_op: &fn(ty::Region, ty::Region))
{
for &r in the_stack.iter() {
if !r.is_bound() && !r_sub.is_bound() {
relate_op(r, r_sub);
impl<'self> RegionRelator<'self> {
fn relate(&mut self, r_sub: ty::Region) {
for &r in self.stack.iter() {
if !r.is_bound() && !r_sub.is_bound() {
(self.relate_op)(r, r_sub);
}
}
}
}

View File

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

View File

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

View File

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

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)));
}
do argvecs(this, a.inputs, b.inputs)
.and_then |inputs| {
do this.tys(a.output, b.output).and_then |output| {
Ok(FnSig {
bound_lifetime_names: opt_vec::Empty, // FIXME(#4846)
inputs: inputs.clone(),
output: output,
variadic: a.variadic
})
}
}
let inputs = if_ok!(argvecs(this, a.inputs, b.inputs));
let output = if_ok!(this.tys(a.output, b.output));
Ok(FnSig {binder_id: a.binder_id,
inputs: inputs,
output: output,
variadic: a.variadic})
}
pub fn super_tys<C:Combine>(
this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
let tcx = this.infcx().tcx;
return match (&ty::get(a).sty, &ty::get(b).sty) {
let a_sty = &ty::get(a).sty;
let b_sty = &ty::get(b).sty;
debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
return match (a_sty, b_sty) {
// The "subtype" ought to be handling cases involving bot or var:
(&ty::ty_bot, _) |
(_, &ty::ty_bot) |
@ -494,6 +491,7 @@ pub fn super_tys<C:Combine>(
unify_float_variable(this, !this.a_is_expected(), v_id, v)
}
(&ty::ty_char, _) |
(&ty::ty_nil, _) |
(&ty::ty_bool, _) |
(&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::{TypeTrace, Subtype};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::isr_alist;
use syntax::ast::{Many, Once, extern_fn, impure_fn, MutImmutable, MutMutable};
use syntax::ast::{unsafe_fn};
use syntax::ast::{unsafe_fn, NodeId};
use syntax::ast::{Onceness, purity};
use std::hashmap::HashMap;
use util::common::{indenter};
use util::ppaux::mt_to_str;
use extra::list;
pub struct Glb(CombineFields); // "greatest lower bound" (common subtype)
impl Combine for Glb {
@ -132,14 +130,14 @@ impl Combine for Glb {
let snapshot = self.infcx.region_vars.start_snapshot();
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_isr) =
let (a_with_fresh, a_map) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.trace, a);
let a_vars = var_ids(self, a_isr);
let (b_with_fresh, b_isr) =
let a_vars = var_ids(self, &a_map);
let (b_with_fresh, b_map) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.trace, b);
let b_vars = var_ids(self, b_isr);
let b_vars = var_ids(self, &b_map);
// Collect constraints.
let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
@ -152,20 +150,23 @@ impl Combine for Glb {
fold_regions_in_sig(
self.infcx.tcx,
&sig0,
|r, _in_fn| generalize_region(self, snapshot,
new_vars, a_isr, a_vars, b_vars,
r));
|r| generalize_region(self, snapshot,
new_vars, sig0.binder_id,
&a_map, a_vars, b_vars,
r));
debug!("sig1 = {}", sig1.inf_str(self.infcx));
return Ok(sig1);
fn generalize_region(this: &Glb,
snapshot: uint,
new_vars: &[RegionVid],
a_isr: isr_alist,
new_binder_id: NodeId,
a_map: &HashMap<ty::bound_region, ty::Region>,
a_vars: &[RegionVid],
b_vars: &[RegionVid],
r0: ty::Region) -> ty::Region {
if !is_var_in_set(new_vars, r0) {
assert!(!r0.is_bound());
return r0;
}
@ -177,13 +178,13 @@ impl Combine for Glb {
for r in tainted.iter() {
if is_var_in_set(a_vars, *r) {
if a_r.is_some() {
return fresh_bound_variable(this);
return fresh_bound_variable(this, new_binder_id);
} else {
a_r = Some(*r);
}
} else if is_var_in_set(b_vars, *r) {
if b_r.is_some() {
return fresh_bound_variable(this);
return fresh_bound_variable(this, new_binder_id);
} else {
b_r = Some(*r);
}
@ -192,57 +193,57 @@ impl Combine for Glb {
}
}
// NB---I do not believe this algorithm computes
// (necessarily) the GLB. As written it can
// spuriously fail. In particular, if there is a case
// like: &fn(fn(&a)) and fn(fn(&b)), where a and b are
// free, it will return fn(&c) where c = GLB(a,b). If
// however this GLB is not defined, then the result is
// an error, even though something like
// "fn<X>(fn(&X))" where X is bound would be a
// subtype of both of those.
//
// The problem is that if we were to return a bound
// variable, we'd be computing a lower-bound, but not
// necessarily the *greatest* lower-bound.
// NB---I do not believe this algorithm computes
// (necessarily) the GLB. As written it can
// spuriously fail. In particular, if there is a case
// like: &fn(fn(&a)) and fn(fn(&b)), where a and b are
// free, it will return fn(&c) where c = GLB(a,b). If
// however this GLB is not defined, then the result is
// an error, even though something like
// "fn<X>(fn(&X))" where X is bound would be a
// subtype of both of those.
//
// The problem is that if we were to return a bound
// variable, we'd be computing a lower-bound, but not
// necessarily the *greatest* lower-bound.
//
// Unfortunately, this problem is non-trivial to solve,
// because we do not know at the time of computing the GLB
// whether a GLB(a,b) exists or not, because we haven't
// run region inference (or indeed, even fully computed
// the region hierarchy!). The current algorithm seems to
// works ok in practice.
if a_r.is_some() && b_r.is_some() && only_new_vars {
// Related to exactly one bound variable from each fn:
return rev_lookup(this, a_isr, a_r.unwrap());
return rev_lookup(this, a_map, new_binder_id, a_r.unwrap());
} else if a_r.is_none() && b_r.is_none() {
// Not related to bound variables from either fn:
assert!(!r0.is_bound());
return r0;
} else {
// Other:
return fresh_bound_variable(this);
return fresh_bound_variable(this, new_binder_id);
}
}
fn rev_lookup(this: &Glb,
a_isr: isr_alist,
a_map: &HashMap<ty::bound_region, ty::Region>,
new_binder_id: NodeId,
r: ty::Region) -> ty::Region
{
let mut ret = None;
do list::each(a_isr) |pair| {
let (a_br, a_r) = *pair;
if a_r == r {
ret = Some(ty::re_bound(a_br));
false
} else {
true
for (a_br, a_r) in a_map.iter() {
if *a_r == r {
return ty::re_fn_bound(new_binder_id, *a_br);
}
};
match ret {
Some(x) => x,
None => this.infcx.tcx.sess.span_bug(
this.trace.origin.span(),
format!("could not find original bound region for {:?}", r))
}
this.infcx.tcx.sess.span_bug(
this.trace.origin.span(),
format!("could not find original bound region for {:?}", r))
}
fn fresh_bound_variable(this: &Glb) -> ty::Region {
this.infcx.region_vars.new_bound()
fn fresh_bound_variable(this: &Glb, binder_id: NodeId) -> ty::Region {
this.infcx.region_vars.new_bound(binder_id)
}
}
}

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,10 +11,10 @@
use metadata::encoder;
use middle::ty::{ReSkolemized, ReVar};
use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid};
use middle::ty::{bound_region, br_anon, br_named};
use middle::ty::{br_fresh, ctxt, field};
use middle::ty::{mt, t, param_ty};
use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region,
use middle::ty::{re_free, re_scope, re_infer, re_static, Region,
re_empty};
use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure};
@ -118,6 +118,11 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region)
let (msg, opt_span) = explain_span(cx, "block", blk.span);
(format!("{} {}", prefix, msg), opt_span)
}
Some(&ast_map::node_item(it, _)) if match it.node {
ast::item_impl(*) => true, _ => false} => {
let (msg, opt_span) = explain_span(cx, "impl", it.span);
(format!("{} {}", prefix, msg), opt_span)
}
Some(_) | None => {
// this really should not happen
(format!("{} node {}", prefix, fr.scope_id), None)
@ -131,7 +136,7 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region)
// I believe these cases should not occur (except when debugging,
// perhaps)
re_infer(_) | re_bound(_) => {
ty::re_infer(_) | ty::re_type_bound(*) | ty::re_fn_bound(*) => {
(format!("lifetime {:?}", region), None)
}
};
@ -154,14 +159,15 @@ pub fn bound_region_to_str(cx: ctxt,
br: bound_region) -> ~str {
let space_str = if space { " " } else { "" };
if cx.sess.verbose() { return format!("{}{:?}{}", prefix, br, space_str); }
if cx.sess.verbose() {
return format!("{}{}{}", prefix, br.repr(cx), space_str);
}
match br {
br_named(id) => format!("{}'{}{}", prefix, cx.sess.str_of(id), space_str),
br_self => format!("{}'self{}", prefix, space_str),
br_named(_, ident) => format!("{}'{}{}", prefix,
cx.sess.str_of(ident), space_str),
br_anon(_) => prefix.to_str(),
br_fresh(_) => prefix.to_str(),
br_cap_avoid(_, br) => bound_region_to_str(cx, prefix, space, *br)
}
}
@ -215,7 +221,7 @@ pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~st
let space_str = if space { " " } else { "" };
if cx.sess.verbose() {
return format!("{}{:?}{}", prefix, region, space_str);
return format!("{}{}{}", prefix, region.repr(cx), space_str);
}
// These printouts are concise. They do not contain all the information
@ -223,15 +229,16 @@ pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~st
// to fit that into a short string. Hence the recommendation to use
// `explain_region()` or `note_and_explain_region()`.
match region {
re_scope(_) => prefix.to_str(),
re_bound(br) => bound_region_to_str(cx, prefix, space, br),
re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region),
re_infer(ReSkolemized(_, br)) => {
ty::re_scope(_) => prefix.to_str(),
ty::re_type_bound(_, _, ident) => cx.sess.str_of(ident).to_owned(),
ty::re_fn_bound(_, br) => bound_region_to_str(cx, prefix, space, br),
ty::re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region),
ty::re_infer(ReSkolemized(_, br)) => {
bound_region_to_str(cx, prefix, space, br)
}
re_infer(ReVar(_)) => prefix.to_str(),
re_static => format!("{}'static{}", prefix, space_str),
re_empty => format!("{}'<empty>{}", prefix, space_str)
ty::re_infer(ReVar(_)) => prefix.to_str(),
ty::re_static => format!("{}'static{}", 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 {
format!("fn{} -> {}",
tys_to_str(cx, typ.inputs.map(|a| *a)),
ty_to_str(cx, typ.output))
format!("fn{}{} -> {}",
typ.binder_id,
typ.inputs.repr(cx),
typ.output.repr(cx))
}
pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str {
@ -594,8 +602,17 @@ impl<T:Repr> Repr for ~[T] {
impl Repr for ty::TypeParameterDef {
fn repr(&self, tcx: ctxt) -> ~str {
format!("TypeParameterDef \\{{:?}, bounds: {}\\}",
self.def_id, self.bounds.repr(tcx))
format!("TypeParameterDef({:?}, {})",
self.def_id,
self.bounds.repr(tcx))
}
}
impl Repr for ty::RegionParameterDef {
fn repr(&self, tcx: ctxt) -> ~str {
format!("RegionParameterDef({}, {:?})",
tcx.sess.str_of(self.ident),
self.def_id)
}
}
@ -655,6 +672,15 @@ impl Repr for ast::Expr {
}
}
impl Repr for ast::item {
fn repr(&self, tcx: ctxt) -> ~str {
format!("item({})",
ast_map::node_id_to_str(tcx.items,
self.id,
token::get_ident_interner()))
}
}
impl Repr for ast::Pat {
fn repr(&self, tcx: ctxt) -> ~str {
format!("pat({}: {})",
@ -665,13 +691,56 @@ impl Repr for ast::Pat {
impl Repr for ty::bound_region {
fn repr(&self, tcx: ctxt) -> ~str {
bound_region_ptr_to_str(tcx, *self)
match *self {
ty::br_anon(id) => format!("br_anon({})", id),
ty::br_named(id, ident) => format!("br_named({}, {})",
id.repr(tcx),
ident.repr(tcx)),
ty::br_fresh(id) => format!("br_fresh({})", id),
}
}
}
impl Repr for ty::Region {
fn repr(&self, tcx: ctxt) -> ~str {
region_to_str(tcx, "", false, *self)
match *self {
ty::re_type_bound(id, index, ident) => {
format!("re_type_bound({}, {}, {})",
id, index, ident.repr(tcx))
}
ty::re_fn_bound(binder_id, ref bound_region) => {
format!("re_fn_bound({}, {})",
binder_id, bound_region.repr(tcx))
}
ty::re_free(ref fr) => {
format!("re_free({}, {})",
fr.scope_id,
fr.bound_region.repr(tcx))
}
ty::re_scope(id) => {
format!("re_scope({})", id)
}
ty::re_static => {
format!("re_static")
}
ty::re_infer(ReVar(ref vid)) => {
format!("re_infer({})", vid.id)
}
ty::re_infer(ReSkolemized(id, ref bound_region)) => {
format!("re_skolemized({}, {})",
id, bound_region.repr(tcx))
}
ty::re_empty => {
format!("re_empty")
}
}
}
}
@ -707,23 +776,38 @@ impl Repr for ty::ty_param_bounds_and_ty {
impl Repr for ty::Generics {
fn repr(&self, tcx: ctxt) -> ~str {
format!("Generics \\{type_param_defs: {}, region_param: {:?}\\}",
self.type_param_defs.repr(tcx),
self.region_param)
format!("Generics(type_param_defs: {}, region_param_defs: {})",
self.type_param_defs.repr(tcx),
self.region_param_defs.repr(tcx))
}
}
impl Repr for ty::ItemVariances {
fn repr(&self, tcx: ctxt) -> ~str {
format!("IterVariances(self_param={}, type_params={}, region_params={})",
self.self_param.repr(tcx),
self.type_params.repr(tcx),
self.region_params.repr(tcx))
}
}
impl Repr for ty::Variance {
fn repr(&self, _: ctxt) -> ~str {
self.to_str().to_owned()
}
}
impl Repr for ty::Method {
fn repr(&self, tcx: ctxt) -> ~str {
format!("method \\{ident: {}, generics: {}, transformed_self_ty: {}, \
fty: {}, explicit_self: {}, vis: {}, def_id: {}\\}",
self.ident.repr(tcx),
self.generics.repr(tcx),
self.transformed_self_ty.repr(tcx),
self.fty.repr(tcx),
self.explicit_self.repr(tcx),
self.vis.repr(tcx),
self.def_id.repr(tcx))
format!("method(ident: {}, generics: {}, transformed_self_ty: {}, \
fty: {}, explicit_self: {}, vis: {}, def_id: {})",
self.ident.repr(tcx),
self.generics.repr(tcx),
self.transformed_self_ty.repr(tcx),
self.fty.repr(tcx),
self.explicit_self.repr(tcx),
self.vis.repr(tcx),
self.def_id.repr(tcx))
}
}

View File

@ -835,7 +835,7 @@ impl Clean<Path> for ast::Path {
#[deriving(Clone, Encodable, Decodable)]
pub struct PathSegment {
name: ~str,
lifetime: Option<Lifetime>,
lifetimes: ~[Lifetime],
types: ~[Type],
}
@ -843,7 +843,7 @@ impl Clean<PathSegment> for ast::PathSegment {
fn clean(&self) -> PathSegment {
PathSegment {
name: self.identifier.clean(),
lifetime: self.lifetime.clean(),
lifetimes: self.lifetimes.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()) }
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());
match seg.lifetime {
Some(ref lifetime) => write!(f.buf, "{}", *lifetime),
None => {}
let mut comma = false;
for lifetime in seg.lifetimes.iter() {
if comma { f.buf.write(", ".as_bytes()); }
comma = true;
write!(f.buf, "{}", *lifetime);
}
for (i, ty) in seg.types.iter().enumerate() {
if i > 0 || seg.lifetime.is_some() {
f.buf.write(", ".as_bytes());
}
for ty in seg.types.iter() {
if comma { f.buf.write(", ".as_bytes()); }
comma = true;
write!(f.buf, "{}", *ty);
}
f.buf.write("&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
let mut generics = ~"";
let last = path.segments.last();
if last.lifetime.is_some() || last.types.len() > 0 {
if last.lifetimes.len() > 0 || last.types.len() > 0 {
let mut counter = 0;
generics.push_str("&lt;");
match last.lifetime {
Some(ref lifetime) => generics.push_str(format!("{}", *lifetime)),
None => {}
for lifetime in last.lifetimes.iter() {
if counter > 0 { generics.push_str(", "); }
counter += 1;
generics.push_str(format!("{}", *lifetime));
}
for (i, ty) in last.types.iter().enumerate() {
if i > 0 || last.lifetime.is_some() {
generics.push_str(", ");
}
for ty in last.types.iter() {
if counter > 0 { generics.push_str(", "); }
counter += 1;
generics.push_str(format!("{}", *ty));
}
generics.push_str("&gt;");
@ -495,7 +497,7 @@ impl fmt::Default for clean::ViewListIdent {
global: false,
segments: ~[clean::PathSegment {
name: v.name.clone(),
lifetime: None,
lifetimes: ~[],
types: ~[],
}]
};

View File

@ -12,7 +12,7 @@
use clone::Clone;
use container::Container;
use iter::Iterator;
use iter::{Iterator, FromIterator};
use option::{Option, Some, None};
use mem;
use unstable::raw::Repr;
@ -134,6 +134,17 @@ impl<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))]
#[allow(missing_doc)]
pub mod traits {

View File

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

View File

@ -488,3 +488,15 @@ pub fn node_item_query<Result>(items: map, id: NodeId,
_ => fail!("{}", error_msg)
}
}
pub fn item_span(items: map,
id: ast::NodeId)
-> Span {
match items.find(&id) {
Some(&node_item(item, _)) => item.span,
r => {
fail!(format!("item_span: expected item with id {} but found {:?}",
id, r))
}
}
}

View File

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

View File

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

View File

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

View File

@ -375,14 +375,10 @@ impl<'self> TraitDef<'self> {
cx.ty_ident(trait_span, ty_param.ident)
};
let self_lifetime = if generics.lifetimes.is_empty() {
None
} else {
Some(*generics.lifetimes.get(0))
};
let self_lifetimes = generics.lifetimes.clone();
// Create the type of `self`.
let self_type = cx.ty_path(cx.path_all(trait_span, false, ~[ type_ident ], self_lifetime,
let self_type = cx.ty_path(cx.path_all(trait_span, false, ~[ type_ident ], self_lifetimes,
opt_vec::take_vec(self_ty_params)), None);
let doc_attr = cx.attribute(

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -1490,7 +1490,7 @@ impl Parser {
segments.push(PathSegmentAndBoundSet {
segment: ast::PathSegment {
identifier: identifier,
lifetime: None,
lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
},
bound_set: bound_set
@ -1499,46 +1499,21 @@ impl Parser {
}
// Parse the `<` before the lifetime and types, if applicable.
let (any_lifetime_or_types, optional_lifetime, types) =
if mode != NoTypesAllowed && self.eat(&token::LT) {
// Parse an optional lifetime.
let optional_lifetime = match *self.token {
token::LIFETIME(*) => Some(self.parse_lifetime()),
_ => None,
};
// Parse type parameters.
let mut types = opt_vec::Empty;
let mut need_comma = optional_lifetime.is_some();
loop {
// We're done if we see a `>`.
match *self.token {
token::GT | token::BINOP(token::SHR) => {
self.expect_gt();
break
}
_ => {} // Go on.
}
if need_comma {
self.expect(&token::COMMA)
} else {
need_comma = true
}
types.push(self.parse_ty(false))
let (any_lifetime_or_types, lifetimes, types) = {
if mode != NoTypesAllowed && self.eat(&token::LT) {
let (lifetimes, types) =
self.parse_generic_values_after_lt();
(true, lifetimes, opt_vec::from(types))
} else {
(false, opt_vec::Empty, opt_vec::Empty)
}
(true, optional_lifetime, types)
} else {
(false, None, opt_vec::Empty)
};
// Assemble and push the result.
segments.push(PathSegmentAndBoundSet {
segment: ast::PathSegment {
identifier: identifier,
lifetime: optional_lifetime,
lifetimes: lifetimes,
types: types,
},
bound_set: bound_set
@ -1609,11 +1584,11 @@ impl Parser {
pub fn parse_lifetime(&self) -> ast::Lifetime {
match *self.token {
token::LIFETIME(i) => {
let span = self.span;
let span = *self.span;
self.bump();
return ast::Lifetime {
id: ast::DUMMY_NODE_ID,
span: *span,
span: span,
ident: i
};
}
@ -4856,7 +4831,7 @@ impl Parser {
segments: path.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
lifetime: None,
lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
}).collect()
@ -4892,7 +4867,7 @@ impl Parser {
segments: path.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
lifetime: None,
lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
}).collect()
@ -4910,7 +4885,7 @@ impl Parser {
segments: path.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
lifetime: None,
lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
}).collect()
@ -4932,7 +4907,7 @@ impl Parser {
segments: path.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
lifetime: None,
lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
}).collect()

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 {
word(s.s, "::")
}
word(s.s, "<");
for lifetime in segment.lifetime.iter() {
for lifetime in segment.lifetimes.iter() {
print_lifetime(s, lifetime);
if !segment.types.is_empty() {
word_space(s, ",")
@ -1905,7 +1905,8 @@ pub fn print_meta_item(s: @ps, item: &ast::MetaItem) {
pub fn print_view_path(s: @ps, vp: &ast::view_path) {
match vp.node {
ast::view_path_simple(ident, ref path, _) => {
if path.segments.last().identifier != ident {
// FIXME can't compare identifiers directly here
if path.segments.last().identifier.name != ident.name {
print_ident(s, ident);
space(s.s);
word_space(s, "=");