mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 01:04:03 +00:00
Generalize AST and ty::Generics to accept multiple lifetimes.
This commit is contained in:
parent
85c51d3b02
commit
1f4faaee40
@ -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,
|
||||
},
|
||||
],
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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];
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(¶m_ty.def_id.node) {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
tcx.sess.span_bug(
|
||||
self.expr.span,
|
||||
format!("No param def for {:?}", param_ty));
|
||||
}
|
||||
};
|
||||
|
||||
self.push_inherent_candidates_from_bounds(
|
||||
rcvr_ty, type_param_def.bounds.trait_bounds,
|
||||
rcvr_ty,
|
||||
self.fcx.inh.param_env.type_param_bounds[param_ty.idx].trait_bounds,
|
||||
param_numbered(param_ty.idx));
|
||||
}
|
||||
|
||||
|
||||
fn push_inherent_candidates_from_self(&self,
|
||||
self_ty: ty::t,
|
||||
did: DefId) {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref;
|
||||
rcvr_ty: ty::t) {
|
||||
debug!("push_inherent_candidates_from_self()");
|
||||
self.push_inherent_candidates_from_bounds(
|
||||
self_ty, &[trait_ref], param_self);
|
||||
rcvr_ty,
|
||||
[self.fcx.inh.param_env.self_param_bound.unwrap()],
|
||||
param_self)
|
||||
}
|
||||
|
||||
fn push_inherent_candidates_from_bounds(&self,
|
||||
@ -574,10 +558,7 @@ impl<'self> LookupContext<'self> {
|
||||
// determine the `self` of the impl with fresh
|
||||
// variables for each parameter:
|
||||
let location_info = &vtable::location_info_for_expr(self.self_expr);
|
||||
let vcx = VtableContext {
|
||||
ccx: self.fcx.ccx,
|
||||
infcx: self.fcx.infcx()
|
||||
};
|
||||
let vcx = self.fcx.vtable_context();
|
||||
let ty::ty_param_substs_and_ty {
|
||||
substs: impl_substs,
|
||||
ty: impl_ty
|
||||
@ -1010,7 +991,7 @@ impl<'self> LookupContext<'self> {
|
||||
};
|
||||
let (_, opt_transformed_self_ty, fn_sig) =
|
||||
replace_bound_regions_in_fn_sig(
|
||||
tcx, @Nil, Some(transformed_self_ty), &bare_fn_ty.sig,
|
||||
tcx, Some(transformed_self_ty), &bare_fn_ty.sig,
|
||||
|br| self.fcx.infcx().next_region_var(
|
||||
infer::BoundRegionInFnCall(self.expr.span, br)));
|
||||
let transformed_self_ty = opt_transformed_self_ty.unwrap();
|
||||
|
@ -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, ¶m_env.free_substs),
|
||||
self_id: method.self_id,
|
||||
span: method.explicit_self.span}
|
||||
});
|
||||
let fty = ty::node_id_to_type(ccx.tcx, method.id);
|
||||
let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
|
||||
|
||||
check_bare_fn(
|
||||
ccx,
|
||||
&method.decl,
|
||||
&method.body,
|
||||
method.id,
|
||||
opt_self_info,
|
||||
fty,
|
||||
param_env);
|
||||
}
|
||||
|
||||
impl AstConv for FnCtxt {
|
||||
fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
|
||||
|
||||
@ -682,48 +727,26 @@ impl FnCtxt {
|
||||
pub fn infcx(&self) -> @mut infer::InferCtxt {
|
||||
self.inh.infcx
|
||||
}
|
||||
|
||||
pub fn err_count_since_creation(&self) -> uint {
|
||||
self.ccx.tcx.sess.err_count() - self.err_count_on_creation
|
||||
}
|
||||
pub fn search_in_scope_regions(&self,
|
||||
span: Span,
|
||||
br: ty::bound_region)
|
||||
-> Result<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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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, ¶m_env.free_substs);
|
||||
|
||||
// Now, locate the vtable for the impl itself. The real
|
||||
// purpose of this is to check for supertrait impls,
|
||||
// but that falls out of doing this.
|
||||
let param_bounds = ty::ParamBounds {
|
||||
builtin_bounds: ty::EmptyBuiltinBounds(),
|
||||
trait_bounds: ~[trait_ref]
|
||||
};
|
||||
let t = ty::node_id_to_type(ccx.tcx, impl_item.id);
|
||||
debug!("=== Doing a self lookup now.");
|
||||
// Right now, we don't have any place to store this.
|
||||
// We will need to make one so we can use this information
|
||||
// for compiling default methods that refer to supertraits.
|
||||
let self_vtable_res =
|
||||
lookup_vtables_for_param(&vcx, &loc_info, None,
|
||||
¶m_bounds, t, false);
|
||||
let infcx = infer::new_infer_ctxt(ccx.tcx);
|
||||
let vcx = VtableContext { infcx: infcx, param_env: ¶m_env };
|
||||
let loc_info = location_info_for_item(impl_item);
|
||||
|
||||
// First, check that the impl implements any trait bounds
|
||||
// on the trait.
|
||||
let trait_def = ty::lookup_trait_def(ccx.tcx, impl_trait_ref.def_id);
|
||||
let vtbls = lookup_vtables(&vcx,
|
||||
&loc_info,
|
||||
*trait_def.generics.type_param_defs,
|
||||
&impl_trait_ref.substs,
|
||||
false);
|
||||
|
||||
// Now, locate the vtable for the impl itself. The real
|
||||
// purpose of this is to check for supertrait impls,
|
||||
// but that falls out of doing this.
|
||||
let param_bounds = ty::ParamBounds {
|
||||
builtin_bounds: ty::EmptyBuiltinBounds(),
|
||||
trait_bounds: ~[impl_trait_ref]
|
||||
};
|
||||
let t = ty::node_id_to_type(ccx.tcx, impl_item.id);
|
||||
let t = t.subst(ccx.tcx, ¶m_env.free_substs);
|
||||
debug!("=== Doing a self lookup now.");
|
||||
|
||||
// Right now, we don't have any place to store this.
|
||||
// We will need to make one so we can use this information
|
||||
// for compiling default methods that refer to supertraits.
|
||||
let self_vtable_res =
|
||||
lookup_vtables_for_param(&vcx, &loc_info, None,
|
||||
¶m_bounds, t, false);
|
||||
|
||||
|
||||
let res = impl_res {
|
||||
trait_vtables: vtbls,
|
||||
self_vtables: self_vtable_res
|
||||
};
|
||||
ccx.tcx.impl_vtables.insert(def_id, res);
|
||||
}
|
||||
}
|
||||
let res = impl_res {
|
||||
trait_vtables: vtbls,
|
||||
self_vtables: self_vtable_res
|
||||
};
|
||||
let impl_def_id = ast_util::local_def(impl_item.id);
|
||||
ccx.tcx.impl_vtables.insert(impl_def_id, res);
|
||||
}
|
||||
|
||||
impl visit::Visitor<()> for @mut FnCtxt {
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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(¶m.id) {
|
||||
Some(&def) => def,
|
||||
None => {
|
||||
let param_ty = ty::param_ty {idx: base_index + offset,
|
||||
def_id: local_def(param.id)};
|
||||
let bounds = @compute_bounds(ccx, rp, generics,
|
||||
param_ty, ¶m.bounds);
|
||||
let bounds = @compute_bounds(ccx, param_ty, ¶m.bounds);
|
||||
let def = ty::TypeParameterDef {
|
||||
ident: param.ident,
|
||||
def_id: local_def(param.id),
|
||||
@ -1234,13 +1172,10 @@ pub fn ty_generics(ccx: &CrateCtxt,
|
||||
|
||||
fn compute_bounds(
|
||||
ccx: &CrateCtxt,
|
||||
rp: Option<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}
|
||||
}
|
||||
|
@ -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(_), _) |
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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()))
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -92,16 +92,17 @@ impl fmt::Default for clean::Path {
|
||||
if i > 0 { f.buf.write("::".as_bytes()) }
|
||||
f.buf.write(seg.name.as_bytes());
|
||||
|
||||
if seg.lifetime.is_some() || seg.types.len() > 0 {
|
||||
if seg.lifetimes.len() > 0 || seg.types.len() > 0 {
|
||||
f.buf.write("<".as_bytes());
|
||||
match seg.lifetime {
|
||||
Some(ref lifetime) => write!(f.buf, "{}", *lifetime),
|
||||
None => {}
|
||||
let mut comma = false;
|
||||
for lifetime in seg.lifetimes.iter() {
|
||||
if comma { f.buf.write(", ".as_bytes()); }
|
||||
comma = true;
|
||||
write!(f.buf, "{}", *lifetime);
|
||||
}
|
||||
for (i, ty) in seg.types.iter().enumerate() {
|
||||
if i > 0 || seg.lifetime.is_some() {
|
||||
f.buf.write(", ".as_bytes());
|
||||
}
|
||||
for ty in seg.types.iter() {
|
||||
if comma { f.buf.write(", ".as_bytes()); }
|
||||
comma = true;
|
||||
write!(f.buf, "{}", *ty);
|
||||
}
|
||||
f.buf.write(">".as_bytes());
|
||||
@ -152,16 +153,17 @@ fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
|
||||
// The generics will get written to both the title and link
|
||||
let mut generics = ~"";
|
||||
let last = path.segments.last();
|
||||
if last.lifetime.is_some() || last.types.len() > 0 {
|
||||
if last.lifetimes.len() > 0 || last.types.len() > 0 {
|
||||
let mut counter = 0;
|
||||
generics.push_str("<");
|
||||
match last.lifetime {
|
||||
Some(ref lifetime) => generics.push_str(format!("{}", *lifetime)),
|
||||
None => {}
|
||||
for lifetime in last.lifetimes.iter() {
|
||||
if counter > 0 { generics.push_str(", "); }
|
||||
counter += 1;
|
||||
generics.push_str(format!("{}", *lifetime));
|
||||
}
|
||||
for (i, ty) in last.types.iter().enumerate() {
|
||||
if i > 0 || last.lifetime.is_some() {
|
||||
generics.push_str(", ");
|
||||
}
|
||||
for ty in last.types.iter() {
|
||||
if counter > 0 { generics.push_str(", "); }
|
||||
counter += 1;
|
||||
generics.push_str(format!("{}", *ty));
|
||||
}
|
||||
generics.push_str(">");
|
||||
@ -495,7 +497,7 @@ impl fmt::Default for clean::ViewListIdent {
|
||||
global: false,
|
||||
segments: ~[clean::PathSegment {
|
||||
name: v.name.clone(),
|
||||
lifetime: None,
|
||||
lifetimes: ~[],
|
||||
types: ~[],
|
||||
}]
|
||||
};
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
]
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) => {
|
||||
|
@ -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: _
|
||||
}
|
||||
]
|
||||
|
@ -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(
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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, "=");
|
||||
|
Loading…
Reference in New Issue
Block a user