auto merge of #10153 : nikomatsakis/rust/issue-4846-multiple-lifetime-parameters-7, r=pnkfelix
Fully support multiple lifetime parameters on types and elsewhere, removing special treatment for `'self`. I am submitting this a touch early in that I plan to push a new commit with more tests specifically targeting types with multiple lifetime parameters -- but the current code bootstraps and passes `make check`. Fixes #4846
This commit is contained in:
commit
8379890c05
@ -125,6 +125,7 @@ ifdef TRACE
|
||||
CFG_RUSTC_FLAGS += -Z trace
|
||||
endif
|
||||
ifndef DEBUG_BORROWS
|
||||
RUSTFLAGS_STAGE0 += -Z no-debug-borrows
|
||||
RUSTFLAGS_STAGE1 += -Z no-debug-borrows
|
||||
RUSTFLAGS_STAGE2 += -Z no-debug-borrows
|
||||
endif
|
||||
|
@ -233,10 +233,10 @@ impl<T:Send> MutexArc<T> {
|
||||
|
||||
/// As unsafe_access(), but with a condvar, as sync::mutex.lock_cond().
|
||||
#[inline]
|
||||
pub unsafe fn unsafe_access_cond<'x, 'c, U>(&self,
|
||||
blk: &fn(x: &'x mut T,
|
||||
c: &'c Condvar) -> U)
|
||||
-> U {
|
||||
pub unsafe fn unsafe_access_cond<U>(&self,
|
||||
blk: &fn(x: &mut T,
|
||||
c: &Condvar) -> U)
|
||||
-> U {
|
||||
let state = self.x.get();
|
||||
do (&(*state).lock).lock_cond |cond| {
|
||||
check_poison(true, (*state).failed);
|
||||
@ -290,10 +290,10 @@ impl<T:Freeze + Send> MutexArc<T> {
|
||||
|
||||
/// As unsafe_access_cond but safe and Freeze.
|
||||
#[inline]
|
||||
pub fn access_cond<'x, 'c, U>(&self,
|
||||
blk: &fn(x: &'x mut T,
|
||||
c: &'c Condvar) -> U)
|
||||
-> U {
|
||||
pub fn access_cond<U>(&self,
|
||||
blk: &fn(x: &mut T,
|
||||
c: &Condvar) -> U)
|
||||
-> U {
|
||||
unsafe { self.unsafe_access_cond(blk) }
|
||||
}
|
||||
}
|
||||
@ -402,9 +402,9 @@ impl<T:Freeze + Send> RWArc<T> {
|
||||
|
||||
/// As write(), but with a condvar, as sync::rwlock.write_cond().
|
||||
#[inline]
|
||||
pub fn write_cond<'x, 'c, U>(&self,
|
||||
blk: &fn(x: &'x mut T, c: &'c Condvar) -> U)
|
||||
-> U {
|
||||
pub fn write_cond<U>(&self,
|
||||
blk: &fn(x: &mut T, c: &Condvar) -> U)
|
||||
-> U {
|
||||
unsafe {
|
||||
let state = self.x.get();
|
||||
do (*borrow_rwlock(state)).write_cond |cond| {
|
||||
@ -554,9 +554,9 @@ impl<'self, T:Freeze + Send> RWWriteMode<'self, T> {
|
||||
}
|
||||
|
||||
/// Access the pre-downgrade RWArc in write mode with a condvar.
|
||||
pub fn write_cond<'x, 'c, U>(&mut self,
|
||||
blk: &fn(x: &'x mut T, c: &'c Condvar) -> U)
|
||||
-> U {
|
||||
pub fn write_cond<U>(&mut self,
|
||||
blk: &fn(x: &mut T, c: &Condvar) -> U)
|
||||
-> U {
|
||||
match *self {
|
||||
RWWriteMode {
|
||||
data: &ref mut data,
|
||||
|
@ -239,6 +239,9 @@ pub fn phase_3_run_analysis_passes(sess: Session,
|
||||
time(time_passes, "resolution", (), |_|
|
||||
middle::resolve::resolve_crate(sess, lang_items, crate));
|
||||
|
||||
let named_region_map = time(time_passes, "lifetime resolution", (),
|
||||
|_| middle::resolve_lifetime::crate(sess, crate));
|
||||
|
||||
time(time_passes, "looking for entry point", (),
|
||||
|_| middle::entry::find_entry_point(sess, crate, ast_map));
|
||||
|
||||
@ -246,13 +249,10 @@ pub fn phase_3_run_analysis_passes(sess: Session,
|
||||
freevars::annotate_freevars(def_map, crate));
|
||||
|
||||
let region_map = time(time_passes, "region resolution", (), |_|
|
||||
middle::region::resolve_crate(sess, def_map, crate));
|
||||
middle::region::resolve_crate(sess, crate));
|
||||
|
||||
let rp_set = time(time_passes, "region parameterization inference", (), |_|
|
||||
middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
|
||||
|
||||
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
|
||||
region_map, rp_set, lang_items);
|
||||
let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map, freevars,
|
||||
region_map, lang_items);
|
||||
|
||||
// passes are timed inside typeck
|
||||
let (method_map, vtable_map) = typeck::check_crate(
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -54,8 +54,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;
|
||||
|
@ -89,7 +89,7 @@ pub static tag_path_elt_name: uint = 0x43u;
|
||||
pub static tag_item_field: uint = 0x44u;
|
||||
pub static tag_struct_mut: uint = 0x45u;
|
||||
|
||||
pub static tag_region_param: uint = 0x46u;
|
||||
pub static tag_item_variances: uint = 0x46;
|
||||
pub static tag_mod_impl_trait: uint = 0x47u;
|
||||
/*
|
||||
trait items contain tag_item_trait_method elements,
|
||||
@ -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,
|
||||
|
@ -14,7 +14,6 @@
|
||||
use metadata::common::*;
|
||||
use metadata::cstore;
|
||||
use metadata::decoder;
|
||||
use metadata;
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
|
||||
@ -144,6 +143,12 @@ pub fn get_trait_method_def_ids(cstore: @mut cstore::CStore,
|
||||
decoder::get_trait_method_def_ids(cdata, def.node)
|
||||
}
|
||||
|
||||
pub fn get_item_variances(cstore: @mut cstore::CStore,
|
||||
def: ast::DefId) -> ty::ItemVariances {
|
||||
let cdata = cstore::get_crate_data(cstore, def.crate);
|
||||
decoder::get_item_variances(cdata, def.node)
|
||||
}
|
||||
|
||||
pub fn get_provided_trait_methods(tcx: ty::ctxt,
|
||||
def: ast::DefId)
|
||||
-> ~[@ty::Method] {
|
||||
@ -199,12 +204,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 +223,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,
|
||||
@ -1078,6 +1088,14 @@ pub fn get_trait_method_def_ids(cdata: Cmd,
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances {
|
||||
let data = cdata.data;
|
||||
let item_doc = lookup_item(id, data);
|
||||
let variance_doc = reader::get_doc(item_doc, tag_item_variances);
|
||||
let mut decoder = reader::Decoder(variance_doc);
|
||||
Decodable::decode(&mut decoder)
|
||||
}
|
||||
|
||||
pub fn get_provided_trait_methods(intr: @ident_interner, cdata: Cmd,
|
||||
id: ast::NodeId, tcx: ty::ctxt) ->
|
||||
~[@ty::Method] {
|
||||
|
@ -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,38 @@ 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_item_variances(ebml_w: &mut writer::Encoder,
|
||||
ecx: &EncodeContext,
|
||||
id: ast::NodeId) {
|
||||
let v = ty::item_variances(ecx.tcx, ast_util::local_def(id));
|
||||
ebml_w.start_tag(tag_item_variances);
|
||||
v.encode(ebml_w);
|
||||
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 +992,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();
|
||||
}
|
||||
@ -986,6 +1001,7 @@ 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, 't');
|
||||
encode_item_variances(ebml_w, ecx, item.id);
|
||||
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);
|
||||
@ -994,7 +1010,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);
|
||||
@ -1027,10 +1042,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
encode_family(ebml_w, 'S');
|
||||
encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
|
||||
|
||||
encode_item_variances(ebml_w, ecx, item.id);
|
||||
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 +1090,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 +1149,7 @@ 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_item_variances(ebml_w, ecx, item.id);
|
||||
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,48 +228,65 @@ 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::BoundRegion {
|
||||
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::BrAnon(id)
|
||||
}
|
||||
'[' => {
|
||||
let def = parse_def(st, RegionParameter, |x,y| conv(x,y));
|
||||
let ident = st.tcx.sess.ident_of(parse_str(st, ']'));
|
||||
ty::BrNamed(def, ident)
|
||||
}
|
||||
'f' => {
|
||||
let id = parse_uint(st);
|
||||
assert_eq!(next(st), '|');
|
||||
ty::BrFresh(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::ReLateBound(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::ReEarlyBound(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,
|
||||
ty::ReFree(ty::FreeRegion {scope_id: id,
|
||||
bound_region: br})
|
||||
}
|
||||
's' => {
|
||||
let id = parse_uint(st) as int;
|
||||
assert_eq!(next(st), '|');
|
||||
ty::re_scope(id)
|
||||
ty::ReScope(id)
|
||||
}
|
||||
't' => {
|
||||
ty::re_static
|
||||
ty::ReStatic
|
||||
}
|
||||
'e' => {
|
||||
ty::re_static
|
||||
ty::ReStatic
|
||||
}
|
||||
_ => fail!("parse_region: bad input")
|
||||
}
|
||||
@ -331,37 +351,37 @@ 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);
|
||||
}
|
||||
's' => {
|
||||
let did = parse_def(st, TypeParameter, conv);
|
||||
let did = parse_def(st, TypeParameter, |x,y| conv(x,y));
|
||||
return ty::mk_self(st.tcx, did);
|
||||
}
|
||||
'@' => return ty::mk_box(st.tcx, parse_mt(st, conv)),
|
||||
'~' => return ty::mk_uniq(st.tcx, parse_mt(st, conv)),
|
||||
'*' => return ty::mk_ptr(st.tcx, parse_mt(st, conv)),
|
||||
'@' => return ty::mk_box(st.tcx, parse_mt(st, |x,y| conv(x,y))),
|
||||
'~' => return ty::mk_uniq(st.tcx, parse_mt(st, |x,y| conv(x,y))),
|
||||
'*' => return ty::mk_ptr(st.tcx, parse_mt(st, |x,y| conv(x,y))),
|
||||
'&' => {
|
||||
let r = parse_region(st);
|
||||
let mt = parse_mt(st, conv);
|
||||
let r = parse_region(st, |x,y| conv(x,y));
|
||||
let mt = parse_mt(st, |x,y| conv(x,y));
|
||||
return ty::mk_rptr(st.tcx, r, mt);
|
||||
}
|
||||
'U' => return ty::mk_unboxed_vec(st.tcx, parse_mt(st, conv)),
|
||||
'U' => return ty::mk_unboxed_vec(st.tcx, parse_mt(st, |x,y| conv(x,y))),
|
||||
'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' => {
|
||||
@ -372,10 +392,10 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
|
||||
return ty::mk_tup(st.tcx, params);
|
||||
}
|
||||
'f' => {
|
||||
return ty::mk_closure(st.tcx, parse_closure_ty(st, conv));
|
||||
return ty::mk_closure(st.tcx, parse_closure_ty(st, |x,y| conv(x,y)));
|
||||
}
|
||||
'F' => {
|
||||
return ty::mk_bare_fn(st.tcx, parse_bare_fn_ty(st, conv));
|
||||
return ty::mk_bare_fn(st.tcx, parse_bare_fn_ty(st, |x,y| conv(x,y)));
|
||||
}
|
||||
'Y' => return ty::mk_type(st.tcx),
|
||||
'C' => {
|
||||
@ -397,7 +417,7 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
|
||||
pos: pos,
|
||||
.. *st
|
||||
};
|
||||
let tt = parse_ty(&mut ps, conv);
|
||||
let tt = parse_ty(&mut ps, |x,y| conv(x,y));
|
||||
st.tcx.rcache.insert(key, tt);
|
||||
return tt;
|
||||
}
|
||||
@ -429,7 +449,7 @@ fn parse_mutability(st: &mut PState) -> ast::Mutability {
|
||||
|
||||
fn parse_mt(st: &mut PState, conv: conv_did) -> ty::mt {
|
||||
let m = parse_mutability(st);
|
||||
ty::mt { ty: parse_ty(st, conv), mutbl: m }
|
||||
ty::mt { ty: parse_ty(st, |x,y| conv(x,y)), mutbl: m }
|
||||
}
|
||||
|
||||
fn parse_def(st: &mut PState, source: DefIdSource,
|
||||
@ -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,23 @@ 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,
|
||||
r => fail!(format!("Bad variadic: {}", r)),
|
||||
};
|
||||
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,35 +155,51 @@ 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::ReLateBound(id, br) => {
|
||||
mywrite!(w, "b[{}|", id);
|
||||
enc_bound_region(w, cx, br);
|
||||
mywrite!(w, "]");
|
||||
}
|
||||
ty::re_free(ref fr) => {
|
||||
ty::ReEarlyBound(node_id, index, ident) => {
|
||||
mywrite!(w, "B[{}|{}|{}]",
|
||||
node_id,
|
||||
index,
|
||||
cx.tcx.sess.str_of(ident));
|
||||
}
|
||||
ty::ReFree(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_infer(_) => {
|
||||
ty::ReScope(nid) => {
|
||||
mywrite!(w, "s{}|", nid);
|
||||
}
|
||||
ty::ReStatic => {
|
||||
mywrite!(w, "t");
|
||||
}
|
||||
ty::ReEmpty => {
|
||||
mywrite!(w, "e");
|
||||
}
|
||||
ty::ReInfer(_) => {
|
||||
// these should not crop up after typeck
|
||||
cx.diag.handler().bug("Cannot encode region variables");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enc_bound_region(w: @mut MemWriter, cx: @ctxt, br: ty::bound_region) {
|
||||
fn enc_bound_region(w: @mut MemWriter, cx: @ctxt, br: ty::BoundRegion) {
|
||||
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::BrAnon(idx) => {
|
||||
mywrite!(w, "a{}|", idx);
|
||||
}
|
||||
ty::BrNamed(d, s) => {
|
||||
mywrite!(w, "[{}|{}]",
|
||||
(cx.ds)(d),
|
||||
cx.tcx.sess.str_of(s));
|
||||
}
|
||||
ty::BrFresh(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,24 +476,28 @@ 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_scope(id) => ty::re_scope(xcx.tr_id(id)),
|
||||
ty::re_empty | ty::re_static | ty::re_infer(*) => *self,
|
||||
ty::re_free(ref fr) => {
|
||||
ty::re_free(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id),
|
||||
ty::ReLateBound(id, br) => ty::ReLateBound(xcx.tr_id(id),
|
||||
br.tr(xcx)),
|
||||
ty::ReEarlyBound(id, index, ident) => ty::ReEarlyBound(xcx.tr_id(id),
|
||||
index,
|
||||
ident),
|
||||
ty::ReScope(id) => ty::ReScope(xcx.tr_id(id)),
|
||||
ty::ReEmpty | ty::ReStatic | ty::ReInfer(*) => *self,
|
||||
ty::ReFree(ref fr) => {
|
||||
ty::ReFree(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id),
|
||||
bound_region: fr.bound_region.tr(xcx)})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl tr for ty::bound_region {
|
||||
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::bound_region {
|
||||
impl tr for ty::BoundRegion {
|
||||
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::BoundRegion {
|
||||
match *self {
|
||||
ty::br_anon(_) | ty::br_named(_) | ty::br_self |
|
||||
ty::br_fresh(_) => *self,
|
||||
ty::br_cap_avoid(id, br) => ty::br_cap_avoid(xcx.tr_id(id),
|
||||
@br.tr(xcx))
|
||||
ty::BrAnon(_) |
|
||||
ty::BrFresh(_) => *self,
|
||||
ty::BrNamed(id, ident) => ty::BrNamed(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);
|
||||
|
@ -199,7 +199,7 @@ impl<'self> GuaranteeLifetimeContext<'self> {
|
||||
|
||||
// Make sure that the loan does not exceed the maximum time
|
||||
// that we can root the value, dynamically.
|
||||
let root_region = ty::re_scope(self.root_scope_id);
|
||||
let root_region = ty::ReScope(self.root_scope_id);
|
||||
if !self.bccx.is_subregion_of(self.loan_region, root_region) {
|
||||
self.report_error(
|
||||
err_out_of_root_scope(root_region, self.loan_region));
|
||||
@ -208,9 +208,9 @@ impl<'self> GuaranteeLifetimeContext<'self> {
|
||||
|
||||
// Extract the scope id that indicates how long the rooting is required
|
||||
let root_scope = match self.loan_region {
|
||||
ty::re_scope(id) => id,
|
||||
ty::ReScope(id) => id,
|
||||
_ => {
|
||||
// the check above should fail for anything is not re_scope
|
||||
// the check above should fail for anything is not ReScope
|
||||
self.bccx.tcx.sess.span_bug(
|
||||
cmt_base.span,
|
||||
format!("Cannot issue root for scope region: {:?}",
|
||||
@ -260,12 +260,12 @@ impl<'self> GuaranteeLifetimeContext<'self> {
|
||||
note_and_explain_region(
|
||||
self.bccx.tcx,
|
||||
"managed value only needs to be frozen for ",
|
||||
ty::re_scope(root_scope),
|
||||
ty::ReScope(root_scope),
|
||||
"...");
|
||||
note_and_explain_region(
|
||||
self.bccx.tcx,
|
||||
"...but due to Issue #6248, it will be frozen for ",
|
||||
ty::re_scope(cleanup_scope),
|
||||
ty::ReScope(cleanup_scope),
|
||||
"");
|
||||
}
|
||||
|
||||
@ -324,13 +324,13 @@ impl<'self> GuaranteeLifetimeContext<'self> {
|
||||
|
||||
match cmt.cat {
|
||||
mc::cat_rvalue(cleanup_scope_id) => {
|
||||
ty::re_scope(cleanup_scope_id)
|
||||
ty::ReScope(cleanup_scope_id)
|
||||
}
|
||||
mc::cat_copied_upvar(_) => {
|
||||
ty::re_scope(self.item_scope_id)
|
||||
ty::ReScope(self.item_scope_id)
|
||||
}
|
||||
mc::cat_static_item => {
|
||||
ty::re_static
|
||||
ty::ReStatic
|
||||
}
|
||||
mc::cat_local(local_id) |
|
||||
mc::cat_arg(local_id) |
|
||||
@ -338,7 +338,7 @@ impl<'self> GuaranteeLifetimeContext<'self> {
|
||||
self.bccx.tcx.region_maps.encl_region(local_id)
|
||||
}
|
||||
mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {
|
||||
ty::re_static
|
||||
ty::ReStatic
|
||||
}
|
||||
mc::cat_deref(_, _, mc::region_ptr(_, r)) => {
|
||||
r
|
||||
|
@ -277,7 +277,7 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
|
||||
// Currently these do not use adjustments, so we have to
|
||||
// hardcode this check here (note that the receiver DOES use
|
||||
// adjustments).
|
||||
let scope_r = ty::re_scope(ex.id);
|
||||
let scope_r = ty::ReScope(ex.id);
|
||||
let arg_cmt = this.bccx.cat_expr(arg);
|
||||
this.guarantee_valid(arg.id,
|
||||
arg.span,
|
||||
@ -441,7 +441,7 @@ impl<'self> GatherLoanCtxt<'self> {
|
||||
|
||||
// a loan for the empty region can never be dereferenced, so
|
||||
// it is always safe
|
||||
if loan_region == ty::re_empty {
|
||||
if loan_region == ty::ReEmpty {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -470,10 +470,10 @@ impl<'self> GatherLoanCtxt<'self> {
|
||||
|
||||
restrictions::SafeIf(loan_path, restrictions) => {
|
||||
let loan_scope = match loan_region {
|
||||
ty::re_scope(id) => id,
|
||||
ty::re_free(ref fr) => fr.scope_id,
|
||||
ty::ReScope(id) => id,
|
||||
ty::ReFree(ref fr) => fr.scope_id,
|
||||
|
||||
ty::re_static => {
|
||||
ty::ReStatic => {
|
||||
// If we get here, an error must have been
|
||||
// reported in
|
||||
// `lifetime::guarantee_lifetime()`, because
|
||||
@ -485,9 +485,10 @@ impl<'self> GatherLoanCtxt<'self> {
|
||||
return;
|
||||
}
|
||||
|
||||
ty::re_empty |
|
||||
ty::re_bound(*) |
|
||||
ty::re_infer(*) => {
|
||||
ty::ReEmpty |
|
||||
ty::ReLateBound(*) |
|
||||
ty::ReEarlyBound(*) |
|
||||
ty::ReInfer(*) => {
|
||||
self.tcx().sess.span_bug(
|
||||
cmt.span,
|
||||
format!("Invalid borrow lifetime: {:?}", loan_region));
|
||||
@ -714,7 +715,7 @@ impl<'self> GatherLoanCtxt<'self> {
|
||||
let cmt_discr = match arm_match_ids {
|
||||
None => cmt,
|
||||
Some((arm_id, match_id)) => {
|
||||
let arm_scope = ty::re_scope(arm_id);
|
||||
let arm_scope = ty::ReScope(arm_id);
|
||||
if self.bccx.is_subregion_of(scope_r, arm_scope) {
|
||||
self.bccx.cat_discr(cmt, match_id)
|
||||
} else {
|
||||
|
@ -540,12 +540,12 @@ 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
|
||||
// must have been declared on the enclosing fn item).
|
||||
if target_regions.iter().any(|r| is_re_scope(*r)) {
|
||||
if target_regions.iter().any(|r| is_ReScope(*r)) {
|
||||
return; /* case (1) */
|
||||
}
|
||||
|
||||
@ -582,12 +582,11 @@ pub fn check_cast_for_escaping_regions(
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
fn is_re_scope(r: ty::Region) -> bool {
|
||||
fn is_ReScope(r: ty::Region) -> bool {
|
||||
match r {
|
||||
ty::re_scope(*) => true,
|
||||
ty::ReScope(*) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -22,22 +22,14 @@ Most of the documentation on regions can be found in
|
||||
|
||||
|
||||
use driver::session::Session;
|
||||
use metadata::csearch;
|
||||
use middle::resolve;
|
||||
use middle::ty::{region_variance, rv_covariant, rv_invariant};
|
||||
use middle::ty::{rv_contravariant, FreeRegion};
|
||||
use middle::ty::{FreeRegion};
|
||||
use middle::ty;
|
||||
|
||||
use std::hashmap::{HashMap, HashSet};
|
||||
use syntax::ast_map;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::print::pprust;
|
||||
use syntax::parse::token;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::{ast, visit};
|
||||
use syntax::visit::{Visitor,fn_kind};
|
||||
use syntax::ast::{Block,item,fn_decl,NodeId,Arm,Pat,Stmt,Expr,Local};
|
||||
use syntax::ast::{Ty,TypeMethod,struct_field};
|
||||
|
||||
/**
|
||||
The region maps encode information about region relationships.
|
||||
@ -74,7 +66,6 @@ pub struct Context {
|
||||
|
||||
struct RegionResolutionVisitor {
|
||||
sess: Session,
|
||||
def_map: resolve::DefMap,
|
||||
|
||||
// Generated maps:
|
||||
region_maps: @mut RegionMaps,
|
||||
@ -146,7 +137,7 @@ impl RegionMaps {
|
||||
pub fn encl_region(&self, id: ast::NodeId) -> ty::Region {
|
||||
//! Returns the narrowest scope region that encloses `id`, if any.
|
||||
|
||||
ty::re_scope(self.encl_scope(id))
|
||||
ty::ReScope(self.encl_scope(id))
|
||||
}
|
||||
|
||||
pub fn scopes_intersect(&self, scope1: ast::NodeId, scope2: ast::NodeId)
|
||||
@ -236,19 +227,19 @@ impl RegionMaps {
|
||||
|
||||
sub_region == super_region || {
|
||||
match (sub_region, super_region) {
|
||||
(_, ty::re_static) => {
|
||||
(_, ty::ReStatic) => {
|
||||
true
|
||||
}
|
||||
|
||||
(ty::re_scope(sub_scope), ty::re_scope(super_scope)) => {
|
||||
(ty::ReScope(sub_scope), ty::ReScope(super_scope)) => {
|
||||
self.is_subscope_of(sub_scope, super_scope)
|
||||
}
|
||||
|
||||
(ty::re_scope(sub_scope), ty::re_free(ref fr)) => {
|
||||
(ty::ReScope(sub_scope), ty::ReFree(ref fr)) => {
|
||||
self.is_subscope_of(sub_scope, fr.scope_id)
|
||||
}
|
||||
|
||||
(ty::re_free(sub_fr), ty::re_free(super_fr)) => {
|
||||
(ty::ReFree(sub_fr), ty::ReFree(super_fr)) => {
|
||||
self.sub_free_region(sub_fr, super_fr)
|
||||
}
|
||||
|
||||
@ -504,7 +495,6 @@ impl Visitor<Context> for RegionResolutionVisitor {
|
||||
}
|
||||
|
||||
pub fn resolve_crate(sess: Session,
|
||||
def_map: resolve::DefMap,
|
||||
crate: &ast::Crate) -> @mut RegionMaps
|
||||
{
|
||||
let region_maps = @mut RegionMaps {
|
||||
@ -516,483 +506,9 @@ pub fn resolve_crate(sess: Session,
|
||||
var_parent: None};
|
||||
let mut visitor = RegionResolutionVisitor {
|
||||
sess: sess,
|
||||
def_map: def_map,
|
||||
region_maps: region_maps,
|
||||
};
|
||||
visit::walk_crate(&mut visitor, crate, cx);
|
||||
return region_maps;
|
||||
}
|
||||
|
||||
// ___________________________________________________________________________
|
||||
// Determining region parameterization
|
||||
//
|
||||
// Infers which type defns must be region parameterized---this is done
|
||||
// by scanning their contents to see whether they reference a region
|
||||
// type, directly or indirectly. This is a fixed-point computation.
|
||||
//
|
||||
// We do it in two passes. First we walk the AST and construct a map
|
||||
// from each type defn T1 to other defns which make use of it. For example,
|
||||
// if we have a type like:
|
||||
//
|
||||
// type S = *int;
|
||||
// type T = S;
|
||||
//
|
||||
// Then there would be a map entry from S to T. During the same walk,
|
||||
// we also construct add any types that reference regions to a set and
|
||||
// a worklist. We can then process the worklist, propagating indirect
|
||||
// dependencies until a fixed point is reached.
|
||||
|
||||
pub type region_paramd_items = @mut HashMap<ast::NodeId, region_variance>;
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub struct region_dep {
|
||||
ambient_variance: region_variance,
|
||||
id: ast::NodeId
|
||||
}
|
||||
|
||||
pub struct DetermineRpCtxt {
|
||||
sess: Session,
|
||||
ast_map: ast_map::map,
|
||||
def_map: resolve::DefMap,
|
||||
region_paramd_items: region_paramd_items,
|
||||
dep_map: @mut HashMap<ast::NodeId, @mut ~[region_dep]>,
|
||||
worklist: ~[ast::NodeId],
|
||||
|
||||
// the innermost enclosing item id
|
||||
item_id: ast::NodeId,
|
||||
|
||||
// true when we are within an item but not within a method.
|
||||
// see long discussion on region_is_relevant().
|
||||
anon_implies_rp: bool,
|
||||
|
||||
// encodes the context of the current type; invariant if
|
||||
// mutable, covariant otherwise
|
||||
ambient_variance: region_variance,
|
||||
}
|
||||
|
||||
pub fn join_variance(variance1: region_variance,
|
||||
variance2: region_variance)
|
||||
-> region_variance {
|
||||
match (variance1, variance2) {
|
||||
(rv_invariant, _) => {rv_invariant}
|
||||
(_, rv_invariant) => {rv_invariant}
|
||||
(rv_covariant, rv_contravariant) => {rv_invariant}
|
||||
(rv_contravariant, rv_covariant) => {rv_invariant}
|
||||
(rv_covariant, rv_covariant) => {rv_covariant}
|
||||
(rv_contravariant, rv_contravariant) => {rv_contravariant}
|
||||
}
|
||||
}
|
||||
|
||||
/// Combines the ambient variance with the variance of a
|
||||
/// particular site to yield the final variance of the reference.
|
||||
///
|
||||
/// Example: if we are checking function arguments then the ambient
|
||||
/// variance is contravariant. If we then find a `&'r T` pointer, `r`
|
||||
/// appears in a co-variant position. This implies that this
|
||||
/// occurrence of `r` is contra-variant with respect to the current
|
||||
/// item, and hence the function returns `rv_contravariant`.
|
||||
pub fn add_variance(ambient_variance: region_variance,
|
||||
variance: region_variance)
|
||||
-> region_variance {
|
||||
match (ambient_variance, variance) {
|
||||
(rv_invariant, _) => rv_invariant,
|
||||
(_, rv_invariant) => rv_invariant,
|
||||
(rv_covariant, c) => c,
|
||||
(c, rv_covariant) => c,
|
||||
(rv_contravariant, rv_contravariant) => rv_covariant
|
||||
}
|
||||
}
|
||||
|
||||
impl DetermineRpCtxt {
|
||||
pub fn add_variance(&self, variance: region_variance) -> region_variance {
|
||||
add_variance(self.ambient_variance, variance)
|
||||
}
|
||||
|
||||
/// Records that item `id` is region-parameterized with the
|
||||
/// variance `variance`. If `id` was already parameterized, then
|
||||
/// the new variance is joined with the old variance.
|
||||
pub fn add_rp(&mut self, id: ast::NodeId, variance: region_variance) {
|
||||
assert!(id != 0);
|
||||
let old_variance = self.region_paramd_items.find(&id).map(|x| *x);
|
||||
let joined_variance = match old_variance {
|
||||
None => variance,
|
||||
Some(v) => join_variance(v, variance)
|
||||
};
|
||||
|
||||
debug!("add_rp() variance for {}: {:?} == {:?} ^ {:?}",
|
||||
ast_map::node_id_to_str(self.ast_map, id,
|
||||
token::get_ident_interner()),
|
||||
joined_variance, old_variance, variance);
|
||||
|
||||
if Some(joined_variance) != old_variance {
|
||||
let region_paramd_items = self.region_paramd_items;
|
||||
region_paramd_items.insert(id, joined_variance);
|
||||
self.worklist.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates that the region-parameterization of the current item
|
||||
/// is dependent on the region-parameterization of the item
|
||||
/// `from`. Put another way, it indicates that the current item
|
||||
/// contains a value of type `from`, so if `from` is
|
||||
/// region-parameterized, so is the current item.
|
||||
pub fn add_dep(&mut self, from: ast::NodeId) {
|
||||
debug!("add dependency from {} -> {} ({} -> {}) with variance {:?}",
|
||||
from, self.item_id,
|
||||
ast_map::node_id_to_str(self.ast_map, from,
|
||||
token::get_ident_interner()),
|
||||
ast_map::node_id_to_str(self.ast_map, self.item_id,
|
||||
token::get_ident_interner()),
|
||||
self.ambient_variance);
|
||||
let vec = do self.dep_map.find_or_insert_with(from) |_| {
|
||||
@mut ~[]
|
||||
};
|
||||
let dep = region_dep {
|
||||
ambient_variance: self.ambient_variance,
|
||||
id: self.item_id
|
||||
};
|
||||
if !vec.iter().any(|x| x == &dep) { vec.push(dep); }
|
||||
}
|
||||
|
||||
// Determines whether a reference to a region that appears in the
|
||||
// AST implies that the enclosing type is region-parameterized (RP).
|
||||
// This point is subtle. Here are some examples to make it more
|
||||
// concrete.
|
||||
//
|
||||
// 1. impl foo for &int { ... }
|
||||
// 2. impl foo for &'self int { ... }
|
||||
// 3. impl foo for bar { fn m(@self) -> &'self int { ... } }
|
||||
// 4. impl foo for bar { fn m(&self) -> &'self int { ... } }
|
||||
// 5. impl foo for bar { fn m(&self) -> &int { ... } }
|
||||
//
|
||||
// In case 1, the anonymous region is being referenced,
|
||||
// but it appears in a context where the anonymous region
|
||||
// resolves to self, so the impl foo is RP.
|
||||
//
|
||||
// In case 2, the self parameter is written explicitly.
|
||||
//
|
||||
// In case 3, the method refers to the region `self`, so that
|
||||
// implies that the impl must be region parameterized. (If the
|
||||
// type bar is not region parameterized, that is an error, because
|
||||
// the self region is effectively unconstrained, but that is
|
||||
// detected elsewhere).
|
||||
//
|
||||
// In case 4, the method refers to the region `self`, but the
|
||||
// `self` region is bound by the `&self` receiver, and so this
|
||||
// does not require that `bar` be RP.
|
||||
//
|
||||
// In case 5, the anonymous region is referenced, but it
|
||||
// bound by the method, so it does not refer to self. This impl
|
||||
// need not be region parameterized.
|
||||
//
|
||||
// Normally, & or &self implies that the enclosing item is RP.
|
||||
// However, within a function, & is always bound. Within a method
|
||||
// with &self type, &self is also bound. We detect those last two
|
||||
// cases via flags (anon_implies_rp and self_implies_rp) that are
|
||||
// true when the anon or self region implies RP.
|
||||
pub fn region_is_relevant(&self, r: &Option<ast::Lifetime>) -> bool {
|
||||
match r {
|
||||
&None => {
|
||||
self.anon_implies_rp
|
||||
}
|
||||
&Some(ref l) if l.ident == special_idents::statik => {
|
||||
false
|
||||
}
|
||||
&Some(ref l) if l.ident == special_idents::self_ => {
|
||||
true
|
||||
}
|
||||
&Some(_) => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with(@mut self,
|
||||
item_id: ast::NodeId,
|
||||
anon_implies_rp: bool,
|
||||
f: &fn()) {
|
||||
let old_item_id = self.item_id;
|
||||
let old_anon_implies_rp = self.anon_implies_rp;
|
||||
self.item_id = item_id;
|
||||
self.anon_implies_rp = anon_implies_rp;
|
||||
debug!("with_item_id({}, {})",
|
||||
item_id,
|
||||
anon_implies_rp);
|
||||
let _i = ::util::common::indenter();
|
||||
f();
|
||||
self.item_id = old_item_id;
|
||||
self.anon_implies_rp = old_anon_implies_rp;
|
||||
}
|
||||
|
||||
pub fn with_ambient_variance(@mut self,
|
||||
variance: region_variance,
|
||||
f: &fn()) {
|
||||
let old_ambient_variance = self.ambient_variance;
|
||||
self.ambient_variance = self.add_variance(variance);
|
||||
f();
|
||||
self.ambient_variance = old_ambient_variance;
|
||||
}
|
||||
}
|
||||
|
||||
fn determine_rp_in_item(visitor: &mut DetermineRpVisitor,
|
||||
item: @ast::item) {
|
||||
do visitor.cx.with(item.id, true) {
|
||||
visit::walk_item(visitor, item, ());
|
||||
}
|
||||
}
|
||||
|
||||
fn determine_rp_in_fn(visitor: &mut DetermineRpVisitor,
|
||||
fk: &visit::fn_kind,
|
||||
decl: &ast::fn_decl,
|
||||
body: &ast::Block,
|
||||
_: Span,
|
||||
_: ast::NodeId) {
|
||||
let cx = visitor.cx;
|
||||
do cx.with(cx.item_id, false) {
|
||||
do cx.with_ambient_variance(rv_contravariant) {
|
||||
for a in decl.inputs.iter() {
|
||||
visitor.visit_ty(&a.ty, ());
|
||||
}
|
||||
}
|
||||
visitor.visit_ty(&decl.output, ());
|
||||
let generics = visit::generics_of_fn(fk);
|
||||
visitor.visit_generics(&generics, ());
|
||||
visitor.visit_block(body, ());
|
||||
}
|
||||
}
|
||||
|
||||
fn determine_rp_in_ty_method(visitor: &mut DetermineRpVisitor,
|
||||
ty_m: &ast::TypeMethod) {
|
||||
let cx = visitor.cx;
|
||||
do cx.with(cx.item_id, false) {
|
||||
visit::walk_ty_method(visitor, ty_m, ());
|
||||
}
|
||||
}
|
||||
|
||||
fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
|
||||
ty: &ast::Ty) {
|
||||
let cx = visitor.cx;
|
||||
|
||||
// we are only interested in types that will require an item to
|
||||
// be region-parameterized. if cx.item_id is zero, then this type
|
||||
// is not a member of a type defn nor is it a constitutent of an
|
||||
// impl etc. So we can ignore it and its components.
|
||||
if cx.item_id == 0 { return; }
|
||||
|
||||
// if this type directly references a region pointer like &'r ty,
|
||||
// add to the worklist/set. Note that &'r ty is contravariant with
|
||||
// respect to &r, because &'r ty can be used whereever a *smaller*
|
||||
// region is expected (and hence is a supertype of those
|
||||
// locations)
|
||||
let sess = cx.sess;
|
||||
match ty.node {
|
||||
ast::ty_rptr(ref r, _) => {
|
||||
debug!("referenced rptr type {}",
|
||||
pprust::ty_to_str(ty, sess.intr()));
|
||||
|
||||
if cx.region_is_relevant(r) {
|
||||
let rv = cx.add_variance(rv_contravariant);
|
||||
cx.add_rp(cx.item_id, rv)
|
||||
}
|
||||
}
|
||||
|
||||
ast::ty_closure(ref f) => {
|
||||
debug!("referenced fn type: {}",
|
||||
pprust::ty_to_str(ty, sess.intr()));
|
||||
match f.region {
|
||||
Some(_) => {
|
||||
if cx.region_is_relevant(&f.region) {
|
||||
let rv = cx.add_variance(rv_contravariant);
|
||||
cx.add_rp(cx.item_id, rv)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if f.sigil == ast::BorrowedSigil && cx.anon_implies_rp {
|
||||
let rv = cx.add_variance(rv_contravariant);
|
||||
cx.add_rp(cx.item_id, rv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// if this references another named type, add the dependency
|
||||
// to the dep_map. If the type is not defined in this crate,
|
||||
// then check whether it is region-parameterized and consider
|
||||
// that as a direct dependency.
|
||||
match ty.node {
|
||||
ast::ty_path(ref path, _, id) => {
|
||||
match cx.def_map.find(&id) {
|
||||
Some(&ast::DefTy(did)) |
|
||||
Some(&ast::DefTrait(did)) |
|
||||
Some(&ast::DefStruct(did)) => {
|
||||
if did.crate == ast::LOCAL_CRATE {
|
||||
if cx.region_is_relevant(&path.segments.last().lifetime) {
|
||||
cx.add_dep(did.node);
|
||||
}
|
||||
} else {
|
||||
let cstore = sess.cstore;
|
||||
match csearch::get_region_param(cstore, did) {
|
||||
None => {}
|
||||
Some(variance) => {
|
||||
debug!("reference to external, rp'd type {}",
|
||||
pprust::ty_to_str(ty, sess.intr()));
|
||||
if cx.region_is_relevant(&path.segments.last().lifetime) {
|
||||
let rv = cx.add_variance(variance);
|
||||
cx.add_rp(cx.item_id, rv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match ty.node {
|
||||
ast::ty_box(ref mt) | ast::ty_uniq(ref mt) | ast::ty_vec(ref mt) |
|
||||
ast::ty_rptr(_, ref mt) | ast::ty_ptr(ref mt) => {
|
||||
visit_mt(visitor, mt);
|
||||
}
|
||||
|
||||
ast::ty_path(ref path, _, _) => {
|
||||
// type parameters are---for now, anyway---always invariant
|
||||
do cx.with_ambient_variance(rv_invariant) {
|
||||
for tp in path.segments.iter().flat_map(|s| s.types.iter()) {
|
||||
visitor.visit_ty(tp, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast::ty_closure(@ast::TyClosure {decl: ref decl, _}) |
|
||||
ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => {
|
||||
// fn() binds the & region, so do not consider &T types that
|
||||
// appear *inside* a fn() type to affect the enclosing item:
|
||||
do cx.with(cx.item_id, false) {
|
||||
// parameters are contravariant
|
||||
do cx.with_ambient_variance(rv_contravariant) {
|
||||
for a in decl.inputs.iter() {
|
||||
visitor.visit_ty(&a.ty, ());
|
||||
}
|
||||
}
|
||||
visitor.visit_ty(&decl.output, ());
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
visit::walk_ty(visitor, ty, ());
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mt(visitor: &mut DetermineRpVisitor,
|
||||
mt: &ast::mt) {
|
||||
let cx = visitor.cx;
|
||||
// mutability is invariant
|
||||
if mt.mutbl == ast::MutMutable {
|
||||
do cx.with_ambient_variance(rv_invariant) {
|
||||
visitor.visit_ty(mt.ty, ());
|
||||
}
|
||||
} else {
|
||||
visitor.visit_ty(mt.ty, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn determine_rp_in_struct_field(visitor: &mut DetermineRpVisitor,
|
||||
cm: @ast::struct_field) {
|
||||
visit::walk_struct_field(visitor, cm, ());
|
||||
}
|
||||
|
||||
struct DetermineRpVisitor {
|
||||
cx: @mut DetermineRpCtxt
|
||||
}
|
||||
|
||||
impl Visitor<()> for DetermineRpVisitor {
|
||||
|
||||
fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl,
|
||||
b:&Block, s:Span, n:NodeId, _:()) {
|
||||
determine_rp_in_fn(self, fk, fd, b, s, n);
|
||||
}
|
||||
fn visit_item(&mut self, i:@item, _:()) {
|
||||
determine_rp_in_item(self, i);
|
||||
}
|
||||
fn visit_ty(&mut self, t:&Ty, _:()) {
|
||||
determine_rp_in_ty(self, t);
|
||||
}
|
||||
fn visit_ty_method(&mut self, t:&TypeMethod, _:()) {
|
||||
determine_rp_in_ty_method(self, t);
|
||||
}
|
||||
fn visit_struct_field(&mut self, s:@struct_field, _:()) {
|
||||
determine_rp_in_struct_field(self, s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn determine_rp_in_crate(sess: Session,
|
||||
ast_map: ast_map::map,
|
||||
def_map: resolve::DefMap,
|
||||
crate: &ast::Crate)
|
||||
-> region_paramd_items {
|
||||
let cx = @mut DetermineRpCtxt {
|
||||
sess: sess,
|
||||
ast_map: ast_map,
|
||||
def_map: def_map,
|
||||
region_paramd_items: @mut HashMap::new(),
|
||||
dep_map: @mut HashMap::new(),
|
||||
worklist: ~[],
|
||||
item_id: 0,
|
||||
anon_implies_rp: false,
|
||||
ambient_variance: rv_covariant
|
||||
};
|
||||
|
||||
// Gather up the base set, worklist and dep_map
|
||||
let mut visitor = DetermineRpVisitor { cx: cx };
|
||||
visit::walk_crate(&mut visitor, crate, ());
|
||||
|
||||
// Propagate indirect dependencies
|
||||
//
|
||||
// Each entry in the worklist is the id of an item C whose region
|
||||
// parameterization has been updated. So we pull ids off of the
|
||||
// worklist, find the current variance, and then iterate through
|
||||
// all of the dependent items (that is, those items that reference
|
||||
// C). For each dependent item D, we combine the variance of C
|
||||
// with the ambient variance where the reference occurred and then
|
||||
// update the region-parameterization of D to reflect the result.
|
||||
{
|
||||
let cx = &mut *cx;
|
||||
while cx.worklist.len() != 0 {
|
||||
let c_id = cx.worklist.pop();
|
||||
let c_variance = cx.region_paramd_items.get_copy(&c_id);
|
||||
debug!("popped {} from worklist", c_id);
|
||||
match cx.dep_map.find(&c_id) {
|
||||
None => {}
|
||||
Some(deps) => {
|
||||
for dep in deps.iter() {
|
||||
let v = add_variance(dep.ambient_variance, c_variance);
|
||||
cx.add_rp(dep.id, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("{}", {
|
||||
debug!("Region variance results:");
|
||||
let region_paramd_items = cx.region_paramd_items;
|
||||
for (&key, &value) in region_paramd_items.iter() {
|
||||
debug!("item {:?} ({}) is parameterized with variance {:?}",
|
||||
key,
|
||||
ast_map::node_id_to_str(ast_map, key,
|
||||
token::get_ident_interner()),
|
||||
value);
|
||||
}
|
||||
"----"
|
||||
});
|
||||
|
||||
// return final set
|
||||
return cx.region_paramd_items;
|
||||
}
|
||||
|
@ -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 \
|
||||
|
321
src/librustc/middle/resolve_lifetime.rs
Normal file
321
src/librustc/middle/resolve_lifetime.rs
Normal file
@ -0,0 +1,321 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
* Name resolution for lifetimes.
|
||||
*
|
||||
* Name resolution for lifetimes follows MUCH simpler rules than the
|
||||
* full resolve. For example, lifetime names are never exported or
|
||||
* used between functions, and they operate in a purely top-down
|
||||
* way. Therefore we break lifetime name resolution into a separate pass.
|
||||
*/
|
||||
|
||||
use driver::session;
|
||||
use std::hashmap::HashMap;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::opt_vec::OptVec;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::print::pprust::{lifetime_to_str};
|
||||
use syntax::visit;
|
||||
use syntax::visit::Visitor;
|
||||
|
||||
// maps the id of each lifetime reference to the lifetime decl
|
||||
// that it corresponds to
|
||||
pub type NamedRegionMap = HashMap<ast::NodeId, ast::DefRegion>;
|
||||
|
||||
struct LifetimeContext {
|
||||
sess: session::Session,
|
||||
named_region_map: @mut NamedRegionMap,
|
||||
}
|
||||
|
||||
enum ScopeChain<'self> {
|
||||
ItemScope(&'self OptVec<ast::Lifetime>),
|
||||
FnScope(ast::NodeId, &'self OptVec<ast::Lifetime>, &'self ScopeChain<'self>),
|
||||
BlockScope(ast::NodeId, &'self ScopeChain<'self>),
|
||||
RootScope
|
||||
}
|
||||
|
||||
pub fn crate(sess: session::Session,
|
||||
crate: &ast::Crate)
|
||||
-> @mut NamedRegionMap {
|
||||
let mut ctxt = LifetimeContext {
|
||||
sess: sess,
|
||||
named_region_map: @mut HashMap::new()
|
||||
};
|
||||
visit::walk_crate(&mut ctxt, crate, &RootScope);
|
||||
sess.abort_if_errors();
|
||||
ctxt.named_region_map
|
||||
}
|
||||
|
||||
impl<'self> Visitor<&'self ScopeChain<'self>> for LifetimeContext {
|
||||
fn visit_item(&mut self,
|
||||
item: @ast::item,
|
||||
_: &'self ScopeChain<'self>) {
|
||||
let scope = match item.node {
|
||||
ast::item_fn(*) | // fn lifetimes get added in visit_fn below
|
||||
ast::item_mod(*) |
|
||||
ast::item_mac(*) |
|
||||
ast::item_foreign_mod(*) |
|
||||
ast::item_static(*) => {
|
||||
RootScope
|
||||
}
|
||||
ast::item_ty(_, ref generics) |
|
||||
ast::item_enum(_, ref generics) |
|
||||
ast::item_struct(_, ref generics) |
|
||||
ast::item_impl(ref generics, _, _, _) |
|
||||
ast::item_trait(ref generics, _, _) => {
|
||||
self.check_lifetime_names(&generics.lifetimes);
|
||||
ItemScope(&generics.lifetimes)
|
||||
}
|
||||
};
|
||||
debug!("entering scope {:?}", scope);
|
||||
visit::walk_item(self, item, &scope);
|
||||
debug!("exiting scope {:?}", scope);
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self,
|
||||
fk: &visit::fn_kind,
|
||||
fd: &ast::fn_decl,
|
||||
b: &ast::Block,
|
||||
s: Span,
|
||||
n: ast::NodeId,
|
||||
scope: &'self ScopeChain<'self>) {
|
||||
match *fk {
|
||||
visit::fk_item_fn(_, generics, _, _) |
|
||||
visit::fk_method(_, generics, _) => {
|
||||
let scope1 = FnScope(n, &generics.lifetimes, scope);
|
||||
self.check_lifetime_names(&generics.lifetimes);
|
||||
debug!("pushing fn scope id={} due to item/method", n);
|
||||
visit::walk_fn(self, fk, fd, b, s, n, &scope1);
|
||||
debug!("popping fn scope id={} due to item/method", n);
|
||||
}
|
||||
visit::fk_anon(*) | visit::fk_fn_block(*) => {
|
||||
visit::walk_fn(self, fk, fd, b, s, n, scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self,
|
||||
ty: &ast::Ty,
|
||||
scope: &'self ScopeChain<'self>) {
|
||||
match ty.node {
|
||||
ast::ty_closure(@ast::TyClosure { lifetimes: ref lifetimes, _ }) |
|
||||
ast::ty_bare_fn(@ast::TyBareFn { lifetimes: ref lifetimes, _ }) => {
|
||||
let scope1 = FnScope(ty.id, lifetimes, scope);
|
||||
self.check_lifetime_names(lifetimes);
|
||||
debug!("pushing fn scope id={} due to type", ty.id);
|
||||
visit::walk_ty(self, ty, &scope1);
|
||||
debug!("popping fn scope id={} due to type", ty.id);
|
||||
}
|
||||
_ => {
|
||||
visit::walk_ty(self, ty, scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty_method(&mut self,
|
||||
m: &ast::TypeMethod,
|
||||
scope: &'self ScopeChain<'self>) {
|
||||
let scope1 = FnScope(m.id, &m.generics.lifetimes, scope);
|
||||
self.check_lifetime_names(&m.generics.lifetimes);
|
||||
debug!("pushing fn scope id={} due to ty_method", m.id);
|
||||
visit::walk_ty_method(self, m, &scope1);
|
||||
debug!("popping fn scope id={} due to ty_method", m.id);
|
||||
}
|
||||
|
||||
fn visit_block(&mut self,
|
||||
b: &ast::Block,
|
||||
scope: &'self ScopeChain<'self>) {
|
||||
let scope1 = BlockScope(b.id, scope);
|
||||
debug!("pushing block scope {}", b.id);
|
||||
visit::walk_block(self, b, &scope1);
|
||||
debug!("popping block scope {}", b.id);
|
||||
}
|
||||
|
||||
fn visit_lifetime_ref(&mut self,
|
||||
lifetime_ref: &ast::Lifetime,
|
||||
scope: &'self ScopeChain<'self>) {
|
||||
if lifetime_ref.ident == special_idents::statik {
|
||||
self.insert_lifetime(lifetime_ref, ast::DefStaticRegion);
|
||||
return;
|
||||
}
|
||||
self.resolve_lifetime_ref(lifetime_ref, scope);
|
||||
}
|
||||
}
|
||||
|
||||
impl LifetimeContext {
|
||||
fn resolve_lifetime_ref(&self,
|
||||
lifetime_ref: &ast::Lifetime,
|
||||
scope: &ScopeChain) {
|
||||
// Walk up the scope chain, tracking the number of fn scopes
|
||||
// that we pass through, until we find a lifetime with the
|
||||
// given name or we run out of scopes. If we encounter a code
|
||||
// block, then the lifetime is not bound but free, so switch
|
||||
// over to `resolve_free_lifetime_ref()` to complete the
|
||||
// search.
|
||||
let mut depth = 0;
|
||||
let mut scope = scope;
|
||||
loop {
|
||||
match *scope {
|
||||
BlockScope(id, s) => {
|
||||
return self.resolve_free_lifetime_ref(id, lifetime_ref, s);
|
||||
}
|
||||
|
||||
RootScope => {
|
||||
break;
|
||||
}
|
||||
|
||||
ItemScope(lifetimes) => {
|
||||
match search_lifetimes(lifetimes, lifetime_ref) {
|
||||
Some((index, decl_id)) => {
|
||||
let def = ast::DefEarlyBoundRegion(index, decl_id);
|
||||
self.insert_lifetime(lifetime_ref, def);
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FnScope(id, lifetimes, s) => {
|
||||
match search_lifetimes(lifetimes, lifetime_ref) {
|
||||
Some((_index, decl_id)) => {
|
||||
let def = ast::DefLateBoundRegion(id, depth, decl_id);
|
||||
self.insert_lifetime(lifetime_ref, def);
|
||||
return;
|
||||
}
|
||||
|
||||
None => {
|
||||
depth += 1;
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.unresolved_lifetime_ref(lifetime_ref);
|
||||
}
|
||||
|
||||
fn resolve_free_lifetime_ref(&self,
|
||||
scope_id: ast::NodeId,
|
||||
lifetime_ref: &ast::Lifetime,
|
||||
scope: &ScopeChain) {
|
||||
// Walk up the scope chain, tracking the outermost free scope,
|
||||
// until we encounter a scope that contains the named lifetime
|
||||
// or we run out of scopes.
|
||||
let mut scope_id = scope_id;
|
||||
let mut scope = scope;
|
||||
let mut search_result = None;
|
||||
loop {
|
||||
match *scope {
|
||||
BlockScope(id, s) => {
|
||||
scope_id = id;
|
||||
scope = s;
|
||||
}
|
||||
|
||||
RootScope => {
|
||||
break;
|
||||
}
|
||||
|
||||
ItemScope(lifetimes) => {
|
||||
search_result = search_lifetimes(lifetimes, lifetime_ref);
|
||||
break;
|
||||
}
|
||||
|
||||
FnScope(_, lifetimes, s) => {
|
||||
search_result = search_lifetimes(lifetimes, lifetime_ref);
|
||||
if search_result.is_some() {
|
||||
break;
|
||||
}
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match search_result {
|
||||
Some((_depth, decl_id)) => {
|
||||
let def = ast::DefFreeRegion(scope_id, decl_id);
|
||||
self.insert_lifetime(lifetime_ref, def);
|
||||
}
|
||||
|
||||
None => {
|
||||
self.unresolved_lifetime_ref(lifetime_ref);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn unresolved_lifetime_ref(&self,
|
||||
lifetime_ref: &ast::Lifetime) {
|
||||
self.sess.span_err(
|
||||
lifetime_ref.span,
|
||||
format!("use of undeclared lifetime name `'{}`",
|
||||
self.sess.str_of(lifetime_ref.ident)));
|
||||
}
|
||||
|
||||
fn check_lifetime_names(&self, lifetimes: &OptVec<ast::Lifetime>) {
|
||||
for i in range(0, lifetimes.len()) {
|
||||
let lifetime_i = lifetimes.get(i);
|
||||
|
||||
let special_idents = [special_idents::statik];
|
||||
for lifetime in lifetimes.iter() {
|
||||
if special_idents.iter().any(|&i| i == lifetime.ident) {
|
||||
self.sess.span_err(
|
||||
lifetime.span,
|
||||
format!("illegal lifetime parameter name: `{}`",
|
||||
self.sess.str_of(lifetime.ident)));
|
||||
}
|
||||
}
|
||||
|
||||
for j in range(i + 1, lifetimes.len()) {
|
||||
let lifetime_j = lifetimes.get(j);
|
||||
|
||||
if lifetime_i.ident == lifetime_j.ident {
|
||||
self.sess.span_err(
|
||||
lifetime_j.span,
|
||||
format!("lifetime name `'{}` declared twice in \
|
||||
the same scope",
|
||||
self.sess.str_of(lifetime_j.ident)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_lifetime(&self,
|
||||
lifetime_ref: &ast::Lifetime,
|
||||
def: ast::DefRegion) {
|
||||
if lifetime_ref.id == ast::DUMMY_NODE_ID {
|
||||
self.sess.span_bug(lifetime_ref.span,
|
||||
"Lifetime reference not renumbered, \
|
||||
probably a bug in syntax::fold");
|
||||
}
|
||||
|
||||
debug!("lifetime_ref={} id={} resolved to {:?}",
|
||||
lifetime_to_str(lifetime_ref,
|
||||
self.sess.intr()),
|
||||
lifetime_ref.id,
|
||||
def);
|
||||
self.named_region_map.insert(lifetime_ref.id, def);
|
||||
}
|
||||
}
|
||||
|
||||
fn search_lifetimes(lifetimes: &OptVec<ast::Lifetime>,
|
||||
lifetime_ref: &ast::Lifetime)
|
||||
-> Option<(uint, ast::NodeId)> {
|
||||
for (i, lifetime_decl) in lifetimes.iter().enumerate() {
|
||||
if lifetime_decl.ident == lifetime_ref.ident {
|
||||
return Some((i, lifetime_decl.id));
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
@ -10,10 +10,11 @@
|
||||
|
||||
// Type substitutions.
|
||||
|
||||
|
||||
use middle::ty;
|
||||
use middle::ty_fold;
|
||||
use middle::ty_fold::TypeFolder;
|
||||
use syntax::opt_vec::OptVec;
|
||||
use util::ppaux::Repr;
|
||||
use std::at_vec;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Public trait `Subst`
|
||||
@ -33,39 +34,43 @@ pub trait Subst {
|
||||
// to all subst methods but ran into trouble due to the limitations of
|
||||
// our current method/trait matching algorithm. - Niko
|
||||
|
||||
trait EffectfulSubst {
|
||||
fn effectfulSubst(&self, tcx: ty::ctxt, substs: &ty::substs) -> Self;
|
||||
}
|
||||
|
||||
impl Subst for ty::t {
|
||||
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::t {
|
||||
if ty::substs_is_noop(substs) {
|
||||
return *self;
|
||||
*self
|
||||
} else {
|
||||
return self.effectfulSubst(tcx, substs);
|
||||
let mut folder = SubstFolder {tcx: tcx, substs: substs};
|
||||
folder.fold_ty(*self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EffectfulSubst for ty::t {
|
||||
fn effectfulSubst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::t {
|
||||
if !ty::type_needs_subst(*self) {
|
||||
return *self;
|
||||
struct SubstFolder<'self> {
|
||||
tcx: ty::ctxt,
|
||||
substs: &'self ty::substs
|
||||
}
|
||||
|
||||
impl<'self> TypeFolder for SubstFolder<'self> {
|
||||
fn tcx(&self) -> ty::ctxt { self.tcx }
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
|
||||
r.subst(self.tcx, self.substs)
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: ty::t) -> ty::t {
|
||||
if !ty::type_needs_subst(t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
match ty::get(*self).sty {
|
||||
match ty::get(t).sty {
|
||||
ty::ty_param(p) => {
|
||||
substs.tps[p.idx]
|
||||
self.substs.tps[p.idx]
|
||||
}
|
||||
ty::ty_self(_) => {
|
||||
substs.self_ty.expect("ty_self not found in substs")
|
||||
self.substs.self_ty.expect("ty_self not found in substs")
|
||||
}
|
||||
_ => {
|
||||
ty::fold_regions_and_ty(
|
||||
tcx, *self,
|
||||
|r| r.subst(tcx, substs),
|
||||
|t| t.effectfulSubst(tcx, substs),
|
||||
|t| t.effectfulSubst(tcx, substs))
|
||||
ty_fold::super_fold_ty(self, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -80,6 +85,12 @@ impl<T:Subst> Subst for ~[T] {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Subst> Subst for @[T] {
|
||||
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @[T] {
|
||||
at_vec::map(*self, |t| t.subst(tcx, substs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Subst> Subst for OptVec<T> {
|
||||
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> OptVec<T> {
|
||||
self.map(|t| t.subst(tcx, substs))
|
||||
@ -134,7 +145,8 @@ impl Subst for ty::RegionSubsts {
|
||||
|
||||
impl Subst for ty::BareFnTy {
|
||||
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::BareFnTy {
|
||||
ty::fold_bare_fn_ty(self, |t| t.subst(tcx, substs))
|
||||
let mut folder = SubstFolder {tcx: tcx, substs: substs};
|
||||
folder.fold_bare_fn_ty(self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,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::ReEarlyBound(_, 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::ErasedRegions => ty::ReStatic,
|
||||
ty::NonerasedRegions(ref regions) => *regions.get(i),
|
||||
}
|
||||
}
|
||||
_ => *self
|
||||
|
@ -1048,7 +1048,7 @@ fn extract_vec_elems(bcx: @mut Block,
|
||||
let slice_len = Sub(bcx, len, slice_len_offset);
|
||||
let slice_ty = ty::mk_evec(bcx.tcx(),
|
||||
ty::mt {ty: vt.unit_ty, mutbl: ast::MutImmutable},
|
||||
ty::vstore_slice(ty::re_static)
|
||||
ty::vstore_slice(ty::ReStatic)
|
||||
);
|
||||
let scratch = scratch_datum(bcx, slice_ty, "", false);
|
||||
Store(bcx, slice_begin,
|
||||
@ -1697,7 +1697,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
|
||||
let t = node_id_type(bcx, pat_id);
|
||||
let Result {bcx: after_cx, val: matches} = {
|
||||
do with_scope_result(bcx, None,
|
||||
"compare_scope") |bcx| {
|
||||
"compaReScope") |bcx| {
|
||||
match trans_opt(bcx, opt) {
|
||||
single_result(
|
||||
Result {bcx, val}) => {
|
||||
|
@ -181,7 +181,7 @@ pub fn const_expr(cx: @mut CrateContext, e: &ast::Expr) -> (ValueRef, bool) {
|
||||
let adjustment = cx.tcx.adjustments.find_copy(&e.id);
|
||||
match adjustment {
|
||||
None => { }
|
||||
Some(@ty::AutoAddEnv(ty::re_static, ast::BorrowedSigil)) => {
|
||||
Some(@ty::AutoAddEnv(ty::ReStatic, ast::BorrowedSigil)) => {
|
||||
llconst = C_struct([llconst, C_null(Type::opaque_box(cx).ptr_to())], false)
|
||||
}
|
||||
Some(@ty::AutoAddEnv(ref r, ref s)) => {
|
||||
@ -211,11 +211,11 @@ pub fn const_expr(cx: @mut CrateContext, e: &ast::Expr) -> (ValueRef, bool) {
|
||||
};
|
||||
match *autoref {
|
||||
ty::AutoUnsafe(m) |
|
||||
ty::AutoPtr(ty::re_static, m) => {
|
||||
ty::AutoPtr(ty::ReStatic, m) => {
|
||||
assert!(m != ast::MutMutable);
|
||||
llconst = llptr;
|
||||
}
|
||||
ty::AutoBorrowVec(ty::re_static, m) => {
|
||||
ty::AutoBorrowVec(ty::ReStatic, m) => {
|
||||
assert!(m != ast::MutMutable);
|
||||
assert_eq!(abi::slice_elt_base, 0);
|
||||
assert_eq!(abi::slice_elt_len, 1);
|
||||
|
@ -588,7 +588,7 @@ impl Datum {
|
||||
// result (which will be by-value). Note that it is not
|
||||
// significant *which* region we pick here.
|
||||
let llval = self.to_ref_llval(bcx);
|
||||
let rptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::re_static,
|
||||
let rptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic,
|
||||
self.ty);
|
||||
Datum {val: llval, ty: rptr_ty, mode: ByValue}
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ pub fn trans_to_datum(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock {
|
||||
// real one, but it will have the same runtime representation
|
||||
let slice_ty = ty::mk_evec(tcx,
|
||||
ty::mt { ty: unit_ty, mutbl: ast::MutImmutable },
|
||||
ty::vstore_slice(ty::re_static));
|
||||
ty::vstore_slice(ty::ReStatic));
|
||||
|
||||
let scratch = scratch_datum(bcx, slice_ty, "__adjust", false);
|
||||
|
||||
|
@ -339,7 +339,7 @@ pub fn make_visit_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
||||
do with_scope(bcx, None, "visitor cleanup") |bcx| {
|
||||
let mut bcx = bcx;
|
||||
let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(),
|
||||
ty::re_static) {
|
||||
ty::ReStatic) {
|
||||
Ok(pair) => pair,
|
||||
Err(s) => {
|
||||
bcx.tcx().sess.fatal(s);
|
||||
|
@ -59,7 +59,7 @@ impl Reflector {
|
||||
// We're careful to not use first class aggregates here because that
|
||||
// will kick us off fast isel. (Issue #4352.)
|
||||
let bcx = self.bcx;
|
||||
let str_vstore = ty::vstore_slice(ty::re_static);
|
||||
let str_vstore = ty::vstore_slice(ty::ReStatic);
|
||||
let str_ty = ty::mk_estr(bcx.tcx(), str_vstore);
|
||||
let scratch = scratch_datum(bcx, str_ty, "", false);
|
||||
let len = C_uint(bcx.ccx(), s.len());
|
||||
|
@ -14,6 +14,7 @@ use middle::trans::common::*;
|
||||
use middle::trans::foreign;
|
||||
use middle::ty;
|
||||
use util::ppaux;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use middle::trans::type_::Type;
|
||||
|
||||
@ -172,14 +173,16 @@ pub fn sizing_type_of(cx: &mut CrateContext, t: ty::t) -> Type {
|
||||
|
||||
// NB: If you update this, be sure to update `sizing_type_of()` as well.
|
||||
pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type {
|
||||
debug!("type_of {:?}: {:?}", t, ty::get(t));
|
||||
|
||||
// Check the cache.
|
||||
match cx.lltypes.find(&t) {
|
||||
Some(&t) => return t,
|
||||
Some(&llty) => {
|
||||
return llty;
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
|
||||
debug!("type_of {} {:?}", t.repr(cx.tcx), t);
|
||||
|
||||
// Replace any typedef'd types with their equivalent non-typedef
|
||||
// type. This ensures that all LLVM nominal types that contain
|
||||
// Rust types are defined as the same LLVM types. If we don't do
|
||||
@ -189,6 +192,12 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type {
|
||||
|
||||
if t != t_norm {
|
||||
let llty = type_of(cx, t_norm);
|
||||
debug!("--> normalized {} {:?} to {} {:?} llty={}",
|
||||
t.repr(cx.tcx),
|
||||
t,
|
||||
t_norm.repr(cx.tcx),
|
||||
t_norm,
|
||||
cx.tn.type_to_str(llty));
|
||||
cx.lltypes.insert(t, llty);
|
||||
return llty;
|
||||
}
|
||||
@ -299,6 +308,10 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type {
|
||||
ty::ty_err(*) => cx.tcx.sess.bug("type_of with ty_err")
|
||||
};
|
||||
|
||||
debug!("--> mapped t={} {:?} to llty={}",
|
||||
t.repr(cx.tcx),
|
||||
t,
|
||||
cx.tn.type_to_str(llty));
|
||||
cx.lltypes.insert(t, llty);
|
||||
|
||||
// If this was an enum or struct, fill in the type now.
|
||||
|
@ -17,9 +17,12 @@ use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
|
||||
use middle::lang_items::OpaqueStructLangItem;
|
||||
use middle::freevars;
|
||||
use middle::resolve;
|
||||
use middle::resolve_lifetime;
|
||||
use middle::ty;
|
||||
use middle::subst::Subst;
|
||||
use middle::typeck;
|
||||
use middle::ty_fold;
|
||||
use middle::ty_fold::TypeFolder;
|
||||
use middle;
|
||||
use util::ppaux::{note_and_explain_region, bound_region_ptr_to_str};
|
||||
use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
|
||||
@ -206,13 +209,19 @@ pub enum ast_ty_to_ty_cache_entry {
|
||||
atttce_resolved(t) /* resolved to a type, irrespective of region */
|
||||
}
|
||||
|
||||
pub type opt_region_variance = Option<region_variance>;
|
||||
#[deriving(Clone, Eq, Decodable, Encodable)]
|
||||
pub struct ItemVariances {
|
||||
self_param: Option<Variance>,
|
||||
type_params: OptVec<Variance>,
|
||||
region_params: OptVec<Variance>
|
||||
}
|
||||
|
||||
#[deriving(Clone, Eq, Decodable, Encodable)]
|
||||
pub enum region_variance {
|
||||
rv_covariant,
|
||||
rv_invariant,
|
||||
rv_contravariant,
|
||||
pub enum Variance {
|
||||
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
|
||||
Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
|
||||
Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type
|
||||
Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
|
||||
}
|
||||
|
||||
#[deriving(Decodable, Encodable)]
|
||||
@ -258,8 +267,9 @@ struct ctxt_ {
|
||||
sess: session::Session,
|
||||
def_map: resolve::DefMap,
|
||||
|
||||
named_region_map: @mut resolve_lifetime::NamedRegionMap,
|
||||
|
||||
region_maps: @mut middle::region::RegionMaps,
|
||||
region_paramd_items: middle::region::region_paramd_items,
|
||||
|
||||
// Stores the types for various nodes in the AST. Note that this table
|
||||
// is not guaranteed to be populated until after typeck. See
|
||||
@ -304,6 +314,10 @@ struct ctxt_ {
|
||||
provided_method_sources: @mut HashMap<ast::DefId, ast::DefId>,
|
||||
supertraits: @mut HashMap<ast::DefId, @~[@TraitRef]>,
|
||||
|
||||
// Maps from def-id of a type or region parameter to its
|
||||
// (inferred) variance.
|
||||
item_variance_map: @mut HashMap<ast::DefId, @ItemVariances>,
|
||||
|
||||
// A mapping from the def ID of an enum or struct type to the def ID
|
||||
// of the method that implements its destructor. If the type is not
|
||||
// present in this map, it does not have a destructor. This map is
|
||||
@ -431,14 +445,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
|
||||
@ -453,86 +470,75 @@ 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 or fn declaration which will be
|
||||
// substituted 'early' -- that is, at the same time when type
|
||||
// parameters are substituted.
|
||||
ReEarlyBound(/* param id */ ast::NodeId, /*index*/ uint, ast::Ident),
|
||||
|
||||
// Region bound in a function scope, which will be substituted when the
|
||||
// function is called. The first argument must be the `binder_id` of
|
||||
// some enclosing function signature.
|
||||
ReLateBound(/* binder_id */ ast::NodeId, BoundRegion),
|
||||
|
||||
/// 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
|
||||
/// region parameters.
|
||||
re_free(FreeRegion),
|
||||
ReFree(FreeRegion),
|
||||
|
||||
/// A concrete region naming some expression within the current function.
|
||||
re_scope(NodeId),
|
||||
ReScope(NodeId),
|
||||
|
||||
/// Static data that has an "infinite" lifetime. Top in the region lattice.
|
||||
re_static,
|
||||
ReStatic,
|
||||
|
||||
/// A region variable. Should not exist after typeck.
|
||||
re_infer(InferRegion),
|
||||
ReInfer(InferRegion),
|
||||
|
||||
/// Empty lifetime is for data that is never accessed.
|
||||
/// Bottom in the region lattice. We treat re_empty somewhat
|
||||
/// Bottom in the region lattice. We treat ReEmpty somewhat
|
||||
/// specially; at least right now, we do not generate instances of
|
||||
/// it during the GLB computations, but rather
|
||||
/// generate an error instead. This is to improve error messages.
|
||||
/// The only way to get an instance of re_empty is to have a region
|
||||
/// The only way to get an instance of ReEmpty is to have a region
|
||||
/// variable with no constraints.
|
||||
re_empty,
|
||||
ReEmpty,
|
||||
}
|
||||
|
||||
impl Region {
|
||||
pub fn is_bound(&self) -> bool {
|
||||
match self {
|
||||
&re_bound(*) => true,
|
||||
&ty::ReEarlyBound(*) => true,
|
||||
&ty::ReLateBound(*) => 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
|
||||
bound_region: BoundRegion
|
||||
}
|
||||
|
||||
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
|
||||
pub enum bound_region {
|
||||
/// The self region for structs, impls (&T in a type defn or &'self T)
|
||||
br_self,
|
||||
|
||||
#[deriving(Clone, Eq, TotalEq, TotalOrd, IterBytes, Encodable, Decodable, ToStr)]
|
||||
pub enum BoundRegion {
|
||||
/// An anonymous region parameter for a given fn (&T)
|
||||
br_anon(uint),
|
||||
BrAnon(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.
|
||||
BrNamed(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),
|
||||
BrFresh(uint),
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the values to use when substituting lifetime parameters.
|
||||
* If the value is `ErasedRegions`, then this subst is occurring during
|
||||
* trans, and all region parameters will be replaced with `ty::re_static`. */
|
||||
* trans, and all region parameters will be replaced with `ty::ReStatic`. */
|
||||
#[deriving(Clone, Eq, IterBytes)]
|
||||
pub enum RegionSubsts {
|
||||
ErasedRegions,
|
||||
@ -697,8 +703,8 @@ pub enum type_err {
|
||||
terr_regions_does_not_outlive(Region, Region),
|
||||
terr_regions_not_same(Region, Region),
|
||||
terr_regions_no_overlap(Region, Region),
|
||||
terr_regions_insufficiently_polymorphic(bound_region, Region),
|
||||
terr_regions_overly_polymorphic(bound_region, Region),
|
||||
terr_regions_insufficiently_polymorphic(BoundRegion, Region),
|
||||
terr_regions_overly_polymorphic(BoundRegion, Region),
|
||||
terr_vstores_differ(terr_vstore_kind, expected_found<vstore>),
|
||||
terr_trait_stores_differ(terr_vstore_kind, expected_found<TraitStore>),
|
||||
terr_in_field(@type_err, ast::Ident),
|
||||
@ -774,7 +780,7 @@ pub enum InferTy {
|
||||
#[deriving(Clone, Encodable, Decodable, IterBytes, ToStr)]
|
||||
pub enum InferRegion {
|
||||
ReVar(RegionVid),
|
||||
ReSkolemized(uint, bound_region)
|
||||
ReSkolemized(uint, BoundRegion)
|
||||
}
|
||||
|
||||
impl cmp::Eq for InferRegion {
|
||||
@ -863,12 +869,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 {
|
||||
@ -877,6 +892,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
|
||||
@ -919,13 +961,15 @@ pub fn new_ty_hash<V:'static>() -> @mut HashMap<t, V> {
|
||||
|
||||
pub fn mk_ctxt(s: session::Session,
|
||||
dm: resolve::DefMap,
|
||||
named_region_map: @mut resolve_lifetime::NamedRegionMap,
|
||||
amap: ast_map::map,
|
||||
freevars: freevars::freevar_map,
|
||||
region_maps: @mut middle::region::RegionMaps,
|
||||
region_paramd_items: middle::region::region_paramd_items,
|
||||
lang_items: middle::lang_items::LanguageItems)
|
||||
-> ctxt {
|
||||
@ctxt_ {
|
||||
named_region_map: named_region_map,
|
||||
item_variance_map: @mut HashMap::new(),
|
||||
diag: s.diagnostic(),
|
||||
interner: @mut HashMap::new(),
|
||||
next_id: @mut primitives::LAST_PRIMITIVE_ID,
|
||||
@ -933,7 +977,6 @@ pub fn mk_ctxt(s: session::Session,
|
||||
sess: s,
|
||||
def_map: dm,
|
||||
region_maps: region_maps,
|
||||
region_paramd_items: region_paramd_items,
|
||||
node_types: @mut HashMap::new(),
|
||||
node_type_substs: @mut HashMap::new(),
|
||||
trait_refs: @mut HashMap::new(),
|
||||
@ -978,7 +1021,7 @@ pub fn mk_ctxt(s: session::Session,
|
||||
|
||||
// Interns a type/name combination, stores the resulting box in cx.interner,
|
||||
// and returns the box as cast to an unsafe ptr (see comments for t above).
|
||||
fn mk_t(cx: ctxt, st: sty) -> t {
|
||||
pub fn mk_t(cx: ctxt, st: sty) -> t {
|
||||
// Check for primitive types.
|
||||
match st {
|
||||
ty_nil => return mk_nil(),
|
||||
@ -987,6 +1030,8 @@ fn mk_t(cx: ctxt, st: sty) -> t {
|
||||
ty_int(i) => return mk_mach_int(i),
|
||||
ty_uint(u) => return mk_mach_uint(u),
|
||||
ty_float(f) => return mk_mach_float(f),
|
||||
ty_char => return mk_char(),
|
||||
ty_bot => return mk_bot(),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
@ -1000,7 +1045,7 @@ fn mk_t(cx: ctxt, st: sty) -> t {
|
||||
fn rflags(r: Region) -> uint {
|
||||
(has_regions as uint) | {
|
||||
match r {
|
||||
ty::re_infer(_) => needs_infer as uint,
|
||||
ty::ReInfer(_) => needs_infer as uint,
|
||||
_ => 0u
|
||||
}
|
||||
}
|
||||
@ -1246,14 +1291,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
|
||||
@ -1333,224 +1381,70 @@ pub fn maybe_walk_ty(ty: t, f: &fn(t) -> bool) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_sty_to_ty(tcx: ty::ctxt, sty: &sty, foldop: &fn(t) -> t) -> t {
|
||||
mk_t(tcx, fold_sty(sty, foldop))
|
||||
}
|
||||
|
||||
pub fn fold_sig(sig: &FnSig, fldop: &fn(t) -> t) -> FnSig {
|
||||
let args = sig.inputs.map(|arg| fldop(*arg));
|
||||
|
||||
FnSig {
|
||||
bound_lifetime_names: sig.bound_lifetime_names.clone(),
|
||||
inputs: args,
|
||||
output: fldop(sig.output),
|
||||
variadic: sig.variadic
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_bare_fn_ty(fty: &BareFnTy, fldop: &fn(t) -> t) -> BareFnTy {
|
||||
BareFnTy {sig: fold_sig(&fty.sig, fldop),
|
||||
abis: fty.abis,
|
||||
purity: fty.purity}
|
||||
}
|
||||
|
||||
fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty {
|
||||
fn fold_substs(substs: &substs, fldop: &fn(t) -> t) -> substs {
|
||||
substs {regions: substs.regions.clone(),
|
||||
self_ty: substs.self_ty.map(|t| fldop(t)),
|
||||
tps: substs.tps.map(|t| fldop(*t))}
|
||||
}
|
||||
|
||||
match *sty {
|
||||
ty_box(ref tm) => {
|
||||
ty_box(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
|
||||
}
|
||||
ty_uniq(ref tm) => {
|
||||
ty_uniq(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
|
||||
}
|
||||
ty_ptr(ref tm) => {
|
||||
ty_ptr(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
|
||||
}
|
||||
ty_unboxed_vec(ref tm) => {
|
||||
ty_unboxed_vec(mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
|
||||
}
|
||||
ty_evec(ref tm, vst) => {
|
||||
ty_evec(mt {ty: fldop(tm.ty), mutbl: tm.mutbl}, vst)
|
||||
}
|
||||
ty_enum(tid, ref substs) => {
|
||||
ty_enum(tid, fold_substs(substs, fldop))
|
||||
}
|
||||
ty_trait(did, ref substs, st, mutbl, bounds) => {
|
||||
ty_trait(did, fold_substs(substs, fldop), st, mutbl, bounds)
|
||||
}
|
||||
ty_tup(ref ts) => {
|
||||
let new_ts = ts.map(|tt| fldop(*tt));
|
||||
ty_tup(new_ts)
|
||||
}
|
||||
ty_bare_fn(ref f) => {
|
||||
ty_bare_fn(fold_bare_fn_ty(f, fldop))
|
||||
}
|
||||
ty_closure(ref f) => {
|
||||
let sig = fold_sig(&f.sig, fldop);
|
||||
ty_closure(ClosureTy {
|
||||
sig: sig,
|
||||
purity: f.purity,
|
||||
sigil: f.sigil,
|
||||
onceness: f.onceness,
|
||||
region: f.region,
|
||||
bounds: f.bounds,
|
||||
})
|
||||
}
|
||||
ty_rptr(r, ref tm) => {
|
||||
ty_rptr(r, mt {ty: fldop(tm.ty), mutbl: tm.mutbl})
|
||||
}
|
||||
ty_struct(did, ref substs) => {
|
||||
ty_struct(did, fold_substs(substs, fldop))
|
||||
}
|
||||
ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
|
||||
ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) | ty_err |
|
||||
ty_opaque_box | ty_infer(_) | ty_param(*) | ty_self(_) => {
|
||||
(*sty).clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Folds types from the bottom up.
|
||||
pub fn fold_ty(cx: ctxt, t0: t, fldop: &fn(t) -> t) -> t {
|
||||
let sty = fold_sty(&get(t0).sty, |t| fold_ty(cx, fldop(t), |t| fldop(t)));
|
||||
fldop(mk_t(cx, sty))
|
||||
let mut f = ty_fold::BottomUpFolder {tcx: cx, fldop: fldop};
|
||||
f.fold_ty(t0)
|
||||
}
|
||||
|
||||
pub fn walk_regions_and_ty(
|
||||
cx: ctxt,
|
||||
ty: t,
|
||||
walkr: &fn(r: Region),
|
||||
walkt: &fn(t: t) -> bool) {
|
||||
|
||||
if (walkt(ty)) {
|
||||
fold_regions_and_ty(
|
||||
cx, ty,
|
||||
|r| { walkr(r); r },
|
||||
|t| { walk_regions_and_ty(cx, t, |r| walkr(r), |t| walkt(t)); t },
|
||||
|t| { walk_regions_and_ty(cx, t, |r| walkr(r), |t| walkt(t)); t });
|
||||
}
|
||||
pub fn walk_regions_and_ty(cx: ctxt,
|
||||
ty: t,
|
||||
fldr: &fn(r: Region),
|
||||
fldt: &fn(t: t))
|
||||
-> t {
|
||||
ty_fold::RegionFolder::general(cx,
|
||||
|r| { fldr(r); r },
|
||||
|t| { fldt(t); t }).fold_ty(ty)
|
||||
}
|
||||
|
||||
pub fn fold_regions_and_ty(
|
||||
cx: ctxt,
|
||||
ty: t,
|
||||
fldr: &fn(r: Region) -> Region,
|
||||
fldfnt: &fn(t: t) -> t,
|
||||
fldt: &fn(t: t) -> t) -> t {
|
||||
|
||||
fn fold_substs(
|
||||
substs: &substs,
|
||||
fldr: &fn(r: Region) -> Region,
|
||||
fldt: &fn(t: t) -> t)
|
||||
-> substs {
|
||||
let regions = match substs.regions {
|
||||
ErasedRegions => ErasedRegions,
|
||||
NonerasedRegions(ref regions) => {
|
||||
NonerasedRegions(regions.map(|r| fldr(*r)))
|
||||
}
|
||||
};
|
||||
|
||||
substs {
|
||||
regions: regions,
|
||||
self_ty: substs.self_ty.map(|t| fldt(t)),
|
||||
tps: substs.tps.map(|t| fldt(*t))
|
||||
}
|
||||
}
|
||||
|
||||
let tb = ty::get(ty);
|
||||
match tb.sty {
|
||||
ty::ty_rptr(r, mt) => {
|
||||
let m_r = fldr(r);
|
||||
let m_t = fldt(mt.ty);
|
||||
ty::mk_rptr(cx, m_r, mt {ty: m_t, mutbl: mt.mutbl})
|
||||
}
|
||||
ty_estr(vstore_slice(r)) => {
|
||||
let m_r = fldr(r);
|
||||
ty::mk_estr(cx, vstore_slice(m_r))
|
||||
}
|
||||
ty_evec(mt, vstore_slice(r)) => {
|
||||
let m_r = fldr(r);
|
||||
let m_t = fldt(mt.ty);
|
||||
ty::mk_evec(cx, mt {ty: m_t, mutbl: mt.mutbl}, vstore_slice(m_r))
|
||||
}
|
||||
ty_enum(def_id, ref substs) => {
|
||||
ty::mk_enum(cx, def_id, fold_substs(substs, fldr, fldt))
|
||||
}
|
||||
ty_struct(def_id, ref substs) => {
|
||||
ty::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt))
|
||||
}
|
||||
ty_trait(def_id, ref substs, st, mutbl, bounds) => {
|
||||
let st = match st {
|
||||
RegionTraitStore(region) => RegionTraitStore(fldr(region)),
|
||||
st => st,
|
||||
};
|
||||
ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl, bounds)
|
||||
}
|
||||
ty_bare_fn(ref f) => {
|
||||
ty::mk_bare_fn(cx, BareFnTy {
|
||||
sig: fold_sig(&f.sig, fldfnt),
|
||||
purity: f.purity,
|
||||
abis: f.abis.clone(),
|
||||
})
|
||||
}
|
||||
ty_closure(ref f) => {
|
||||
ty::mk_closure(cx, ClosureTy {
|
||||
region: fldr(f.region),
|
||||
sig: fold_sig(&f.sig, fldfnt),
|
||||
purity: f.purity,
|
||||
sigil: f.sigil,
|
||||
onceness: f.onceness,
|
||||
bounds: f.bounds,
|
||||
})
|
||||
}
|
||||
ref sty => {
|
||||
fold_sty_to_ty(cx, sty, |t| fldt(t))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// n.b. this function is intended to eventually replace fold_region() below,
|
||||
// that is why its name is so similar.
|
||||
pub fn fold_regions(
|
||||
cx: ctxt,
|
||||
ty: t,
|
||||
fldr: &fn(r: Region, in_fn: bool) -> Region) -> t {
|
||||
fn do_fold(cx: ctxt, ty: t, in_fn: bool,
|
||||
fldr: &fn(Region, bool) -> Region) -> t {
|
||||
debug!("do_fold(ty={}, in_fn={})", ty_to_str(cx, ty), in_fn);
|
||||
if !type_has_regions(ty) { return ty; }
|
||||
fold_regions_and_ty(
|
||||
cx, ty,
|
||||
|r| fldr(r, in_fn),
|
||||
|t| do_fold(cx, t, true, |r,b| fldr(r,b)),
|
||||
|t| do_fold(cx, t, in_fn, |r,b| fldr(r,b)))
|
||||
}
|
||||
do_fold(cx, ty, false, fldr)
|
||||
pub fn fold_regions(cx: ctxt,
|
||||
ty: t,
|
||||
fldr: &fn(r: Region) -> Region)
|
||||
-> t {
|
||||
ty_fold::RegionFolder::regions(cx, fldr).fold_ty(ty)
|
||||
}
|
||||
|
||||
// Substitute *only* type parameters. Used in trans where regions are erased.
|
||||
pub fn subst_tps(cx: ctxt, tps: &[t], self_ty_opt: Option<t>, typ: t) -> t {
|
||||
if tps.len() == 0u && self_ty_opt.is_none() { return typ; }
|
||||
let tb = ty::get(typ);
|
||||
if self_ty_opt.is_none() && !tbox_has_flag(tb, has_params) { return typ; }
|
||||
match tb.sty {
|
||||
ty_param(p) => tps[p.idx],
|
||||
ty_self(_) => {
|
||||
match self_ty_opt {
|
||||
None => cx.sess.bug("ty_self unexpected here"),
|
||||
Some(self_ty) => {
|
||||
subst_tps(cx, tps, self_ty_opt, self_ty)
|
||||
pub fn subst_tps(tcx: ctxt, tps: &[t], self_ty_opt: Option<t>, typ: t) -> t {
|
||||
let mut subst = TpsSubst { tcx: tcx, self_ty_opt: self_ty_opt, tps: tps };
|
||||
return subst.fold_ty(typ);
|
||||
|
||||
pub struct TpsSubst<'self> {
|
||||
tcx: ctxt,
|
||||
self_ty_opt: Option<t>,
|
||||
tps: &'self [t],
|
||||
}
|
||||
|
||||
impl<'self> TypeFolder for TpsSubst<'self> {
|
||||
fn tcx(&self) -> ty::ctxt { self.tcx }
|
||||
|
||||
fn fold_ty(&mut self, t: ty::t) -> ty::t {
|
||||
if self.tps.len() == 0u && self.self_ty_opt.is_none() {
|
||||
return t;
|
||||
}
|
||||
|
||||
let tb = ty::get(t);
|
||||
if self.self_ty_opt.is_none() && !tbox_has_flag(tb, has_params) {
|
||||
return t;
|
||||
}
|
||||
|
||||
match ty::get(t).sty {
|
||||
ty_param(p) => {
|
||||
self.tps[p.idx]
|
||||
}
|
||||
|
||||
ty_self(_) => {
|
||||
match self.self_ty_opt {
|
||||
None => self.tcx.sess.bug("ty_self unexpected here"),
|
||||
Some(self_ty) => self_ty
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
ty_fold::super_fold_ty(self, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
ref sty => {
|
||||
fold_sty_to_ty(cx, sty, |t| subst_tps(cx, tps, self_ty_opt, t))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2256,7 +2150,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
|
||||
ast::MutMutable => TC::ReachesMutable | TC::OwnsAffine,
|
||||
ast::MutImmutable => TC::None,
|
||||
};
|
||||
b | (TC::ReachesBorrowed).when(region != ty::re_static)
|
||||
b | (TC::ReachesBorrowed).when(region != ty::ReStatic)
|
||||
}
|
||||
|
||||
fn closure_contents(cx: ctxt, cty: &ClosureTy) -> TypeContents {
|
||||
@ -2722,55 +2616,6 @@ pub fn index_sty(sty: &sty) -> Option<mt> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces an arbitrary but consistent total ordering over
|
||||
* free regions. This is needed for establishing a consistent
|
||||
* LUB in region_inference. */
|
||||
impl cmp::TotalOrd for FreeRegion {
|
||||
fn cmp(&self, other: &FreeRegion) -> Ordering {
|
||||
cmp::cmp2(&self.scope_id, &self.bound_region,
|
||||
&other.scope_id, &other.bound_region)
|
||||
}
|
||||
}
|
||||
|
||||
impl cmp::TotalEq for FreeRegion {
|
||||
fn equals(&self, other: &FreeRegion) -> bool {
|
||||
*self == *other
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces an arbitrary but consistent total ordering over
|
||||
* bound regions. This is needed for establishing a consistent
|
||||
* LUB in region_inference. */
|
||||
impl cmp::TotalOrd for bound_region {
|
||||
fn cmp(&self, other: &bound_region) -> Ordering {
|
||||
match (self, other) {
|
||||
(&ty::br_self, &ty::br_self) => cmp::Equal,
|
||||
(&ty::br_self, _) => cmp::Less,
|
||||
|
||||
(&ty::br_anon(ref a1), &ty::br_anon(ref a2)) => a1.cmp(a2),
|
||||
(&ty::br_anon(*), _) => cmp::Less,
|
||||
|
||||
(&ty::br_named(ref a1), &ty::br_named(ref a2)) => a1.name.cmp(&a2.name),
|
||||
(&ty::br_named(*), _) => cmp::Less,
|
||||
|
||||
(&ty::br_cap_avoid(ref a1, @ref b1),
|
||||
&ty::br_cap_avoid(ref a2, @ref b2)) => cmp::cmp2(a1, b1, a2, b2),
|
||||
(&ty::br_cap_avoid(*), _) => cmp::Less,
|
||||
|
||||
(&ty::br_fresh(ref a1), &ty::br_fresh(ref a2)) => a1.cmp(a2),
|
||||
(&ty::br_fresh(*), _) => cmp::Less,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl cmp::TotalEq for bound_region {
|
||||
fn equals(&self, other: &bound_region) -> bool {
|
||||
*self == *other
|
||||
}
|
||||
}
|
||||
|
||||
pub fn node_id_to_trait_ref(cx: ctxt, id: ast::NodeId) -> @ty::TraitRef {
|
||||
match cx.trait_refs.find(&id) {
|
||||
Some(&t) => t,
|
||||
@ -3679,7 +3524,6 @@ fn lookup_locally_or_in_crate_store<V:Clone>(
|
||||
load_external: &fn() -> V) -> V
|
||||
{
|
||||
/*!
|
||||
*
|
||||
* Helper for looking things up in the various maps
|
||||
* that are populated during typeck::collect (e.g.,
|
||||
* `cx.methods`, `cx.tcache`, etc). All of these share
|
||||
@ -3689,8 +3533,8 @@ fn lookup_locally_or_in_crate_store<V:Clone>(
|
||||
* the crate loading code (and cache the result for the future).
|
||||
*/
|
||||
|
||||
match map.find(&def_id) {
|
||||
Some(&ref v) => { return (*v).clone(); }
|
||||
match map.find_copy(&def_id) {
|
||||
Some(v) => { return v; }
|
||||
None => { }
|
||||
}
|
||||
|
||||
@ -3728,7 +3572,7 @@ pub fn method(cx: ctxt, id: ast::DefId) -> @Method {
|
||||
|
||||
pub fn trait_method_def_ids(cx: ctxt, id: ast::DefId) -> @~[DefId] {
|
||||
lookup_locally_or_in_crate_store(
|
||||
"methods", id, cx.trait_method_def_ids,
|
||||
"trait_method_def_ids", id, cx.trait_method_def_ids,
|
||||
|| @csearch::get_trait_method_def_ids(cx.cstore, id))
|
||||
}
|
||||
|
||||
@ -4354,77 +4198,57 @@ pub fn ty_params_to_tys(tcx: ty::ctxt, generics: &ast::Generics) -> ~[t] {
|
||||
|
||||
/// Returns an equivalent type with all the typedefs and self regions removed.
|
||||
pub fn normalize_ty(cx: ctxt, t: t) -> t {
|
||||
fn normalize_mt(cx: ctxt, mt: mt) -> mt {
|
||||
mt { ty: normalize_ty(cx, mt.ty), mutbl: mt.mutbl }
|
||||
}
|
||||
fn normalize_vstore(vstore: vstore) -> vstore {
|
||||
match vstore {
|
||||
vstore_fixed(*) | vstore_uniq | vstore_box => vstore,
|
||||
vstore_slice(_) => vstore_slice(re_static)
|
||||
}
|
||||
}
|
||||
let u = TypeNormalizer(cx).fold_ty(t);
|
||||
return u;
|
||||
|
||||
match cx.normalized_cache.find(&t) {
|
||||
Some(&t) => return t,
|
||||
None => ()
|
||||
}
|
||||
struct TypeNormalizer(ctxt);
|
||||
|
||||
let t = match get(t).sty {
|
||||
ty_evec(mt, vstore) =>
|
||||
// This type has a vstore. Get rid of it
|
||||
mk_evec(cx, normalize_mt(cx, mt), normalize_vstore(vstore)),
|
||||
impl TypeFolder for TypeNormalizer {
|
||||
fn tcx(&self) -> ty::ctxt { **self }
|
||||
|
||||
ty_estr(vstore) =>
|
||||
// This type has a vstore. Get rid of it
|
||||
mk_estr(cx, normalize_vstore(vstore)),
|
||||
|
||||
ty_rptr(_, mt) =>
|
||||
// This type has a region. Get rid of it
|
||||
mk_rptr(cx, re_static, normalize_mt(cx, mt)),
|
||||
|
||||
ty_closure(ref closure_ty) => {
|
||||
mk_closure(cx, ClosureTy {
|
||||
region: ty::re_static,
|
||||
..(*closure_ty).clone()
|
||||
})
|
||||
}
|
||||
|
||||
ty_enum(did, ref r) => {
|
||||
match (*r).regions {
|
||||
NonerasedRegions(_) => {
|
||||
// trans doesn't care about regions
|
||||
mk_enum(cx, did, substs {regions: ty::ErasedRegions,
|
||||
self_ty: None,
|
||||
tps: (*r).tps.clone()})
|
||||
fn fold_ty(&mut self, t: ty::t) -> ty::t {
|
||||
match self.tcx().normalized_cache.find_copy(&t) {
|
||||
Some(u) => {
|
||||
return u;
|
||||
}
|
||||
ErasedRegions => {
|
||||
t
|
||||
None => {
|
||||
let t_norm = ty_fold::super_fold_ty(self, t);
|
||||
self.tcx().normalized_cache.insert(t, t_norm);
|
||||
return t_norm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty_struct(did, ref r) => {
|
||||
match (*r).regions {
|
||||
NonerasedRegions(_) => {
|
||||
// Ditto.
|
||||
mk_struct(cx, did, substs {regions: ty::ErasedRegions,
|
||||
self_ty: None,
|
||||
tps: (*r).tps.clone()})
|
||||
}
|
||||
ErasedRegions => {
|
||||
t
|
||||
}
|
||||
fn fold_vstore(&mut self, vstore: vstore) -> vstore {
|
||||
match vstore {
|
||||
vstore_fixed(*) | vstore_uniq | vstore_box => vstore,
|
||||
vstore_slice(_) => vstore_slice(ReStatic)
|
||||
}
|
||||
}
|
||||
|
||||
_ =>
|
||||
t
|
||||
};
|
||||
fn fold_region(&mut self, _: ty::Region) -> ty::Region {
|
||||
ty::ReStatic
|
||||
}
|
||||
|
||||
let sty = fold_sty(&get(t).sty, |t| { normalize_ty(cx, t) });
|
||||
let t_norm = mk_t(cx, sty);
|
||||
cx.normalized_cache.insert(t, t_norm);
|
||||
return t_norm;
|
||||
fn fold_substs(&mut self,
|
||||
substs: &substs)
|
||||
-> substs {
|
||||
substs { regions: ErasedRegions,
|
||||
self_ty: ty_fold::fold_opt_ty(self, substs.self_ty),
|
||||
tps: ty_fold::fold_ty_vec(self, substs.tps) }
|
||||
}
|
||||
|
||||
fn fold_sig(&mut self,
|
||||
sig: &ty::FnSig)
|
||||
-> ty::FnSig {
|
||||
// The binder-id is only relevant to bound regions, which
|
||||
// are erased at trans time.
|
||||
ty::FnSig { binder_id: ast::DUMMY_NODE_ID,
|
||||
inputs: ty_fold::fold_ty_vec(self, sig.inputs),
|
||||
output: self.fold_ty(sig.output),
|
||||
variadic: sig.variadic }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ExprTyProvider {
|
||||
@ -4597,6 +4421,12 @@ pub fn visitor_object_ty(tcx: ctxt,
|
||||
EmptyBuiltinBounds())))
|
||||
}
|
||||
|
||||
pub fn item_variances(tcx: ctxt, item_id: ast::DefId) -> @ItemVariances {
|
||||
lookup_locally_or_in_crate_store(
|
||||
"item_variance_map", item_id, tcx.item_variance_map,
|
||||
|| @csearch::get_item_variances(tcx.cstore, item_id))
|
||||
}
|
||||
|
||||
/// Records a trait-to-implementation mapping.
|
||||
fn record_trait_implementation(tcx: ctxt,
|
||||
trait_def_id: DefId,
|
||||
@ -4737,10 +4567,16 @@ pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: @str) -> u64 {
|
||||
let mut hash = SipState::new(0, 0);
|
||||
let region = |_hash: &mut SipState, r: Region| {
|
||||
match r {
|
||||
re_static => {}
|
||||
ReStatic => {}
|
||||
|
||||
re_empty | re_bound(*) | re_free(*) | re_scope(*) | re_infer(*) =>
|
||||
ReEmpty |
|
||||
ReEarlyBound(*) |
|
||||
ReLateBound(*) |
|
||||
ReFree(*) |
|
||||
ReScope(*) |
|
||||
ReInfer(*) => {
|
||||
tcx.sess.bug("non-static region found when hashing a type")
|
||||
}
|
||||
}
|
||||
};
|
||||
let vstore = |hash: &mut SipState, v: vstore| {
|
||||
@ -4878,3 +4714,90 @@ pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: @str) -> u64 {
|
||||
|
||||
hash.result_u64()
|
||||
}
|
||||
|
||||
impl Variance {
|
||||
pub fn to_str(self) -> &'static str {
|
||||
match self {
|
||||
Covariant => "+",
|
||||
Contravariant => "-",
|
||||
Invariant => "o",
|
||||
Bivariant => "*",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::ReFree(ty::FreeRegion {
|
||||
scope_id: free_id,
|
||||
bound_region: ty::BrNamed(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
286
src/librustc/middle/ty_fold.rs
Normal file
286
src/librustc/middle/ty_fold.rs
Normal file
@ -0,0 +1,286 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Generalized type folding mechanism.
|
||||
|
||||
use middle::ty;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub trait TypeFolder {
|
||||
fn tcx(&self) -> ty::ctxt;
|
||||
|
||||
fn fold_ty(&mut self, t: ty::t) -> ty::t {
|
||||
super_fold_ty(self, t)
|
||||
}
|
||||
|
||||
fn fold_mt(&mut self, t: &ty::mt) -> ty::mt {
|
||||
super_fold_mt(self, t)
|
||||
}
|
||||
|
||||
fn fold_trait_ref(&mut self, t: &ty::TraitRef) -> ty::TraitRef {
|
||||
super_fold_trait_ref(self, t)
|
||||
}
|
||||
|
||||
fn fold_sty(&mut self, sty: &ty::sty) -> ty::sty {
|
||||
super_fold_sty(self, sty)
|
||||
}
|
||||
|
||||
fn fold_substs(&mut self,
|
||||
substs: &ty::substs)
|
||||
-> ty::substs {
|
||||
super_fold_substs(self, substs)
|
||||
}
|
||||
|
||||
fn fold_sig(&mut self,
|
||||
sig: &ty::FnSig)
|
||||
-> ty::FnSig {
|
||||
super_fold_sig(self, sig)
|
||||
}
|
||||
|
||||
fn fold_bare_fn_ty(&mut self,
|
||||
fty: &ty::BareFnTy)
|
||||
-> ty::BareFnTy {
|
||||
ty::BareFnTy { sig: self.fold_sig(&fty.sig),
|
||||
abis: fty.abis,
|
||||
purity: fty.purity }
|
||||
}
|
||||
|
||||
fn fold_closure_ty(&mut self,
|
||||
fty: &ty::ClosureTy)
|
||||
-> ty::ClosureTy {
|
||||
ty::ClosureTy {
|
||||
region: self.fold_region(fty.region),
|
||||
sig: self.fold_sig(&fty.sig),
|
||||
purity: fty.purity,
|
||||
sigil: fty.sigil,
|
||||
onceness: fty.onceness,
|
||||
bounds: fty.bounds,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
|
||||
r
|
||||
}
|
||||
|
||||
fn fold_vstore(&mut self, vstore: ty::vstore) -> ty::vstore {
|
||||
super_fold_vstore(self, vstore)
|
||||
}
|
||||
|
||||
fn fold_trait_store(&mut self, s: ty::TraitStore) -> ty::TraitStore {
|
||||
super_fold_trait_store(self, s)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_opt_ty<T:TypeFolder>(this: &mut T,
|
||||
t: Option<ty::t>)
|
||||
-> Option<ty::t> {
|
||||
t.map(|t| this.fold_ty(t))
|
||||
}
|
||||
|
||||
pub fn fold_ty_vec<T:TypeFolder>(this: &mut T,
|
||||
tys: &[ty::t])
|
||||
-> ~[ty::t] {
|
||||
tys.map(|t| this.fold_ty(*t))
|
||||
}
|
||||
|
||||
pub fn super_fold_ty<T:TypeFolder>(this: &mut T,
|
||||
t: ty::t)
|
||||
-> ty::t {
|
||||
ty::mk_t(this.tcx(), this.fold_sty(&ty::get(t).sty))
|
||||
}
|
||||
|
||||
pub fn super_fold_substs<T:TypeFolder>(this: &mut T,
|
||||
substs: &ty::substs)
|
||||
-> ty::substs {
|
||||
let regions = match substs.regions {
|
||||
ty::ErasedRegions => {
|
||||
ty::ErasedRegions
|
||||
}
|
||||
ty::NonerasedRegions(ref regions) => {
|
||||
ty::NonerasedRegions(regions.map(|r| this.fold_region(*r)))
|
||||
}
|
||||
};
|
||||
|
||||
ty::substs { regions: regions,
|
||||
self_ty: fold_opt_ty(this, substs.self_ty),
|
||||
tps: fold_ty_vec(this, substs.tps), }
|
||||
}
|
||||
|
||||
pub fn super_fold_sig<T:TypeFolder>(this: &mut T,
|
||||
sig: &ty::FnSig)
|
||||
-> ty::FnSig {
|
||||
ty::FnSig { binder_id: sig.binder_id,
|
||||
inputs: fold_ty_vec(this, sig.inputs),
|
||||
output: this.fold_ty(sig.output),
|
||||
variadic: sig.variadic }
|
||||
}
|
||||
|
||||
pub fn super_fold_trait_ref<T:TypeFolder>(this: &mut T,
|
||||
t: &ty::TraitRef)
|
||||
-> ty::TraitRef {
|
||||
ty::TraitRef {
|
||||
def_id: t.def_id,
|
||||
substs: this.fold_substs(&t.substs)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn super_fold_mt<T:TypeFolder>(this: &mut T,
|
||||
mt: &ty::mt) -> ty::mt {
|
||||
ty::mt {ty: this.fold_ty(mt.ty),
|
||||
mutbl: mt.mutbl}
|
||||
}
|
||||
|
||||
pub fn super_fold_sty<T:TypeFolder>(this: &mut T,
|
||||
sty: &ty::sty) -> ty::sty {
|
||||
match *sty {
|
||||
ty::ty_box(ref tm) => {
|
||||
ty::ty_box(this.fold_mt(tm))
|
||||
}
|
||||
ty::ty_uniq(ref tm) => {
|
||||
ty::ty_uniq(this.fold_mt(tm))
|
||||
}
|
||||
ty::ty_ptr(ref tm) => {
|
||||
ty::ty_ptr(this.fold_mt(tm))
|
||||
}
|
||||
ty::ty_unboxed_vec(ref tm) => {
|
||||
ty::ty_unboxed_vec(this.fold_mt(tm))
|
||||
}
|
||||
ty::ty_evec(ref tm, vst) => {
|
||||
ty::ty_evec(this.fold_mt(tm),
|
||||
this.fold_vstore(vst))
|
||||
}
|
||||
ty::ty_enum(tid, ref substs) => {
|
||||
ty::ty_enum(tid, this.fold_substs(substs))
|
||||
}
|
||||
ty::ty_trait(did, ref substs, st, mutbl, bounds) => {
|
||||
ty::ty_trait(did,
|
||||
this.fold_substs(substs),
|
||||
this.fold_trait_store(st),
|
||||
mutbl,
|
||||
bounds)
|
||||
}
|
||||
ty::ty_tup(ref ts) => {
|
||||
ty::ty_tup(fold_ty_vec(this, *ts))
|
||||
}
|
||||
ty::ty_bare_fn(ref f) => {
|
||||
ty::ty_bare_fn(this.fold_bare_fn_ty(f))
|
||||
}
|
||||
ty::ty_closure(ref f) => {
|
||||
ty::ty_closure(this.fold_closure_ty(f))
|
||||
}
|
||||
ty::ty_rptr(r, ref tm) => {
|
||||
ty::ty_rptr(this.fold_region(r),
|
||||
ty::mt {ty: this.fold_ty(tm.ty),
|
||||
mutbl: tm.mutbl})
|
||||
}
|
||||
ty::ty_struct(did, ref substs) => {
|
||||
ty::ty_struct(did,
|
||||
this.fold_substs(substs))
|
||||
}
|
||||
ty::ty_estr(vst) => {
|
||||
ty::ty_estr(this.fold_vstore(vst))
|
||||
}
|
||||
ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char |
|
||||
ty::ty_int(_) | ty::ty_uint(_) |
|
||||
ty::ty_float(_) | ty::ty_type |
|
||||
ty::ty_opaque_closure_ptr(_) |
|
||||
ty::ty_err | ty::ty_opaque_box | ty::ty_infer(_) |
|
||||
ty::ty_param(*) | ty::ty_self(_) => {
|
||||
(*sty).clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn super_fold_vstore<T:TypeFolder>(this: &mut T,
|
||||
vstore: ty::vstore)
|
||||
-> ty::vstore {
|
||||
match vstore {
|
||||
ty::vstore_fixed(i) => ty::vstore_fixed(i),
|
||||
ty::vstore_uniq => ty::vstore_uniq,
|
||||
ty::vstore_box => ty::vstore_box,
|
||||
ty::vstore_slice(r) => ty::vstore_slice(this.fold_region(r)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn super_fold_trait_store<T:TypeFolder>(this: &mut T,
|
||||
trait_store: ty::TraitStore)
|
||||
-> ty::TraitStore {
|
||||
match trait_store {
|
||||
ty::UniqTraitStore => ty::UniqTraitStore,
|
||||
ty::BoxTraitStore => ty::BoxTraitStore,
|
||||
ty::RegionTraitStore(r) => ty::RegionTraitStore(this.fold_region(r)),
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Some sample folders
|
||||
|
||||
pub struct BottomUpFolder<'self> {
|
||||
tcx: ty::ctxt,
|
||||
fldop: &'self fn(ty::t) -> ty::t,
|
||||
}
|
||||
|
||||
impl<'self> TypeFolder for BottomUpFolder<'self> {
|
||||
fn tcx(&self) -> ty::ctxt { self.tcx }
|
||||
|
||||
fn fold_ty(&mut self, ty: ty::t) -> ty::t {
|
||||
let t1 = super_fold_ty(self, ty);
|
||||
(self.fldop)(t1)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Region folder
|
||||
|
||||
pub struct RegionFolder<'self> {
|
||||
tcx: ty::ctxt,
|
||||
fld_t: &'self fn(ty::t) -> ty::t,
|
||||
fld_r: &'self fn(ty::Region) -> ty::Region,
|
||||
}
|
||||
|
||||
impl<'self> RegionFolder<'self> {
|
||||
pub fn general(tcx: ty::ctxt,
|
||||
fld_r: &'self fn(ty::Region) -> ty::Region,
|
||||
fld_t: &'self fn(ty::t) -> ty::t)
|
||||
-> RegionFolder<'self> {
|
||||
RegionFolder {
|
||||
tcx: tcx,
|
||||
fld_t: fld_t,
|
||||
fld_r: fld_r
|
||||
}
|
||||
}
|
||||
|
||||
pub fn regions(tcx: ty::ctxt,
|
||||
fld_r: &'self fn(ty::Region) -> ty::Region)
|
||||
-> RegionFolder<'self> {
|
||||
fn noop(t: ty::t) -> ty::t { t }
|
||||
|
||||
RegionFolder {
|
||||
tcx: tcx,
|
||||
fld_t: noop,
|
||||
fld_r: fld_r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self> TypeFolder for RegionFolder<'self> {
|
||||
fn tcx(&self) -> ty::ctxt { self.tcx }
|
||||
|
||||
fn fold_ty(&mut self, ty: ty::t) -> ty::t {
|
||||
debug!("RegionFolder.fold_ty({})", ty.repr(self.tcx()));
|
||||
let t1 = super_fold_ty(self, ty);
|
||||
(self.fld_t)(t1)
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
|
||||
debug!("RegionFolder.fold_region({})", r.repr(self.tcx()));
|
||||
(self.fld_r)(r)
|
||||
}
|
||||
}
|
@ -23,13 +23,10 @@
|
||||
* In the check phase, when the @FnCtxt is used as the `AstConv`,
|
||||
* `get_item_ty()` just looks up the item type in `tcx.tcache`.
|
||||
*
|
||||
* The `RegionScope` trait controls how region references are
|
||||
* handled. It has two methods which are used to resolve anonymous
|
||||
* region references (e.g., `&T`) and named region references (e.g.,
|
||||
* `&a.T`). There are numerous region scopes that can be used, but most
|
||||
* commonly you want either `EmptyRscope`, which permits only the static
|
||||
* region, or `TypeRscope`, which permits the self region if the type in
|
||||
* question is parameterized by a region.
|
||||
* The `RegionScope` trait controls what happens when the user does
|
||||
* not specify a region in some location where a region is required
|
||||
* (e.g., if the user writes `&Foo` as a type rather than `&'a Foo`).
|
||||
* See the `rscope` module for more details.
|
||||
*
|
||||
* Unlike the `AstConv` trait, the region scope can change as we descend
|
||||
* the type. This is to accommodate the fact that (a) fn types are binding
|
||||
@ -57,20 +54,17 @@ use middle::const_eval;
|
||||
use middle::ty::{substs};
|
||||
use middle::ty::{ty_param_substs_and_ty};
|
||||
use middle::ty;
|
||||
use middle::typeck::rscope::in_binding_rscope;
|
||||
use middle::typeck::rscope::{RegionScope, RegionError};
|
||||
use middle::typeck::rscope::RegionParamNames;
|
||||
use middle::typeck::rscope;
|
||||
use middle::typeck::rscope::{RegionScope};
|
||||
use middle::typeck::lookup_def_tcx;
|
||||
|
||||
use std::result;
|
||||
use std::vec;
|
||||
use syntax::abi::AbiSet;
|
||||
use syntax::{ast, ast_util};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::opt_vec::OptVec;
|
||||
use syntax::opt_vec;
|
||||
use syntax::print::pprust::{lifetime_to_str, path_to_str};
|
||||
use syntax::parse::token::special_idents;
|
||||
use util::common::indenter;
|
||||
|
||||
pub trait AstConv {
|
||||
fn tcx(&self) -> ty::ctxt;
|
||||
@ -81,64 +75,90 @@ pub trait AstConv {
|
||||
fn ty_infer(&self, span: Span) -> ty::t;
|
||||
}
|
||||
|
||||
pub fn get_region_reporting_err(
|
||||
pub fn ast_region_to_region(
|
||||
tcx: ty::ctxt,
|
||||
span: Span,
|
||||
a_r: &Option<ast::Lifetime>,
|
||||
res: Result<ty::Region, RegionError>) -> ty::Region
|
||||
lifetime: &ast::Lifetime)
|
||||
-> ty::Region
|
||||
{
|
||||
match res {
|
||||
result::Ok(r) => r,
|
||||
result::Err(ref e) => {
|
||||
let descr = match a_r {
|
||||
&None => ~"anonymous lifetime",
|
||||
&Some(ref a) => format!("lifetime {}",
|
||||
lifetime_to_str(a, tcx.sess.intr()))
|
||||
};
|
||||
tcx.sess.span_err(
|
||||
span,
|
||||
format!("Illegal {}: {}",
|
||||
descr, e.msg));
|
||||
e.replacement
|
||||
let r = match tcx.named_region_map.find(&lifetime.id) {
|
||||
None => {
|
||||
// should have been recorded by the `resolve_lifetime` pass
|
||||
tcx.sess.span_bug(lifetime.span, "unresolved lifetime");
|
||||
}
|
||||
}
|
||||
|
||||
Some(&ast::DefStaticRegion) => {
|
||||
ty::ReStatic
|
||||
}
|
||||
|
||||
Some(&ast::DefLateBoundRegion(binder_id, _, id)) => {
|
||||
ty::ReLateBound(binder_id, ty::BrNamed(ast_util::local_def(id),
|
||||
lifetime.ident))
|
||||
}
|
||||
|
||||
Some(&ast::DefEarlyBoundRegion(index, id)) => {
|
||||
ty::ReEarlyBound(id, index, lifetime.ident)
|
||||
}
|
||||
|
||||
Some(&ast::DefFreeRegion(scope_id, id)) => {
|
||||
ty::ReFree(ty::FreeRegion {
|
||||
scope_id: scope_id,
|
||||
bound_region: ty::BrNamed(ast_util::local_def(id),
|
||||
lifetime.ident)
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
debug!("ast_region_to_region(lifetime={} id={}) yields {}",
|
||||
lifetime_to_str(lifetime, tcx.sess.intr()),
|
||||
lifetime.id,
|
||||
r.repr(tcx));
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
pub fn ast_region_to_region<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
fn opt_ast_region_to_region<AC:AstConv,RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
default_span: Span,
|
||||
opt_lifetime: &Option<ast::Lifetime>) -> ty::Region
|
||||
{
|
||||
let (span, res) = match opt_lifetime {
|
||||
&None => {
|
||||
(default_span, rscope.anon_region(default_span))
|
||||
let r = match *opt_lifetime {
|
||||
Some(ref lifetime) => {
|
||||
ast_region_to_region(this.tcx(), lifetime)
|
||||
}
|
||||
&Some(ref lifetime) if lifetime.ident == special_idents::statik => {
|
||||
(lifetime.span, Ok(ty::re_static))
|
||||
}
|
||||
&Some(ref lifetime) if lifetime.ident == special_idents::self_ => {
|
||||
(lifetime.span, rscope.self_region(lifetime.span))
|
||||
}
|
||||
&Some(ref lifetime) => {
|
||||
(lifetime.span, rscope.named_region(lifetime.span,
|
||||
lifetime.ident))
|
||||
|
||||
None => {
|
||||
match rscope.anon_regions(default_span, 1) {
|
||||
Err(()) => {
|
||||
debug!("optional region in illegal location");
|
||||
this.tcx().sess.span_err(
|
||||
default_span, "missing lifetime specifier");
|
||||
ty::ReStatic
|
||||
}
|
||||
|
||||
Ok(rs) => {
|
||||
rs[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
get_region_reporting_err(this.tcx(), span, opt_lifetime, res)
|
||||
debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {}",
|
||||
opt_lifetime.as_ref().map(
|
||||
|e| lifetime_to_str(e, this.tcx().sess.intr())),
|
||||
r.repr(this.tcx()));
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
fn ast_path_substs<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
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`.
|
||||
@ -149,30 +169,28 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
// 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_err() {
|
||||
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 {
|
||||
Ok(v) => opt_vec::from(v),
|
||||
Err(()) => opt_vec::from(vec::from_fn(expected_num_region_params,
|
||||
|_| ty::ReStatic)) // hokey
|
||||
}
|
||||
};
|
||||
|
||||
@ -200,7 +218,7 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
}
|
||||
|
||||
pub fn ast_path_to_substs_and_ty<AC:AstConv,
|
||||
RS:RegionScope + Clone + 'static>(
|
||||
RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
did: ast::DefId,
|
||||
@ -212,12 +230,12 @@ 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 }
|
||||
}
|
||||
|
||||
pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
trait_def_id: ast::DefId,
|
||||
@ -230,7 +248,6 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
ast_path_substs(
|
||||
this,
|
||||
rscope,
|
||||
trait_def.trait_ref.def_id,
|
||||
&trait_def.generics,
|
||||
self_ty,
|
||||
path);
|
||||
@ -240,7 +257,7 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
return trait_ref;
|
||||
}
|
||||
|
||||
pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
did: ast::DefId,
|
||||
@ -260,12 +277,11 @@ pub static NO_REGIONS: uint = 1;
|
||||
pub static NO_TPS: uint = 2;
|
||||
|
||||
// Parses the programmer's textual representation of a type into our
|
||||
// internal notion of a type. `getter` is a function that returns the type
|
||||
// corresponding to a definition ID:
|
||||
pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
// internal notion of a type.
|
||||
pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t {
|
||||
|
||||
fn ast_mt_to_mt<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
fn ast_mt_to_mt<AC:AstConv, RS:RegionScope>(
|
||||
this: &AC, rscope: &RS, mt: &ast::mt) -> ty::mt {
|
||||
|
||||
ty::mt {ty: ast_ty_to_ty(this, rscope, mt.ty), mutbl: mt.mutbl}
|
||||
@ -274,7 +290,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
// Handle @, ~, and & being able to mean estrs and evecs.
|
||||
// If a_seq_ty is a str or a vec, make it an estr/evec.
|
||||
// Also handle first-class trait types.
|
||||
fn mk_pointer<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
fn mk_pointer<AC:AstConv,RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
a_seq_ty: &ast::mt,
|
||||
@ -282,6 +298,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
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) => {
|
||||
@ -289,6 +306,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
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) => {
|
||||
@ -347,7 +365,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
}
|
||||
|
||||
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");
|
||||
@ -387,7 +405,8 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
ty::mk_ptr(tcx, ast_mt_to_mt(this, rscope, mt))
|
||||
}
|
||||
ast::ty_rptr(ref region, ref mt) => {
|
||||
let r = ast_region_to_region(this, rscope, ast_ty.span, region);
|
||||
let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
|
||||
debug!("ty_rptr r={}", r.repr(this.tcx()));
|
||||
mk_pointer(this, rscope, mt, ty::vstore_slice(r),
|
||||
|tmt| ty::mk_rptr(tcx, r, tmt))
|
||||
}
|
||||
@ -399,8 +418,8 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
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 {
|
||||
@ -411,12 +430,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil {
|
||||
// Use corresponding trait store to figure out default bounds
|
||||
// if none were specified.
|
||||
ast::BorrowedSigil => ty::RegionTraitStore(ty::re_empty), // dummy region
|
||||
ast::BorrowedSigil => ty::RegionTraitStore(ty::ReEmpty), // dummy region
|
||||
ast::OwnedSigil => ty::UniqTraitStore,
|
||||
ast::ManagedSigil => ty::BoxTraitStore,
|
||||
});
|
||||
let fn_decl = ty_of_closure(this,
|
||||
rscope,
|
||||
ast_ty.id,
|
||||
f.sigil,
|
||||
f.purity,
|
||||
f.onceness,
|
||||
@ -424,7 +444,6 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
&f.region,
|
||||
&f.decl,
|
||||
None,
|
||||
&f.lifetimes,
|
||||
ast_ty.span);
|
||||
ty::mk_closure(tcx, fn_decl)
|
||||
}
|
||||
@ -551,7 +570,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
||||
}
|
||||
|
||||
pub fn ty_of_arg<AC:AstConv,
|
||||
RS:RegionScope + Clone + 'static>(
|
||||
RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
a: &ast::arg,
|
||||
@ -564,46 +583,15 @@ pub fn ty_of_arg<AC:AstConv,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bound_lifetimes<AC:AstConv>(
|
||||
this: &AC,
|
||||
ast_lifetimes: &OptVec<ast::Lifetime>) -> OptVec<ast::Ident>
|
||||
{
|
||||
/*!
|
||||
*
|
||||
* Converts a list of lifetimes into a list of bound identifier
|
||||
* names. Does not permit special names like 'static or 'this to
|
||||
* be bound. Note that this function is for use in closures,
|
||||
* methods, and fn definitions. It is legal to bind 'this in a
|
||||
* type. Eventually this distinction should go away and the same
|
||||
* rules should apply everywhere ('this would not be a special name
|
||||
* at that point).
|
||||
*/
|
||||
|
||||
let special_idents = [special_idents::statik, special_idents::self_];
|
||||
let mut bound_lifetime_names = opt_vec::Empty;
|
||||
ast_lifetimes.map_to_vec(|ast_lifetime| {
|
||||
if special_idents.iter().any(|&i| i == ast_lifetime.ident) {
|
||||
this.tcx().sess.span_err(
|
||||
ast_lifetime.span,
|
||||
format!("illegal lifetime parameter name: `{}`",
|
||||
lifetime_to_str(ast_lifetime, this.tcx().sess.intr())));
|
||||
} else {
|
||||
bound_lifetime_names.push(ast_lifetime.ident);
|
||||
}
|
||||
});
|
||||
bound_lifetime_names
|
||||
}
|
||||
|
||||
struct SelfInfo {
|
||||
untransformed_self_ty: ty::t,
|
||||
explicit_self: ast::explicit_self
|
||||
}
|
||||
|
||||
pub fn ty_of_method<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
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)
|
||||
@ -613,40 +601,35 @@ pub fn ty_of_method<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
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
|
||||
let bound_lifetime_names = bound_lifetimes(this, lifetimes);
|
||||
let rb =
|
||||
in_binding_rscope(rscope,
|
||||
RegionParamNames(bound_lifetime_names.clone()));
|
||||
let rb = rscope::BindingRscope::new(id);
|
||||
|
||||
let opt_transformed_self_ty = do opt_self_info.map |self_info| {
|
||||
transform_self_ty(this, &rb, self_info)
|
||||
@ -663,15 +646,13 @@ 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 + Clone + 'static>(
|
||||
fn transform_self_ty<AC:AstConv,RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
self_info: &SelfInfo) -> Option<ty::t>
|
||||
@ -683,9 +664,9 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
}
|
||||
ast::sty_region(ref lifetime, mutability) => {
|
||||
let region =
|
||||
ast_region_to_region(this, rscope,
|
||||
self_info.explicit_self.span,
|
||||
lifetime);
|
||||
opt_ast_region_to_region(this, rscope,
|
||||
self_info.explicit_self.span,
|
||||
lifetime);
|
||||
Some(ty::mk_rptr(this.tcx(), region,
|
||||
ty::mt {ty: self_info.untransformed_self_ty,
|
||||
mutbl: mutability}))
|
||||
@ -704,9 +685,10 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ty_of_closure<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,
|
||||
@ -714,34 +696,27 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
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
|
||||
let bound_region = match opt_lifetime {
|
||||
&Some(_) => {
|
||||
ast_region_to_region(this, rscope, span, opt_lifetime)
|
||||
&Some(ref lifetime) => {
|
||||
ast_region_to_region(this.tcx(), lifetime)
|
||||
}
|
||||
&None => {
|
||||
match sigil {
|
||||
ast::OwnedSigil | ast::ManagedSigil => {
|
||||
// @fn(), ~fn() default to static as the bound
|
||||
// on their upvars:
|
||||
ty::re_static
|
||||
ty::ReStatic
|
||||
}
|
||||
ast::BorrowedSigil => {
|
||||
// &fn() defaults as normal for an omitted lifetime:
|
||||
ast_region_to_region(this, rscope, span, opt_lifetime)
|
||||
opt_ast_region_to_region(this, rscope, span, opt_lifetime)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -749,10 +724,7 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
|
||||
// new region names that appear inside of the fn decl are bound to
|
||||
// that function type
|
||||
let bound_lifetime_names = bound_lifetimes(this, lifetimes);
|
||||
let rb =
|
||||
in_binding_rscope(rscope,
|
||||
RegionParamNames(bound_lifetime_names.clone()));
|
||||
let rb = rscope::BindingRscope::new(id);
|
||||
|
||||
let input_tys = do decl.inputs.iter().enumerate().map |(i, a)| {
|
||||
let expected_arg_ty = do expected_sig.as_ref().and_then |e| {
|
||||
@ -776,12 +748,10 @@ pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
||||
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}
|
||||
}
|
||||
}
|
||||
|
||||
@ -832,7 +802,7 @@ fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBou
|
||||
// @Trait is sugar for @Trait:'static.
|
||||
// &'static Trait is sugar for &'static Trait:'static.
|
||||
(&None, ty::BoxTraitStore) |
|
||||
(&None, ty::RegionTraitStore(ty::re_static)) => {
|
||||
(&None, ty::RegionTraitStore(ty::ReStatic)) => {
|
||||
let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundStatic); set
|
||||
}
|
||||
// &'r Trait is sugar for &'r Trait:<no-bounds>.
|
||||
|
@ -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();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,7 +29,7 @@ this point a bit better.
|
||||
|
||||
|
||||
use middle::freevars::get_freevars;
|
||||
use middle::ty::{re_scope};
|
||||
use middle::ty::{ReScope};
|
||||
use middle::ty;
|
||||
use middle::typeck::check::FnCtxt;
|
||||
use middle::typeck::check::regionmanip::relate_nested_regions;
|
||||
@ -64,7 +64,7 @@ fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::Def) -> ty::Region {
|
||||
DefUpvar(_, subdef, closure_id, body_id) => {
|
||||
match ty::ty_closure_sigil(fcx.node_ty(closure_id)) {
|
||||
BorrowedSigil => encl_region_of_def(fcx, *subdef),
|
||||
ManagedSigil | OwnedSigil => re_scope(body_id)
|
||||
ManagedSigil | OwnedSigil => ReScope(body_id)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@ -317,7 +317,7 @@ fn visit_expr(rcx: &mut Rcx, expr: @ast::Expr) {
|
||||
//
|
||||
// FIXME(#6268) remove to support nested method calls
|
||||
constrain_regions_in_type_of_node(
|
||||
rcx, expr.id, ty::re_scope(expr.id),
|
||||
rcx, expr.id, ty::ReScope(expr.id),
|
||||
infer::AutoBorrow(expr.span));
|
||||
}
|
||||
}
|
||||
@ -416,7 +416,7 @@ fn visit_expr(rcx: &mut Rcx, expr: @ast::Expr) {
|
||||
//
|
||||
// FIXME(#6268) nested method calls requires that this rule change
|
||||
let ty0 = rcx.resolve_node_type(expr.id);
|
||||
constrain_regions_in_type(rcx, ty::re_scope(expr.id),
|
||||
constrain_regions_in_type(rcx, ty::ReScope(expr.id),
|
||||
infer::AddrOf(expr.span), ty0);
|
||||
visit::walk_expr(rcx, expr, ());
|
||||
}
|
||||
@ -474,7 +474,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||
// (since otherwise that would require
|
||||
// infinite stack).
|
||||
constrain_free_variables(rcx, region, expr);
|
||||
let repeating_scope = ty::re_scope(rcx.repeating_scope);
|
||||
let repeating_scope = ty::ReScope(rcx.repeating_scope);
|
||||
rcx.fcx.mk_subr(true, infer::InfStackClosure(expr.span),
|
||||
region, repeating_scope);
|
||||
}
|
||||
@ -500,7 +500,7 @@ fn constrain_callee(rcx: &mut Rcx,
|
||||
call_expr: @ast::Expr,
|
||||
callee_expr: @ast::Expr)
|
||||
{
|
||||
let call_region = ty::re_scope(call_expr.id);
|
||||
let call_region = ty::ReScope(call_expr.id);
|
||||
|
||||
let callee_ty = rcx.resolve_node_type(callee_id);
|
||||
match ty::get(callee_ty).sty {
|
||||
@ -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
|
||||
@ -549,9 +555,11 @@ fn constrain_call(rcx: &mut Rcx,
|
||||
//
|
||||
// FIXME(#6268) to support nested method calls, should be callee_id
|
||||
let callee_scope = call_expr.id;
|
||||
let callee_region = ty::re_scope(callee_scope);
|
||||
let callee_region = ty::ReScope(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 {
|
||||
@ -595,7 +604,7 @@ fn constrain_derefs(rcx: &mut Rcx,
|
||||
* the deref expr.
|
||||
*/
|
||||
let tcx = rcx.fcx.tcx();
|
||||
let r_deref_expr = ty::re_scope(deref_expr.id);
|
||||
let r_deref_expr = ty::ReScope(deref_expr.id);
|
||||
for i in range(0u, derefs) {
|
||||
debug!("constrain_derefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}",
|
||||
rcx.fcx.infcx().ty_to_str(derefd_ty),
|
||||
@ -641,7 +650,7 @@ fn constrain_index(rcx: &mut Rcx,
|
||||
debug!("constrain_index(index_expr=?, indexed_ty={}",
|
||||
rcx.fcx.infcx().ty_to_str(indexed_ty));
|
||||
|
||||
let r_index_expr = ty::re_scope(index_expr.id);
|
||||
let r_index_expr = ty::ReScope(index_expr.id);
|
||||
match ty::get(indexed_ty).sty {
|
||||
ty::ty_estr(ty::vstore_slice(r_ptr)) |
|
||||
ty::ty_evec(_, ty::vstore_slice(r_ptr)) => {
|
||||
@ -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.
|
||||
@ -903,7 +912,7 @@ pub mod guarantor {
|
||||
let expr_cat = categorize(rcx, expr);
|
||||
debug!("guarantor::for_by_ref(expr={:?}, callee_scope={:?}) category={:?}",
|
||||
expr.id, callee_scope, expr_cat);
|
||||
let minimum_lifetime = ty::re_scope(callee_scope);
|
||||
let minimum_lifetime = ty::ReScope(callee_scope);
|
||||
for guarantor in expr_cat.guarantor.iter() {
|
||||
mk_subregion_due_to_derefence(rcx, expr.span,
|
||||
minimum_lifetime, *guarantor);
|
||||
|
@ -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)
|
||||
mapf: &fn(ty::BoundRegion) -> ty::Region)
|
||||
-> (HashMap<ty::BoundRegion,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::ReLateBound(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,60 @@ 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(#10151) -- Define more precisely when a region is
|
||||
// considered "nested". Consider taking variance into account as
|
||||
// well.
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,7 +169,7 @@ pub fn relate_free_regions(
|
||||
debug!("relate_free_regions(t={})", ppaux::ty_to_str(tcx, t));
|
||||
relate_nested_regions(tcx, None, t, |a, b| {
|
||||
match (&a, &b) {
|
||||
(&ty::re_free(free_a), &ty::re_free(free_b)) => {
|
||||
(&ty::ReFree(free_a), &ty::ReFree(free_b)) => {
|
||||
tcx.region_maps.relate_free_regions(free_a, free_b);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -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 = ~[];
|
||||
@ -480,7 +480,7 @@ fn fixup_substs(vcx: &VtableContext,
|
||||
// use a dummy type just to package up the substs that need fixing up
|
||||
let t = ty::mk_trait(tcx,
|
||||
id, substs,
|
||||
ty::RegionTraitStore(ty::re_static),
|
||||
ty::RegionTraitStore(ty::ReStatic),
|
||||
ast::MutImmutable,
|
||||
ty::EmptyBuiltinBounds());
|
||||
do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
|
||||
@ -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
|
||||
};
|
||||
@ -539,33 +536,6 @@ impl CoherenceChecker {
|
||||
return trait_id;
|
||||
}
|
||||
|
||||
// This check doesn't really have anything to do with coherence. It's
|
||||
// here for historical reasons
|
||||
pub fn check_trait_methods_are_implemented(
|
||||
&self,
|
||||
all_methods: &mut ~[@Method],
|
||||
trait_did: DefId,
|
||||
trait_ref_span: Span) {
|
||||
|
||||
let tcx = self.crate_context.tcx;
|
||||
|
||||
let mut provided_names = HashSet::new();
|
||||
// Implemented methods
|
||||
for elt in all_methods.iter() {
|
||||
provided_names.insert(elt.ident.name);
|
||||
}
|
||||
|
||||
let r = ty::trait_methods(tcx, trait_did);
|
||||
for method in r.iter() {
|
||||
debug!("checking for {}", method.ident.repr(tcx));
|
||||
if provided_names.contains(&method.ident.name) { continue; }
|
||||
|
||||
tcx.sess.span_err(trait_ref_span,
|
||||
format!("missing method `{}`",
|
||||
tcx.sess.str_of(method.ident)));
|
||||
}
|
||||
}
|
||||
|
||||
/// For coherence, when we have `impl Type`, we need to guarantee that
|
||||
/// `Type` is "local" to the crate. For our purposes, this means that it
|
||||
/// must precisely name some nominal type defined in this crate.
|
||||
@ -620,17 +590,10 @@ impl CoherenceChecker {
|
||||
let ty_trait_ref = ty::node_id_to_trait_ref(
|
||||
self.crate_context.tcx,
|
||||
trait_ref.ref_id);
|
||||
let trait_did = ty_trait_ref.def_id;
|
||||
|
||||
self.instantiate_default_methods(local_def(item.id),
|
||||
ty_trait_ref,
|
||||
&mut methods);
|
||||
|
||||
// Check that we have implementations of every trait method
|
||||
self.check_trait_methods_are_implemented(
|
||||
&mut methods,
|
||||
trait_did,
|
||||
trait_ref.path.span);
|
||||
}
|
||||
|
||||
return @Impl {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -123,76 +123,70 @@ pub trait Combine {
|
||||
}
|
||||
}
|
||||
|
||||
fn substs(&self, generics: &ty::Generics, as_: &ty::substs,
|
||||
fn substs(&self,
|
||||
item_def_id: ast::DefId,
|
||||
as_: &ty::substs,
|
||||
bs: &ty::substs) -> cres<ty::substs> {
|
||||
|
||||
fn relate_region_params<C:Combine>(
|
||||
this: &C,
|
||||
generics: &ty::Generics,
|
||||
fn relate_region_params<C:Combine>(this: &C,
|
||||
item_def_id: ast::DefId,
|
||||
a: &ty::RegionSubsts,
|
||||
b: &ty::RegionSubsts)
|
||||
-> cres<ty::RegionSubsts>
|
||||
{
|
||||
-> cres<ty::RegionSubsts> {
|
||||
let tcx = this.infcx().tcx;
|
||||
match (a, b) {
|
||||
(&ty::ErasedRegions, _) |
|
||||
(_, &ty::ErasedRegions) => {
|
||||
(&ty::ErasedRegions, _) | (_, &ty::ErasedRegions) => {
|
||||
Ok(ty::ErasedRegions)
|
||||
}
|
||||
|
||||
(&ty::NonerasedRegions(ref a_rs),
|
||||
&ty::NonerasedRegions(ref b_rs)) => {
|
||||
match generics.region_param {
|
||||
None => {
|
||||
assert!(a_rs.is_empty());
|
||||
assert!(b_rs.is_empty());
|
||||
Ok(ty::NonerasedRegions(opt_vec::Empty))
|
||||
}
|
||||
let variances = ty::item_variances(tcx, item_def_id);
|
||||
let region_params = &variances.region_params;
|
||||
let num_region_params = region_params.len();
|
||||
|
||||
Some(variance) => {
|
||||
assert_eq!(a_rs.len(), 1);
|
||||
assert_eq!(b_rs.len(), 1);
|
||||
let a_r = *a_rs.get(0);
|
||||
let b_r = *b_rs.get(0);
|
||||
debug!("relate_region_params(\
|
||||
item_def_id={}, \
|
||||
a_rs={}, \
|
||||
b_rs={},
|
||||
region_params={})",
|
||||
item_def_id.repr(tcx),
|
||||
a_rs.repr(tcx),
|
||||
b_rs.repr(tcx),
|
||||
region_params.repr(tcx));
|
||||
|
||||
match variance {
|
||||
ty::rv_invariant => {
|
||||
do eq_regions(this, a_r, b_r).then {
|
||||
Ok(ty::NonerasedRegions(opt_vec::with(a_r)))
|
||||
}
|
||||
}
|
||||
|
||||
ty::rv_covariant => {
|
||||
do this.regions(a_r, b_r).and_then |r| {
|
||||
Ok(ty::NonerasedRegions(opt_vec::with(r)))
|
||||
}
|
||||
}
|
||||
|
||||
ty::rv_contravariant => {
|
||||
do this.contraregions(a_r, b_r).and_then |r| {
|
||||
Ok(ty::NonerasedRegions(opt_vec::with(r)))
|
||||
}
|
||||
}
|
||||
assert_eq!(num_region_params, a_rs.len());
|
||||
assert_eq!(num_region_params, b_rs.len());
|
||||
let mut rs = opt_vec::Empty;
|
||||
for i in range(0, num_region_params) {
|
||||
let a_r = *a_rs.get(i);
|
||||
let b_r = *b_rs.get(i);
|
||||
let variance = *region_params.get(i);
|
||||
let r = match variance {
|
||||
ty::Invariant => {
|
||||
eq_regions(this, a_r, b_r)
|
||||
.and_then(|()| Ok(a_r))
|
||||
}
|
||||
}
|
||||
ty::Covariant => this.regions(a_r, b_r),
|
||||
ty::Contravariant => this.contraregions(a_r, b_r),
|
||||
ty::Bivariant => Ok(a_r),
|
||||
};
|
||||
rs.push(if_ok!(r));
|
||||
}
|
||||
Ok(ty::NonerasedRegions(rs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do self.tps(as_.tps, bs.tps).and_then |tps| {
|
||||
do self.self_tys(as_.self_ty, bs.self_ty).and_then |self_ty| {
|
||||
do relate_region_params(self,
|
||||
generics,
|
||||
&as_.regions,
|
||||
&bs.regions).and_then |regions| {
|
||||
Ok(substs {
|
||||
regions: regions,
|
||||
self_ty: self_ty,
|
||||
tps: tps.clone()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
let tps = if_ok!(self.tps(as_.tps, bs.tps));
|
||||
let self_ty = if_ok!(self.self_tys(as_.self_ty, bs.self_ty));
|
||||
let regions = if_ok!(relate_region_params(self,
|
||||
item_def_id,
|
||||
&as_.regions,
|
||||
&bs.regions));
|
||||
Ok(substs { regions: regions,
|
||||
self_ty: self_ty,
|
||||
tps: tps.clone() })
|
||||
}
|
||||
|
||||
fn bare_fn_tys(&self, a: &ty::BareFnTy,
|
||||
@ -267,9 +261,11 @@ pub trait Combine {
|
||||
-> cres<ty::Region>;
|
||||
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region>;
|
||||
|
||||
fn vstores(&self, vk: ty::terr_vstore_kind,
|
||||
a: ty::vstore, b: ty::vstore) -> cres<ty::vstore> {
|
||||
|
||||
fn vstores(&self,
|
||||
vk: ty::terr_vstore_kind,
|
||||
a: ty::vstore,
|
||||
b: ty::vstore)
|
||||
-> cres<ty::vstore> {
|
||||
debug!("{}.vstores(a={:?}, b={:?})", self.tag(), a, b);
|
||||
|
||||
match (a, b) {
|
||||
@ -293,8 +289,7 @@ pub trait Combine {
|
||||
vk: ty::terr_vstore_kind,
|
||||
a: ty::TraitStore,
|
||||
b: ty::TraitStore)
|
||||
-> cres<ty::TraitStore> {
|
||||
|
||||
-> cres<ty::TraitStore> {
|
||||
debug!("{}.trait_stores(a={:?}, b={:?})", self.tag(), a, b);
|
||||
|
||||
match (a, b) {
|
||||
@ -317,7 +312,8 @@ pub trait Combine {
|
||||
|
||||
fn trait_refs(&self,
|
||||
a: &ty::TraitRef,
|
||||
b: &ty::TraitRef) -> cres<ty::TraitRef> {
|
||||
b: &ty::TraitRef)
|
||||
-> cres<ty::TraitRef> {
|
||||
// Different traits cannot be related
|
||||
|
||||
// - NOTE in the future, expand out subtraits!
|
||||
@ -326,15 +322,9 @@ pub trait Combine {
|
||||
Err(ty::terr_traits(
|
||||
expected_found(self, a.def_id, b.def_id)))
|
||||
} else {
|
||||
let tcx = self.infcx().tcx;
|
||||
let trait_def = ty::lookup_trait_def(tcx, a.def_id);
|
||||
let substs = if_ok!(self.substs(&trait_def.generics,
|
||||
&a.substs,
|
||||
&b.substs));
|
||||
Ok(ty::TraitRef {
|
||||
def_id: a.def_id,
|
||||
substs: substs
|
||||
})
|
||||
let substs = if_ok!(self.substs(a.def_id, &a.substs, &b.substs));
|
||||
Ok(ty::TraitRef { def_id: a.def_id,
|
||||
substs: substs })
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -366,8 +356,8 @@ pub fn eq_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> ures {
|
||||
pub fn eq_regions<C:Combine>(this: &C, a: ty::Region, b: ty::Region)
|
||||
-> ures {
|
||||
debug!("eq_regions({}, {})",
|
||||
a.inf_str(this.infcx()),
|
||||
b.inf_str(this.infcx()));
|
||||
a.repr(this.infcx().tcx),
|
||||
b.repr(this.infcx().tcx));
|
||||
let sub = this.sub();
|
||||
do indent {
|
||||
this.infcx().try(|| {
|
||||
@ -429,23 +419,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 +481,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(_), _) |
|
||||
@ -513,36 +501,30 @@ pub fn super_tys<C:Combine>(
|
||||
(&ty::ty_enum(a_id, ref a_substs),
|
||||
&ty::ty_enum(b_id, ref b_substs))
|
||||
if a_id == b_id => {
|
||||
let type_def = ty::lookup_item_type(tcx, a_id);
|
||||
do this.substs(&type_def.generics, a_substs, b_substs).and_then |substs| {
|
||||
Ok(ty::mk_enum(tcx, a_id, substs))
|
||||
}
|
||||
let substs = if_ok!(this.substs(a_id,
|
||||
a_substs,
|
||||
b_substs));
|
||||
Ok(ty::mk_enum(tcx, a_id, substs))
|
||||
}
|
||||
|
||||
(&ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl, a_bounds),
|
||||
&ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl, b_bounds))
|
||||
if a_id == b_id && a_mutbl == b_mutbl => {
|
||||
let trait_def = ty::lookup_trait_def(tcx, a_id);
|
||||
do this.substs(&trait_def.generics, a_substs, b_substs).and_then |substs| {
|
||||
do this.trait_stores(ty::terr_trait, a_store, b_store).and_then |s| {
|
||||
do this.bounds(a_bounds, b_bounds).and_then |bounds| {
|
||||
Ok(ty::mk_trait(tcx,
|
||||
a_id,
|
||||
substs.clone(),
|
||||
s,
|
||||
a_mutbl,
|
||||
bounds))
|
||||
}
|
||||
}
|
||||
}
|
||||
let substs = if_ok!(this.substs(a_id, a_substs, b_substs));
|
||||
let s = if_ok!(this.trait_stores(ty::terr_trait, a_store, b_store));
|
||||
let bounds = if_ok!(this.bounds(a_bounds, b_bounds));
|
||||
Ok(ty::mk_trait(tcx,
|
||||
a_id,
|
||||
substs.clone(),
|
||||
s,
|
||||
a_mutbl,
|
||||
bounds))
|
||||
}
|
||||
|
||||
(&ty::ty_struct(a_id, ref a_substs), &ty::ty_struct(b_id, ref b_substs))
|
||||
if a_id == b_id => {
|
||||
let type_def = ty::lookup_item_type(tcx, a_id);
|
||||
do this.substs(&type_def.generics, a_substs, b_substs).and_then |substs| {
|
||||
Ok(ty::mk_struct(tcx, a_id, substs))
|
||||
}
|
||||
let substs = if_ok!(this.substs(a_id, a_substs, b_substs));
|
||||
Ok(ty::mk_struct(tcx, a_id, substs))
|
||||
}
|
||||
|
||||
(&ty::ty_box(ref a_mt), &ty::ty_box(ref b_mt)) => {
|
||||
@ -578,9 +560,8 @@ pub fn super_tys<C:Combine>(
|
||||
}
|
||||
|
||||
(&ty::ty_estr(vs_a), &ty::ty_estr(vs_b)) => {
|
||||
do this.vstores(ty::terr_str, vs_a, vs_b).and_then |vs| {
|
||||
Ok(ty::mk_estr(tcx,vs))
|
||||
}
|
||||
let vs = if_ok!(this.vstores(ty::terr_str, vs_a, vs_b));
|
||||
Ok(ty::mk_estr(tcx,vs))
|
||||
}
|
||||
|
||||
(&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => {
|
||||
|
@ -73,6 +73,7 @@ use middle::typeck::infer::region_inference::SubSupConflict;
|
||||
use middle::typeck::infer::region_inference::SupSupConflict;
|
||||
use syntax::opt_vec::OptVec;
|
||||
use util::ppaux::UserString;
|
||||
use util::ppaux::bound_region_to_str;
|
||||
use util::ppaux::note_and_explain_region;
|
||||
|
||||
pub trait ErrorReporting {
|
||||
@ -110,6 +111,13 @@ pub trait ErrorReporting {
|
||||
region2: Region);
|
||||
}
|
||||
|
||||
trait ErrorReportingHelpers {
|
||||
fn report_inference_failure(@mut self,
|
||||
var_origin: RegionVariableOrigin);
|
||||
|
||||
fn note_region_origin(@mut self,
|
||||
origin: SubregionOrigin);
|
||||
}
|
||||
|
||||
impl ErrorReporting for InferCtxt {
|
||||
fn report_region_errors(@mut self,
|
||||
@ -398,10 +406,7 @@ impl ErrorReporting for InferCtxt {
|
||||
sub_region: Region,
|
||||
sup_origin: SubregionOrigin,
|
||||
sup_region: Region) {
|
||||
self.tcx.sess.span_err(
|
||||
var_origin.span(),
|
||||
format!("cannot infer an appropriate lifetime \
|
||||
due to conflicting requirements"));
|
||||
self.report_inference_failure(var_origin);
|
||||
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
@ -409,9 +414,7 @@ impl ErrorReporting for InferCtxt {
|
||||
sup_region,
|
||||
"...");
|
||||
|
||||
self.tcx.sess.span_note(
|
||||
sup_origin.span(),
|
||||
format!("...due to the following expression"));
|
||||
self.note_region_origin(sup_origin);
|
||||
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
@ -419,9 +422,7 @@ impl ErrorReporting for InferCtxt {
|
||||
sub_region,
|
||||
"...");
|
||||
|
||||
self.tcx.sess.span_note(
|
||||
sub_origin.span(),
|
||||
format!("...due to the following expression"));
|
||||
self.note_region_origin(sub_origin);
|
||||
}
|
||||
|
||||
fn report_sup_sup_conflict(@mut self,
|
||||
@ -430,10 +431,7 @@ impl ErrorReporting for InferCtxt {
|
||||
region1: Region,
|
||||
origin2: SubregionOrigin,
|
||||
region2: Region) {
|
||||
self.tcx.sess.span_err(
|
||||
var_origin.span(),
|
||||
format!("cannot infer an appropriate lifetime \
|
||||
due to conflicting requirements"));
|
||||
self.report_inference_failure(var_origin);
|
||||
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
@ -441,9 +439,7 @@ impl ErrorReporting for InferCtxt {
|
||||
region1,
|
||||
"...");
|
||||
|
||||
self.tcx.sess.span_note(
|
||||
origin1.span(),
|
||||
format!("...due to the following expression"));
|
||||
self.note_region_origin(origin1);
|
||||
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
@ -451,9 +447,167 @@ impl ErrorReporting for InferCtxt {
|
||||
region2,
|
||||
"...");
|
||||
|
||||
self.tcx.sess.span_note(
|
||||
origin2.span(),
|
||||
format!("...due to the following expression"));
|
||||
self.note_region_origin(origin2);
|
||||
}
|
||||
}
|
||||
|
||||
impl ErrorReportingHelpers for InferCtxt {
|
||||
fn report_inference_failure(@mut self,
|
||||
var_origin: RegionVariableOrigin) {
|
||||
let var_description = match var_origin {
|
||||
infer::MiscVariable(_) => ~"",
|
||||
infer::PatternRegion(_) => ~" for pattern",
|
||||
infer::AddrOfRegion(_) => ~" for borrow expression",
|
||||
infer::AddrOfSlice(_) => ~" for slice expression",
|
||||
infer::Autoref(_) => ~" for autoref",
|
||||
infer::Coercion(_) => ~" for automatic coercion",
|
||||
infer::BoundRegionInFnCall(_, br) => {
|
||||
format!(" for {}in function call",
|
||||
bound_region_to_str(self.tcx, "region ", true, br))
|
||||
}
|
||||
infer::BoundRegionInFnType(_, br) => {
|
||||
format!(" for {}in function type",
|
||||
bound_region_to_str(self.tcx, "region ", true, br))
|
||||
}
|
||||
infer::BoundRegionInTypeOrImpl(_) => {
|
||||
format!(" for region in type/impl")
|
||||
}
|
||||
infer::BoundRegionInCoherence(*) => {
|
||||
format!(" for coherence check")
|
||||
}
|
||||
};
|
||||
|
||||
self.tcx.sess.span_err(
|
||||
var_origin.span(),
|
||||
format!("cannot infer an appropriate lifetime{} \
|
||||
due to conflicting requirements",
|
||||
var_description));
|
||||
}
|
||||
|
||||
fn note_region_origin(@mut self,
|
||||
origin: SubregionOrigin) {
|
||||
match origin {
|
||||
infer::Subtype(ref trace) => {
|
||||
let desc = match trace.origin {
|
||||
infer::Misc(_) => {
|
||||
format!("types are compatible")
|
||||
}
|
||||
infer::MethodCompatCheck(_) => {
|
||||
format!("method type is compatible with trait")
|
||||
}
|
||||
infer::ExprAssignable(_) => {
|
||||
format!("expression is assignable")
|
||||
}
|
||||
infer::RelateTraitRefs(_) => {
|
||||
format!("traits are compatible")
|
||||
}
|
||||
infer::RelateSelfType(_) => {
|
||||
format!("type matches impl")
|
||||
}
|
||||
infer::MatchExpression(_) => {
|
||||
format!("match arms have compatible types")
|
||||
}
|
||||
infer::IfExpression(_) => {
|
||||
format!("if and else have compatible types")
|
||||
}
|
||||
};
|
||||
|
||||
match self.values_str(&trace.values) {
|
||||
Some(values_str) => {
|
||||
self.tcx.sess.span_note(
|
||||
trace.origin.span(),
|
||||
format!("...so that {} ({})",
|
||||
desc, values_str));
|
||||
}
|
||||
None => {
|
||||
// Really should avoid printing this error at
|
||||
// all, since it is derived, but that would
|
||||
// require more refactoring than I feel like
|
||||
// doing right now. - nmatsakis
|
||||
self.tcx.sess.span_note(
|
||||
trace.origin.span(),
|
||||
format!("...so that {}", desc));
|
||||
}
|
||||
}
|
||||
}
|
||||
infer::Reborrow(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that borrowed pointer does not outlive \
|
||||
borrowed content");
|
||||
}
|
||||
infer::InfStackClosure(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that closure does not outlive its stack frame");
|
||||
}
|
||||
infer::InvokeClosure(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that closure is not invoked outside its lifetime");
|
||||
}
|
||||
infer::DerefPointer(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that pointer is not dereferenced \
|
||||
outside its lifetime");
|
||||
}
|
||||
infer::FreeVariable(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that captured variable does not outlive the \
|
||||
enclosing closure");
|
||||
}
|
||||
infer::IndexSlice(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that slice is not indexed outside the lifetime");
|
||||
}
|
||||
infer::RelateObjectBound(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that source pointer does not outlive \
|
||||
lifetime bound of the object type");
|
||||
}
|
||||
infer::CallRcvr(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that method receiver is valid for the method call");
|
||||
}
|
||||
infer::CallArg(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that argument is valid for the call");
|
||||
}
|
||||
infer::CallReturn(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that return value is valid for the call");
|
||||
}
|
||||
infer::AddrOf(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that borrowed pointer is valid \
|
||||
at the time of borrow");
|
||||
}
|
||||
infer::AutoBorrow(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that automatically borrowed pointer is valid \
|
||||
at the time of borrow");
|
||||
}
|
||||
infer::BindingTypeIsNotValidAtDecl(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that variable is valid at time of its declaration");
|
||||
}
|
||||
infer::ReferenceOutlivesReferent(_, span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that the pointer does not outlive the \
|
||||
data it points at");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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::BoundRegion, 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::BoundRegion, 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::ReLateBound(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,25 +521,22 @@ 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::BoundRegion, ty::Region>)
|
||||
-> ~[RegionVid] {
|
||||
map.iter().map(|(_, r)| match *r {
|
||||
ty::ReInfer(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 {
|
||||
match r {
|
||||
ty::re_infer(ty::ReVar(ref v)) => new_vars.iter().any(|x| x == v),
|
||||
ty::ReInfer(ty::ReVar(ref v)) => new_vars.iter().any(|x| x == v),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
@ -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::BoundRegion, 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::ReLateBound(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;
|
||||
@ -216,17 +216,15 @@ pub enum RegionVariableOrigin {
|
||||
|
||||
// Region variables created for bound regions
|
||||
// in a function or method that is called
|
||||
BoundRegionInFnCall(Span, ty::bound_region),
|
||||
BoundRegionInFnCall(Span, ty::BoundRegion),
|
||||
|
||||
// Region variables created for bound regions
|
||||
// when doing subtyping/lub/glb computations
|
||||
BoundRegionInFnType(Span, ty::bound_region),
|
||||
BoundRegionInFnType(Span, ty::BoundRegion),
|
||||
|
||||
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
|
||||
@ -639,7 +638,18 @@ impl InferCtxt {
|
||||
}
|
||||
|
||||
pub fn next_region_var(&mut self, origin: RegionVariableOrigin) -> ty::Region {
|
||||
ty::re_infer(ty::ReVar(self.region_vars.new_region_var(origin)))
|
||||
ty::ReInfer(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) {
|
||||
@ -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::BoundRegion,
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -924,14 +933,13 @@ impl Repr for RegionVariableOrigin {
|
||||
AddrOfSlice(a) => format!("AddrOfSlice({})", a.repr(tcx)),
|
||||
Autoref(a) => format!("Autoref({})", a.repr(tcx)),
|
||||
Coercion(a) => format!("Coercion({})", a.repr(tcx)),
|
||||
BoundRegionInFnCall(a, b) => format!("BoundRegionInFnCall({},{})",
|
||||
BoundRegionInFnCall(a, b) => format!("bound_regionInFnCall({},{})",
|
||||
a.repr(tcx), b.repr(tcx)),
|
||||
BoundRegionInFnType(a, b) => format!("BoundRegionInFnType({},{})",
|
||||
BoundRegionInFnType(a, b) => format!("bound_regionInFnType({},{})",
|
||||
a.repr(tcx), b.repr(tcx)),
|
||||
BoundRegionInTypeOrImpl(a) => format!("BoundRegionInTypeOrImpl({})",
|
||||
BoundRegionInTypeOrImpl(a) => format!("bound_regionInTypeOrImpl({})",
|
||||
a.repr(tcx)),
|
||||
BoundRegionInCoherence => format!("BoundRegionInCoherence"),
|
||||
BoundRegionError(a) => format!("BoundRegionError({})", a.repr(tcx)),
|
||||
BoundRegionInCoherence => format!("bound_regionInCoherence"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,9 @@
|
||||
|
||||
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_scope, ReVar, ReSkolemized, br_fresh};
|
||||
use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound,
|
||||
ReLateBound};
|
||||
use middle::ty::{ReScope, ReVar, ReSkolemized, BrFresh};
|
||||
use middle::typeck::infer::cres;
|
||||
use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin};
|
||||
use middle::typeck::infer;
|
||||
@ -186,30 +187,39 @@ impl RegionVarBindings {
|
||||
return vid;
|
||||
}
|
||||
|
||||
pub fn new_skolemized(&mut self, br: ty::bound_region) -> Region {
|
||||
pub fn new_skolemized(&mut self, br: ty::BoundRegion) -> Region {
|
||||
let sc = self.skolemization_count;
|
||||
self.skolemization_count += 1;
|
||||
re_infer(ReSkolemized(sc, br))
|
||||
ReInfer(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()");
|
||||
}
|
||||
|
||||
ReLateBound(binder_id, BrFresh(sc))
|
||||
}
|
||||
|
||||
pub fn add_constraint(&mut self,
|
||||
@ -236,25 +246,25 @@ impl RegionVarBindings {
|
||||
|
||||
debug!("RegionVarBindings: make_subregion({:?}, {:?})", sub, sup);
|
||||
match (sub, sup) {
|
||||
(re_infer(ReVar(sub_id)), re_infer(ReVar(sup_id))) => {
|
||||
(ReEarlyBound(*), _) |
|
||||
(ReLateBound(*), _) |
|
||||
(_, ReEarlyBound(*)) |
|
||||
(_, ReLateBound(*)) => {
|
||||
self.tcx.sess.span_bug(
|
||||
origin.span(),
|
||||
format!("Cannot relate bound region: {} <= {}",
|
||||
sub.repr(self.tcx),
|
||||
sup.repr(self.tcx)));
|
||||
}
|
||||
(ReInfer(ReVar(sub_id)), ReInfer(ReVar(sup_id))) => {
|
||||
self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin);
|
||||
}
|
||||
(r, re_infer(ReVar(sup_id))) => {
|
||||
(r, ReInfer(ReVar(sup_id))) => {
|
||||
self.add_constraint(ConstrainRegSubVar(r, sup_id), origin);
|
||||
}
|
||||
(re_infer(ReVar(sub_id)), r) => {
|
||||
(ReInfer(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);
|
||||
}
|
||||
@ -271,8 +281,8 @@ impl RegionVarBindings {
|
||||
|
||||
debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b);
|
||||
match (a, b) {
|
||||
(re_static, _) | (_, re_static) => {
|
||||
re_static // nothing lives longer than static
|
||||
(ReStatic, _) | (_, ReStatic) => {
|
||||
ReStatic // nothing lives longer than static
|
||||
}
|
||||
|
||||
_ => {
|
||||
@ -294,7 +304,7 @@ impl RegionVarBindings {
|
||||
|
||||
debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b);
|
||||
match (a, b) {
|
||||
(re_static, r) | (r, re_static) => {
|
||||
(ReStatic, r) | (r, ReStatic) => {
|
||||
// static lives longer than everything else
|
||||
r
|
||||
}
|
||||
@ -323,13 +333,13 @@ impl RegionVarBindings {
|
||||
Value(r) => r,
|
||||
|
||||
NoValue => {
|
||||
// No constraints, return ty::re_empty
|
||||
re_empty
|
||||
// No constraints, return ty::ReEmpty
|
||||
ReEmpty
|
||||
}
|
||||
|
||||
ErrorValue => {
|
||||
// An error that has previously been reported.
|
||||
re_static
|
||||
ReStatic
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -356,7 +366,7 @@ impl RegionVarBindings {
|
||||
let vars = TwoRegions { a: a, b: b };
|
||||
match self.combine_map(t).find(&vars) {
|
||||
Some(&c) => {
|
||||
return re_infer(ReVar(c));
|
||||
return ReInfer(ReVar(c));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
@ -365,10 +375,10 @@ impl RegionVarBindings {
|
||||
if self.in_snapshot() {
|
||||
self.undo_log.push(AddCombination(t, vars));
|
||||
}
|
||||
relate(self, a, re_infer(ReVar(c)));
|
||||
relate(self, b, re_infer(ReVar(c)));
|
||||
relate(self, a, ReInfer(ReVar(c)));
|
||||
relate(self, b, ReInfer(ReVar(c)));
|
||||
debug!("combine_vars() c={:?}", c);
|
||||
re_infer(ReVar(c))
|
||||
ReInfer(ReVar(c))
|
||||
}
|
||||
|
||||
pub fn vars_created_since_snapshot(&mut self, snapshot: uint)
|
||||
@ -411,14 +421,14 @@ impl RegionVarBindings {
|
||||
// nb: can't use uint::range() here as we move result_set
|
||||
let regs = match self.undo_log[undo_index] {
|
||||
AddConstraint(ConstrainVarSubVar(ref a, ref b)) => {
|
||||
Some((re_infer(ReVar(*a)),
|
||||
re_infer(ReVar(*b))))
|
||||
Some((ReInfer(ReVar(*a)),
|
||||
ReInfer(ReVar(*b))))
|
||||
}
|
||||
AddConstraint(ConstrainRegSubVar(ref a, ref b)) => {
|
||||
Some((*a, re_infer(ReVar(*b))))
|
||||
Some((*a, ReInfer(ReVar(*b))))
|
||||
}
|
||||
AddConstraint(ConstrainVarSubReg(ref a, ref b)) => {
|
||||
Some((re_infer(ReVar(*a)), *b))
|
||||
Some((ReInfer(ReVar(*a)), *b))
|
||||
}
|
||||
AddConstraint(ConstrainRegSubReg(a, b)) => {
|
||||
Some((a, b))
|
||||
@ -485,23 +495,33 @@ impl RegionVarBindings {
|
||||
|
||||
fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
|
||||
match (a, b) {
|
||||
(re_static, _) | (_, re_static) => {
|
||||
re_static // nothing lives longer than static
|
||||
(ReLateBound(*), _) |
|
||||
(_, ReLateBound(*)) |
|
||||
(ReEarlyBound(*), _) |
|
||||
(_, ReEarlyBound(*)) => {
|
||||
self.tcx.sess.bug(
|
||||
format!("Cannot relate bound region: LUB({}, {})",
|
||||
a.repr(self.tcx),
|
||||
b.repr(self.tcx)));
|
||||
}
|
||||
|
||||
(re_empty, r) | (r, re_empty) => {
|
||||
(ReStatic, _) | (_, ReStatic) => {
|
||||
ReStatic // nothing lives longer than static
|
||||
}
|
||||
|
||||
(ReEmpty, r) | (r, ReEmpty) => {
|
||||
r // everything lives longer than empty
|
||||
}
|
||||
|
||||
(re_infer(ReVar(v_id)), _) | (_, re_infer(ReVar(v_id))) => {
|
||||
(ReInfer(ReVar(v_id)), _) | (_, ReInfer(ReVar(v_id))) => {
|
||||
self.tcx.sess.span_bug(
|
||||
self.var_origins[v_id.to_uint()].span(),
|
||||
format!("lub_concrete_regions invoked with \
|
||||
non-concrete regions: {:?}, {:?}", a, b));
|
||||
}
|
||||
|
||||
(f @ re_free(ref fr), re_scope(s_id)) |
|
||||
(re_scope(s_id), f @ re_free(ref fr)) => {
|
||||
(f @ ReFree(ref fr), ReScope(s_id)) |
|
||||
(ReScope(s_id), f @ ReFree(ref fr)) => {
|
||||
// A "free" region can be interpreted as "some region
|
||||
// at least as big as the block fr.scope_id". So, we can
|
||||
// reasonably compare free regions and scopes:
|
||||
@ -514,35 +534,30 @@ impl RegionVarBindings {
|
||||
|
||||
// otherwise, we don't know what the free region is,
|
||||
// so we must conservatively say the LUB is static:
|
||||
_ => re_static
|
||||
_ => ReStatic
|
||||
}
|
||||
}
|
||||
|
||||
(re_scope(a_id), re_scope(b_id)) => {
|
||||
(ReScope(a_id), ReScope(b_id)) => {
|
||||
// The region corresponding to an outer block is a
|
||||
// subtype of the region corresponding to an inner
|
||||
// block.
|
||||
let rm = self.tcx.region_maps;
|
||||
match rm.nearest_common_ancestor(a_id, b_id) {
|
||||
Some(r_id) => re_scope(r_id),
|
||||
_ => re_static
|
||||
Some(r_id) => ReScope(r_id),
|
||||
_ => ReStatic
|
||||
}
|
||||
}
|
||||
|
||||
(re_free(ref a_fr), re_free(ref b_fr)) => {
|
||||
(ReFree(ref a_fr), ReFree(ref b_fr)) => {
|
||||
self.lub_free_regions(a_fr, b_fr)
|
||||
}
|
||||
|
||||
// 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(_)) => {
|
||||
if a == b {a} else {re_static}
|
||||
(ReInfer(ReSkolemized(*)), _) |
|
||||
(_, ReInfer(ReSkolemized(*))) => {
|
||||
if a == b {a} else {ReStatic}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -560,7 +575,7 @@ impl RegionVarBindings {
|
||||
return match a.cmp(b) {
|
||||
Less => helper(self, a, b),
|
||||
Greater => helper(self, b, a),
|
||||
Equal => ty::re_free(*a)
|
||||
Equal => ty::ReFree(*a)
|
||||
};
|
||||
|
||||
fn helper(this: &RegionVarBindings,
|
||||
@ -569,11 +584,11 @@ impl RegionVarBindings {
|
||||
{
|
||||
let rm = this.tcx.region_maps;
|
||||
if rm.sub_free_region(*a, *b) {
|
||||
ty::re_free(*b)
|
||||
ty::ReFree(*b)
|
||||
} else if rm.sub_free_region(*b, *a) {
|
||||
ty::re_free(*a)
|
||||
ty::ReFree(*a)
|
||||
} else {
|
||||
ty::re_static
|
||||
ty::ReStatic
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -584,26 +599,36 @@ impl RegionVarBindings {
|
||||
-> cres<Region> {
|
||||
debug!("glb_concrete_regions({:?}, {:?})", a, b);
|
||||
match (a, b) {
|
||||
(re_static, r) | (r, re_static) => {
|
||||
(ReLateBound(*), _) |
|
||||
(_, ReLateBound(*)) |
|
||||
(ReEarlyBound(*), _) |
|
||||
(_, ReEarlyBound(*)) => {
|
||||
self.tcx.sess.bug(
|
||||
format!("Cannot relate bound region: GLB({}, {})",
|
||||
a.repr(self.tcx),
|
||||
b.repr(self.tcx)));
|
||||
}
|
||||
|
||||
(ReStatic, r) | (r, ReStatic) => {
|
||||
// static lives longer than everything else
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
(re_empty, _) | (_, re_empty) => {
|
||||
(ReEmpty, _) | (_, ReEmpty) => {
|
||||
// nothing lives shorter than everything else
|
||||
Ok(re_empty)
|
||||
Ok(ReEmpty)
|
||||
}
|
||||
|
||||
(re_infer(ReVar(v_id)), _) |
|
||||
(_, re_infer(ReVar(v_id))) => {
|
||||
(ReInfer(ReVar(v_id)), _) |
|
||||
(_, ReInfer(ReVar(v_id))) => {
|
||||
self.tcx.sess.span_bug(
|
||||
self.var_origins[v_id.to_uint()].span(),
|
||||
format!("glb_concrete_regions invoked with \
|
||||
non-concrete regions: {:?}, {:?}", a, b));
|
||||
}
|
||||
|
||||
(re_free(ref fr), s @ re_scope(s_id)) |
|
||||
(s @ re_scope(s_id), re_free(ref fr)) => {
|
||||
(ReFree(ref fr), s @ ReScope(s_id)) |
|
||||
(s @ ReScope(s_id), ReFree(ref fr)) => {
|
||||
// Free region is something "at least as big as
|
||||
// `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger
|
||||
// than the scope `s_id`, then we can say that the GLB
|
||||
@ -616,23 +641,18 @@ impl RegionVarBindings {
|
||||
}
|
||||
}
|
||||
|
||||
(re_scope(a_id), re_scope(b_id)) => {
|
||||
(ReScope(a_id), ReScope(b_id)) => {
|
||||
self.intersect_scopes(a, b, a_id, b_id)
|
||||
}
|
||||
|
||||
(re_free(ref a_fr), re_free(ref b_fr)) => {
|
||||
(ReFree(ref a_fr), ReFree(ref b_fr)) => {
|
||||
self.glb_free_regions(a_fr, b_fr)
|
||||
}
|
||||
|
||||
// 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(_)) => {
|
||||
(ReInfer(ReSkolemized(*)), _) |
|
||||
(_, ReInfer(ReSkolemized(*))) => {
|
||||
if a == b {
|
||||
Ok(a)
|
||||
} else {
|
||||
@ -655,7 +675,7 @@ impl RegionVarBindings {
|
||||
return match a.cmp(b) {
|
||||
Less => helper(self, a, b),
|
||||
Greater => helper(self, b, a),
|
||||
Equal => Ok(ty::re_free(*a))
|
||||
Equal => Ok(ty::ReFree(*a))
|
||||
};
|
||||
|
||||
fn helper(this: &RegionVarBindings,
|
||||
@ -664,11 +684,11 @@ impl RegionVarBindings {
|
||||
{
|
||||
let rm = this.tcx.region_maps;
|
||||
if rm.sub_free_region(*a, *b) {
|
||||
Ok(ty::re_free(*a))
|
||||
Ok(ty::ReFree(*a))
|
||||
} else if rm.sub_free_region(*b, *a) {
|
||||
Ok(ty::re_free(*b))
|
||||
Ok(ty::ReFree(*b))
|
||||
} else {
|
||||
this.intersect_scopes(ty::re_free(*a), ty::re_free(*b),
|
||||
this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
|
||||
a.scope_id, b.scope_id)
|
||||
}
|
||||
}
|
||||
@ -695,8 +715,8 @@ impl RegionVarBindings {
|
||||
scope_a, scope_b, region_a, region_b);
|
||||
let rm = self.tcx.region_maps;
|
||||
match rm.nearest_common_ancestor(scope_a, scope_b) {
|
||||
Some(r_id) if scope_a == r_id => Ok(re_scope(scope_b)),
|
||||
Some(r_id) if scope_b == r_id => Ok(re_scope(scope_a)),
|
||||
Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)),
|
||||
Some(r_id) if scope_b == r_id => Ok(ReScope(scope_a)),
|
||||
_ => Err(ty::terr_regions_no_overlap(region_a, region_b))
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
@ -181,21 +192,21 @@ impl ResolveState {
|
||||
pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region {
|
||||
debug!("Resolve_region({})", orig.inf_str(self.infcx));
|
||||
match orig {
|
||||
ty::re_infer(ty::ReVar(rid)) => self.resolve_region_var(rid),
|
||||
ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid),
|
||||
_ => orig
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region {
|
||||
if !self.should(resolve_rvar) {
|
||||
return ty::re_infer(ty::ReVar(rid));
|
||||
return ty::ReInfer(ty::ReVar(rid));
|
||||
}
|
||||
self.infcx.region_vars.resolve_var(rid)
|
||||
}
|
||||
|
||||
pub fn assert_not_rvar(&mut self, rid: RegionVid, r: ty::Region) {
|
||||
match r {
|
||||
ty::re_infer(ty::ReVar(rid2)) => {
|
||||
ty::ReInfer(ty::ReVar(rid2)) => {
|
||||
self.err = Some(region_var_bound_by_region_var(rid, rid2));
|
||||
}
|
||||
_ => { }
|
||||
|
@ -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,16 +186,13 @@ 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
|
||||
// or new variables:
|
||||
match *tainted_region {
|
||||
ty::re_infer(ty::ReVar(ref vid)) => {
|
||||
ty::ReInfer(ty::ReVar(ref vid)) => {
|
||||
if new_vars.iter().any(|x| x == vid) { continue; }
|
||||
}
|
||||
_ => {
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ impl Env {
|
||||
meta: FnMeta {purity: ast::impure_fn,
|
||||
proto: ast::ProtoBare,
|
||||
onceness: ast::Many,
|
||||
region: ty::re_static,
|
||||
region: ty::ReStatic,
|
||||
bounds: @~[]},
|
||||
sig: FnSig {
|
||||
inputs: inputs,
|
||||
@ -203,22 +203,22 @@ impl Env {
|
||||
}
|
||||
|
||||
pub fn t_rptr_bound(&self, id: uint) -> ty::t {
|
||||
ty::mk_imm_rptr(self.tcx, ty::re_bound(ty::br_anon(id)), self.t_int())
|
||||
ty::mk_imm_rptr(self.tcx, ty::re_bound(ty::BrAnon(id)), self.t_int())
|
||||
}
|
||||
|
||||
pub fn t_rptr_scope(&self, id: ast::node_id) -> ty::t {
|
||||
ty::mk_imm_rptr(self.tcx, ty::re_scope(id), self.t_int())
|
||||
ty::mk_imm_rptr(self.tcx, ty::ReScope(id), self.t_int())
|
||||
}
|
||||
|
||||
pub fn t_rptr_free(&self, nid: ast::node_id, id: uint) -> ty::t {
|
||||
ty::mk_imm_rptr(self.tcx,
|
||||
ty::re_free(ty::FreeRegion {scope_id: nid,
|
||||
bound_region: ty::br_anon(id)}),
|
||||
ty::ReFree(ty::FreeRegion {scope_id: nid,
|
||||
bound_region: ty::BrAnon(id)}),
|
||||
self.t_int())
|
||||
}
|
||||
|
||||
pub fn t_rptr_static(&self) -> ty::t {
|
||||
ty::mk_imm_rptr(self.tcx, ty::re_static, self.t_int())
|
||||
ty::mk_imm_rptr(self.tcx, ty::ReStatic, self.t_int())
|
||||
}
|
||||
|
||||
pub fn lub() -> Lub { Lub(self.infcx.combine_fields(true, dummy_sp())) }
|
||||
|
@ -19,16 +19,23 @@ The type checker is responsible for:
|
||||
3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
|
||||
Well, dear reader, read on)
|
||||
|
||||
The main entry point is `check_crate()`. Type checking operates in two major
|
||||
phases: collect and check. The collect phase passes over all items and
|
||||
determines their type, without examining their "innards". The check phase
|
||||
then checks function bodies and so forth.
|
||||
The main entry point is `check_crate()`. Type checking operates in
|
||||
several major phases:
|
||||
|
||||
Within the check phase, we check each function body one at a time (bodies of
|
||||
function expressions are checked as part of the containing function).
|
||||
Inference is used to supply types wherever they are unknown. The actual
|
||||
checking of a function itself has several phases (check, regionck, writeback),
|
||||
as discussed in the documentation for the `check` module.
|
||||
1. The collect phase first passes over all items and determines their
|
||||
type, without examining their "innards".
|
||||
|
||||
2. Variance inference then runs to compute the variance of each parameter
|
||||
|
||||
3. Coherence checks for overlapping or orphaned impls
|
||||
|
||||
4. Finally, the check phase then checks function bodies and so forth.
|
||||
Within the check phase, we check each function body one at a time
|
||||
(bodies of function expressions are checked as part of the
|
||||
containing function). Inference is used to supply types wherever
|
||||
they are unknown. The actual checking of a function itself has
|
||||
several phases (check, regionck, writeback), as discussed in the
|
||||
documentation for the `check` module.
|
||||
|
||||
The type checker is defined into various submodules which are documented
|
||||
independently:
|
||||
@ -39,6 +46,10 @@ independently:
|
||||
- collect: computes the types of each top-level item and enters them into
|
||||
the `cx.tcache` table for later use
|
||||
|
||||
- coherence: enforces coherence rules, builds some tables
|
||||
|
||||
- variance: variance inference
|
||||
|
||||
- check: walks over function bodies and type checks them, inferring types for
|
||||
local variables, type parameters, etc as necessary.
|
||||
|
||||
@ -64,7 +75,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;
|
||||
@ -72,6 +82,7 @@ pub mod astconv;
|
||||
pub mod infer;
|
||||
pub mod collect;
|
||||
pub mod coherence;
|
||||
pub mod variance;
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable, Eq, Ord)]
|
||||
pub enum param_index {
|
||||
@ -266,7 +277,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
|
||||
}
|
||||
}
|
||||
@ -306,19 +317,19 @@ pub fn require_same_types(
|
||||
|
||||
// a list of mapping from in-scope-region-names ("isr") to the
|
||||
// corresponding ty::Region
|
||||
pub type isr_alist = @List<(ty::bound_region, ty::Region)>;
|
||||
pub type isr_alist = @List<(ty::BoundRegion, ty::Region)>;
|
||||
|
||||
trait get_and_find_region {
|
||||
fn get(&self, br: ty::bound_region) -> ty::Region;
|
||||
fn find(&self, br: ty::bound_region) -> Option<ty::Region>;
|
||||
fn get(&self, br: ty::BoundRegion) -> ty::Region;
|
||||
fn find(&self, br: ty::BoundRegion) -> Option<ty::Region>;
|
||||
}
|
||||
|
||||
impl get_and_find_region for isr_alist {
|
||||
fn get(&self, br: ty::bound_region) -> ty::Region {
|
||||
fn get(&self, br: ty::BoundRegion) -> ty::Region {
|
||||
self.find(br).unwrap()
|
||||
}
|
||||
|
||||
fn find(&self, br: ty::bound_region) -> Option<ty::Region> {
|
||||
fn find(&self, br: ty::BoundRegion) -> Option<ty::Region> {
|
||||
let mut ret = None;
|
||||
do list::each(*self) |isr| {
|
||||
let (isr_br, isr_r) = *isr;
|
||||
@ -354,7 +365,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 +411,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()))
|
||||
@ -456,6 +467,9 @@ pub fn check_crate(tcx: ty::ctxt,
|
||||
// have valid types and not error
|
||||
tcx.sess.abort_if_errors();
|
||||
|
||||
time(time_passes, "variance inference", (), |_|
|
||||
variance::infer_variance(tcx, crate));
|
||||
|
||||
time(time_passes, "coherence checking", (), |_|
|
||||
coherence::check_coherence(ccx, crate));
|
||||
|
||||
|
@ -11,312 +11,71 @@
|
||||
|
||||
use middle::ty;
|
||||
|
||||
use std::result;
|
||||
use std::vec;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::opt_vec::OptVec;
|
||||
use syntax::opt_vec;
|
||||
use syntax::parse::token::special_idents;
|
||||
|
||||
#[deriving(ToStr)]
|
||||
pub struct RegionError {
|
||||
msg: ~str,
|
||||
replacement: ty::Region
|
||||
}
|
||||
|
||||
/// Defines strategies for handling regions that are omitted. For
|
||||
/// example, if one writes the type `&Foo`, then the lifetime of of
|
||||
/// this borrowed pointer has been omitted. When converting this
|
||||
/// type, the generic functions in astconv will invoke `anon_regions`
|
||||
/// on the provided region-scope to decide how to translate this
|
||||
/// omitted region.
|
||||
///
|
||||
/// It is not always legal to omit regions, therefore `anon_regions`
|
||||
/// can return `Err(())` to indicate that this is not a scope in which
|
||||
/// regions can legally be omitted.
|
||||
pub trait RegionScope {
|
||||
fn anon_region(&self, span: Span) -> Result<ty::Region, RegionError>;
|
||||
fn self_region(&self, span: Span) -> Result<ty::Region, RegionError>;
|
||||
fn named_region(&self, span: Span, id: ast::Ident)
|
||||
-> Result<ty::Region, RegionError>;
|
||||
fn anon_regions(&self,
|
||||
span: Span,
|
||||
count: uint)
|
||||
-> Result<~[ty::Region], ()>;
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct EmptyRscope;
|
||||
impl RegionScope for EmptyRscope {
|
||||
fn anon_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
|
||||
result::Err(RegionError {
|
||||
msg: ~"only 'static is allowed here",
|
||||
replacement: ty::re_static
|
||||
})
|
||||
}
|
||||
fn self_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
|
||||
self.anon_region(_span)
|
||||
}
|
||||
fn named_region(&self, _span: Span, _id: ast::Ident)
|
||||
-> Result<ty::Region, RegionError>
|
||||
{
|
||||
self.anon_region(_span)
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct RegionParamNames(OptVec<ast::Ident>);
|
||||
|
||||
impl RegionParamNames {
|
||||
fn has_self(&self) -> bool {
|
||||
self.has_ident(special_idents::self_)
|
||||
}
|
||||
|
||||
fn has_ident(&self, ident: ast::Ident) -> bool {
|
||||
for region_param_name in self.iter() {
|
||||
if *region_param_name == ident {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn add_generics(&mut self, generics: &ast::Generics) {
|
||||
match generics.lifetimes {
|
||||
opt_vec::Empty => {}
|
||||
opt_vec::Vec(ref new_lifetimes) => {
|
||||
match **self {
|
||||
opt_vec::Empty => {
|
||||
*self = RegionParamNames(
|
||||
opt_vec::Vec(new_lifetimes.map(|lt| lt.ident)));
|
||||
}
|
||||
opt_vec::Vec(ref mut existing_lifetimes) => {
|
||||
for new_lifetime in new_lifetimes.iter() {
|
||||
existing_lifetimes.push(new_lifetime.ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience function to produce the error for an unresolved name. The
|
||||
// optional argument specifies a custom replacement.
|
||||
pub fn undeclared_name(custom_replacement: Option<ty::Region>)
|
||||
-> Result<ty::Region, RegionError> {
|
||||
let replacement = match custom_replacement {
|
||||
None => ty::re_bound(ty::br_self),
|
||||
Some(custom_replacement) => custom_replacement
|
||||
};
|
||||
Err(RegionError {
|
||||
msg: ~"this lifetime must be declared",
|
||||
replacement: replacement
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_generics(generics: &ast::Generics) -> RegionParamNames {
|
||||
match generics.lifetimes {
|
||||
opt_vec::Empty => RegionParamNames(opt_vec::Empty),
|
||||
opt_vec::Vec(ref lifetimes) => {
|
||||
RegionParamNames(opt_vec::Vec(lifetimes.map(|lt| lt.ident)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_lifetimes(lifetimes: &opt_vec::OptVec<ast::Lifetime>)
|
||||
-> RegionParamNames {
|
||||
match *lifetimes {
|
||||
opt_vec::Empty => RegionParamNames::new(),
|
||||
opt_vec::Vec(ref v) => {
|
||||
RegionParamNames(opt_vec::Vec(v.map(|lt| lt.ident)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new() -> RegionParamNames {
|
||||
RegionParamNames(opt_vec::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
struct RegionParameterization {
|
||||
variance: ty::region_variance,
|
||||
region_param_names: RegionParamNames,
|
||||
}
|
||||
|
||||
impl RegionParameterization {
|
||||
pub fn from_variance_and_generics(variance: Option<ty::region_variance>,
|
||||
generics: &ast::Generics)
|
||||
-> Option<RegionParameterization> {
|
||||
match variance {
|
||||
None => None,
|
||||
Some(variance) => {
|
||||
Some(RegionParameterization {
|
||||
variance: variance,
|
||||
region_param_names:
|
||||
RegionParamNames::from_generics(generics),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct MethodRscope {
|
||||
explicit_self: ast::explicit_self_,
|
||||
variance: Option<ty::region_variance>,
|
||||
region_param_names: RegionParamNames,
|
||||
}
|
||||
|
||||
impl MethodRscope {
|
||||
// `generics` here refers to the generics of the outer item (impl or
|
||||
// trait).
|
||||
pub fn new(explicit_self: ast::explicit_self_,
|
||||
variance: Option<ty::region_variance>,
|
||||
rcvr_generics: &ast::Generics)
|
||||
-> MethodRscope {
|
||||
let region_param_names =
|
||||
RegionParamNames::from_generics(rcvr_generics);
|
||||
MethodRscope {
|
||||
explicit_self: explicit_self,
|
||||
variance: variance,
|
||||
region_param_names: region_param_names
|
||||
}
|
||||
}
|
||||
|
||||
pub fn region_param_names(&self) -> RegionParamNames {
|
||||
self.region_param_names.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionScope for MethodRscope {
|
||||
fn anon_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
|
||||
result::Err(RegionError {
|
||||
msg: ~"anonymous lifetimes are not permitted here",
|
||||
replacement: ty::re_bound(ty::br_self)
|
||||
})
|
||||
}
|
||||
fn self_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
|
||||
assert!(self.variance.is_some());
|
||||
match self.variance {
|
||||
None => {} // must be borrowed self, so this is OK
|
||||
Some(_) => {
|
||||
if !self.region_param_names.has_self() {
|
||||
return Err(RegionError {
|
||||
msg: ~"the `self` lifetime must be declared",
|
||||
replacement: ty::re_bound(ty::br_self)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
result::Ok(ty::re_bound(ty::br_self))
|
||||
}
|
||||
fn named_region(&self, span: Span, id: ast::Ident)
|
||||
-> Result<ty::Region, RegionError> {
|
||||
if !self.region_param_names.has_ident(id) {
|
||||
return RegionParamNames::undeclared_name(None);
|
||||
}
|
||||
do EmptyRscope.named_region(span, id).or_else |_e| {
|
||||
result::Err(RegionError {
|
||||
msg: ~"lifetime is not in scope",
|
||||
replacement: ty::re_bound(ty::br_self)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct TypeRscope(Option<RegionParameterization>);
|
||||
|
||||
impl TypeRscope {
|
||||
fn replacement(&self) -> ty::Region {
|
||||
if self.is_some() {
|
||||
ty::re_bound(ty::br_self)
|
||||
} else {
|
||||
ty::re_static
|
||||
}
|
||||
}
|
||||
}
|
||||
impl RegionScope for TypeRscope {
|
||||
fn anon_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
|
||||
result::Err(RegionError {
|
||||
msg: ~"anonymous lifetimes are not permitted here",
|
||||
replacement: self.replacement()
|
||||
})
|
||||
}
|
||||
fn self_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
|
||||
match **self {
|
||||
None => {
|
||||
// if the self region is used, region parameterization should
|
||||
// have inferred that this type is RP
|
||||
fail!("region parameterization should have inferred that \
|
||||
this type is RP");
|
||||
}
|
||||
Some(ref region_parameterization) => {
|
||||
if !region_parameterization.region_param_names.has_self() {
|
||||
return Err(RegionError {
|
||||
msg: ~"the `self` lifetime must be declared",
|
||||
replacement: ty::re_bound(ty::br_self)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
result::Ok(ty::re_bound(ty::br_self))
|
||||
}
|
||||
fn named_region(&self, span: Span, id: ast::Ident)
|
||||
-> Result<ty::Region, RegionError> {
|
||||
do EmptyRscope.named_region(span, id).or_else |_e| {
|
||||
result::Err(RegionError {
|
||||
msg: ~"only 'self is allowed as part of a type declaration",
|
||||
replacement: self.replacement()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bound_self_region(rp: Option<ty::region_variance>)
|
||||
-> OptVec<ty::Region> {
|
||||
match rp {
|
||||
Some(_) => opt_vec::with(ty::re_bound(ty::br_self)),
|
||||
None => opt_vec::Empty
|
||||
// A scope in which all regions must be explicitly named
|
||||
pub struct ExplicitRscope;
|
||||
|
||||
impl RegionScope for ExplicitRscope {
|
||||
fn anon_regions(&self,
|
||||
_span: Span,
|
||||
_count: uint)
|
||||
-> Result<~[ty::Region], ()> {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A scope in which we generate anonymous, late-bound regions for
|
||||
/// omitted regions. This occurs in function signatures.
|
||||
pub struct BindingRscope {
|
||||
base: @RegionScope,
|
||||
anon_bindings: @mut uint,
|
||||
region_param_names: RegionParamNames,
|
||||
binder_id: ast::NodeId,
|
||||
anon_bindings: @mut uint
|
||||
}
|
||||
|
||||
impl Clone for BindingRscope {
|
||||
fn clone(&self) -> BindingRscope {
|
||||
impl BindingRscope {
|
||||
pub fn new(binder_id: ast::NodeId) -> BindingRscope {
|
||||
BindingRscope {
|
||||
base: self.base,
|
||||
anon_bindings: self.anon_bindings,
|
||||
region_param_names: self.region_param_names.clone(),
|
||||
binder_id: binder_id,
|
||||
anon_bindings: @mut 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn in_binding_rscope<RS:RegionScope + Clone + 'static>(
|
||||
this: &RS,
|
||||
region_param_names: RegionParamNames)
|
||||
-> BindingRscope {
|
||||
let base = @(*this).clone();
|
||||
let base = base as @RegionScope;
|
||||
BindingRscope {
|
||||
base: base,
|
||||
anon_bindings: @mut 0,
|
||||
region_param_names: region_param_names,
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionScope for BindingRscope {
|
||||
fn anon_region(&self, _span: Span) -> Result<ty::Region, RegionError> {
|
||||
fn anon_regions(&self,
|
||||
_: Span,
|
||||
count: uint)
|
||||
-> Result<~[ty::Region], ()> {
|
||||
let idx = *self.anon_bindings;
|
||||
*self.anon_bindings += 1;
|
||||
result::Ok(ty::re_bound(ty::br_anon(idx)))
|
||||
}
|
||||
fn self_region(&self, span: Span) -> Result<ty::Region, RegionError> {
|
||||
self.base.self_region(span)
|
||||
}
|
||||
fn named_region(&self,
|
||||
span: Span,
|
||||
id: ast::Ident) -> Result<ty::Region, RegionError>
|
||||
{
|
||||
do self.base.named_region(span, id).or_else |_e| {
|
||||
let result = ty::re_bound(ty::br_named(id));
|
||||
if self.region_param_names.has_ident(id) {
|
||||
result::Ok(result)
|
||||
} else {
|
||||
RegionParamNames::undeclared_name(Some(result))
|
||||
}
|
||||
}
|
||||
*self.anon_bindings += count;
|
||||
Ok(vec::from_fn(count, |i| ty::ReLateBound(self.binder_id,
|
||||
ty::BrAnon(idx + i))))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bound_type_regions(defs: &[ty::RegionParameterDef])
|
||||
-> OptVec<ty::Region> {
|
||||
assert!(defs.iter().all(|def| def.def_id.crate == ast::LOCAL_CRATE));
|
||||
defs.iter().enumerate().map(
|
||||
|(i, def)| ty::ReEarlyBound(def.def_id.node, i, def.ident)).collect()
|
||||
}
|
||||
|
1000
src/librustc/middle/typeck/variance.rs
Normal file
1000
src/librustc/middle/typeck/variance.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -11,11 +11,11 @@
|
||||
|
||||
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::{br_fresh, ctxt, field};
|
||||
use middle::ty::{BoundRegion, BrAnon, BrNamed};
|
||||
use middle::ty::{BrFresh, ctxt, field};
|
||||
use middle::ty::{mt, t, param_ty};
|
||||
use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region,
|
||||
re_empty};
|
||||
use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region,
|
||||
ReEmpty};
|
||||
use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
|
||||
use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure};
|
||||
use middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param};
|
||||
@ -71,7 +71,7 @@ pub fn explain_region(cx: ctxt, region: ty::Region) -> ~str {
|
||||
pub fn explain_region_and_span(cx: ctxt, region: ty::Region)
|
||||
-> (~str, Option<Span>) {
|
||||
return match region {
|
||||
re_scope(node_id) => {
|
||||
ReScope(node_id) => {
|
||||
match cx.items.find(&node_id) {
|
||||
Some(&ast_map::node_block(ref blk)) => {
|
||||
explain_span(cx, "block", blk.span)
|
||||
@ -104,11 +104,11 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region)
|
||||
}
|
||||
}
|
||||
|
||||
re_free(ref fr) => {
|
||||
ReFree(ref fr) => {
|
||||
let prefix = match fr.bound_region {
|
||||
br_anon(idx) => format!("the anonymous lifetime \\#{} defined on",
|
||||
BrAnon(idx) => format!("the anonymous lifetime \\#{} defined on",
|
||||
idx + 1),
|
||||
br_fresh(_) => format!("an anonymous lifetime defined on"),
|
||||
BrFresh(_) => format!("an anonymous lifetime defined on"),
|
||||
_ => format!("the lifetime {} as defined on",
|
||||
bound_region_ptr_to_str(cx, fr.bound_region))
|
||||
};
|
||||
@ -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)
|
||||
@ -125,13 +130,13 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region)
|
||||
}
|
||||
}
|
||||
|
||||
re_static => { (~"the static lifetime", None) }
|
||||
ReStatic => { (~"the static lifetime", None) }
|
||||
|
||||
re_empty => { (~"the empty lifetime", None) }
|
||||
ReEmpty => { (~"the empty lifetime", None) }
|
||||
|
||||
// I believe these cases should not occur (except when debugging,
|
||||
// perhaps)
|
||||
re_infer(_) | re_bound(_) => {
|
||||
ty::ReInfer(_) | ty::ReEarlyBound(*) | ty::ReLateBound(*) => {
|
||||
(format!("lifetime {:?}", region), None)
|
||||
}
|
||||
};
|
||||
@ -145,27 +150,28 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bound_region_ptr_to_str(cx: ctxt, br: bound_region) -> ~str {
|
||||
pub fn bound_region_ptr_to_str(cx: ctxt, br: BoundRegion) -> ~str {
|
||||
bound_region_to_str(cx, "&", true, br)
|
||||
}
|
||||
|
||||
pub fn bound_region_to_str(cx: ctxt,
|
||||
prefix: &str, space: bool,
|
||||
br: bound_region) -> ~str {
|
||||
br: BoundRegion) -> ~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_anon(_) => prefix.to_str(),
|
||||
br_fresh(_) => prefix.to_str(),
|
||||
br_cap_avoid(_, br) => bound_region_to_str(cx, prefix, space, *br)
|
||||
BrNamed(_, ident) => format!("{}'{}{}", prefix,
|
||||
cx.sess.str_of(ident), space_str),
|
||||
BrAnon(_) => prefix.to_str(),
|
||||
BrFresh(_) => prefix.to_str(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn re_scope_id_to_str(cx: ctxt, node_id: ast::NodeId) -> ~str {
|
||||
pub fn ReScope_id_to_str(cx: ctxt, node_id: ast::NodeId) -> ~str {
|
||||
match cx.items.find(&node_id) {
|
||||
Some(&ast_map::node_block(ref blk)) => {
|
||||
format!("<block at {}>",
|
||||
@ -198,7 +204,7 @@ pub fn re_scope_id_to_str(cx: ctxt, node_id: ast::NodeId) -> ~str {
|
||||
format!("<unknown-{}>", node_id)
|
||||
}
|
||||
_ => { cx.sess.bug(
|
||||
format!("re_scope refers to {}",
|
||||
format!("ReScope refers to {}",
|
||||
ast_map::node_id_to_str(cx.items, node_id,
|
||||
token::get_ident_interner()))) }
|
||||
}
|
||||
@ -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::ReScope(_) => prefix.to_str(),
|
||||
ty::ReEarlyBound(_, _, ident) => cx.sess.str_of(ident).to_owned(),
|
||||
ty::ReLateBound(_, br) => bound_region_to_str(cx, prefix, space, br),
|
||||
ty::ReFree(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region),
|
||||
ty::ReInfer(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::ReInfer(ReVar(_)) => prefix.to_str(),
|
||||
ty::ReStatic => format!("{}'static{}", prefix, space_str),
|
||||
ty::ReEmpty => 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 {
|
||||
@ -348,8 +356,8 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
|
||||
};
|
||||
|
||||
match (cty.sigil, cty.region) {
|
||||
(ast::ManagedSigil, ty::re_static) |
|
||||
(ast::OwnedSigil, ty::re_static) => {}
|
||||
(ast::ManagedSigil, ty::ReStatic) |
|
||||
(ast::OwnedSigil, ty::ReStatic) => {}
|
||||
|
||||
(_, region) => {
|
||||
s.push_str(region_to_str(cx, "", true, region));
|
||||
@ -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({}: {})",
|
||||
@ -663,15 +689,58 @@ impl Repr for ast::Pat {
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::bound_region {
|
||||
impl Repr for ty::BoundRegion {
|
||||
fn repr(&self, tcx: ctxt) -> ~str {
|
||||
bound_region_ptr_to_str(tcx, *self)
|
||||
match *self {
|
||||
ty::BrAnon(id) => format!("BrAnon({})", id),
|
||||
ty::BrNamed(id, ident) => format!("BrNamed({}, {})",
|
||||
id.repr(tcx),
|
||||
ident.repr(tcx)),
|
||||
ty::BrFresh(id) => format!("BrFresh({})", id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::Region {
|
||||
fn repr(&self, tcx: ctxt) -> ~str {
|
||||
region_to_str(tcx, "", false, *self)
|
||||
match *self {
|
||||
ty::ReEarlyBound(id, index, ident) => {
|
||||
format!("ReEarlyBound({}, {}, {})",
|
||||
id, index, ident.repr(tcx))
|
||||
}
|
||||
|
||||
ty::ReLateBound(binder_id, ref bound_region) => {
|
||||
format!("ReLateBound({}, {})",
|
||||
binder_id, bound_region.repr(tcx))
|
||||
}
|
||||
|
||||
ty::ReFree(ref fr) => {
|
||||
format!("ReFree({}, {})",
|
||||
fr.scope_id,
|
||||
fr.bound_region.repr(tcx))
|
||||
}
|
||||
|
||||
ty::ReScope(id) => {
|
||||
format!("ReScope({})", id)
|
||||
}
|
||||
|
||||
ty::ReStatic => {
|
||||
format!("ReStatic")
|
||||
}
|
||||
|
||||
ty::ReInfer(ReVar(ref vid)) => {
|
||||
format!("ReInfer({})", vid.id)
|
||||
}
|
||||
|
||||
ty::ReInfer(ReSkolemized(id, ref bound_region)) => {
|
||||
format!("re_skolemized({}, {})",
|
||||
id, bound_region.repr(tcx))
|
||||
}
|
||||
|
||||
ty::ReEmpty => {
|
||||
format!("ReEmpty")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
@ -251,6 +251,14 @@ pub enum Def {
|
||||
DefMethod(DefId /* method */, Option<DefId> /* trait */),
|
||||
}
|
||||
|
||||
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
|
||||
pub enum DefRegion {
|
||||
DefStaticRegion,
|
||||
DefEarlyBoundRegion(/* index */ uint, /* lifetime decl */ NodeId),
|
||||
DefLateBoundRegion(/* binder_id */ NodeId, /* depth */ uint, /* lifetime decl */ NodeId),
|
||||
DefFreeRegion(/* block scope */ NodeId, /* lifetime decl */ NodeId),
|
||||
}
|
||||
|
||||
// The set of MetaItems that define the compilation environment of the crate,
|
||||
// used to drive conditional compilation
|
||||
pub type CrateConfig = ~[@MetaItem];
|
||||
|
@ -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,23 +1566,30 @@ 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() {
|
||||
print_lifetime(s, lifetime);
|
||||
if !segment.types.is_empty() {
|
||||
let mut comma = false;
|
||||
for lifetime in segment.lifetimes.iter() {
|
||||
if comma {
|
||||
word_space(s, ",")
|
||||
}
|
||||
print_lifetime(s, lifetime);
|
||||
comma = true;
|
||||
}
|
||||
|
||||
commasep(s,
|
||||
inconsistent,
|
||||
segment.types.map_to_vec(|t| (*t).clone()),
|
||||
print_type);
|
||||
if !segment.types.is_empty() {
|
||||
if comma {
|
||||
word_space(s, ",")
|
||||
}
|
||||
commasep(s,
|
||||
inconsistent,
|
||||
segment.types.map_to_vec(|t| (*t).clone()),
|
||||
print_type);
|
||||
}
|
||||
|
||||
word(s.s, ">")
|
||||
}
|
||||
@ -1905,7 +1912,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(#6993) can't compare identifiers directly here
|
||||
if path.segments.last().identifier.name != ident.name {
|
||||
print_ident(s, ident);
|
||||
space(s.s);
|
||||
word_space(s, "=");
|
||||
|
@ -90,7 +90,32 @@ pub trait Visitor<E:Clone> {
|
||||
walk_struct_def(self, s, i, g, n, e)
|
||||
}
|
||||
fn visit_struct_field(&mut self, s:@struct_field, e:E) { walk_struct_field(self, s, e) }
|
||||
fn visit_mac(&mut self, m:&mac, e:E) { walk_mac(self, m, e); }
|
||||
fn visit_opt_lifetime_ref(&mut self,
|
||||
_span: Span,
|
||||
opt_lifetime: &Option<Lifetime>,
|
||||
env: E) {
|
||||
/*!
|
||||
* Visits an optional reference to a lifetime. The `span` is
|
||||
* the span of some surrounding reference should opt_lifetime
|
||||
* be None.
|
||||
*/
|
||||
match *opt_lifetime {
|
||||
Some(ref l) => self.visit_lifetime_ref(l, env),
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
fn visit_lifetime_ref(&mut self, _lifetime: &Lifetime, _e: E) {
|
||||
/*! Visits a reference to a lifetime */
|
||||
}
|
||||
fn visit_lifetime_decl(&mut self, _lifetime: &Lifetime, _e: E) {
|
||||
/*! Visits a declaration of a lifetime */
|
||||
}
|
||||
fn visit_explicit_self(&mut self, es: &explicit_self, e: E) {
|
||||
walk_explicit_self(self, es, e)
|
||||
}
|
||||
fn visit_mac(&mut self, macro:&mac, e:E) {
|
||||
walk_mac(self, macro, e)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_crate<E:Clone, V:Visitor<E>>(visitor: &mut V, crate: &Crate, env: E) {
|
||||
@ -119,6 +144,18 @@ pub fn walk_local<E:Clone, V:Visitor<E>>(visitor: &mut V, local: &Local, env: E)
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_explicit_self<E:Clone, V:Visitor<E>>(visitor: &mut V,
|
||||
explicit_self: &explicit_self,
|
||||
env: E) {
|
||||
match explicit_self.node {
|
||||
sty_static | sty_value(_) | sty_box(_) | sty_uniq(_) => {
|
||||
}
|
||||
sty_region(ref lifetime, _) => {
|
||||
visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime, env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_trait_ref<E:Clone, V:Visitor<E>>(visitor: &mut V,
|
||||
trait_ref: &ast::trait_ref,
|
||||
env: E) {
|
||||
@ -221,8 +258,11 @@ pub fn skip_ty<E, V:Visitor<E>>(_: &mut V, _: &Ty, _: E) {
|
||||
pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
|
||||
match typ.node {
|
||||
ty_box(ref mutable_type) | ty_uniq(ref mutable_type) |
|
||||
ty_vec(ref mutable_type) | ty_ptr(ref mutable_type) |
|
||||
ty_rptr(_, ref mutable_type) => {
|
||||
ty_vec(ref mutable_type) | ty_ptr(ref mutable_type) => {
|
||||
visitor.visit_ty(mutable_type.ty, env)
|
||||
}
|
||||
ty_rptr(ref lifetime, ref mutable_type) => {
|
||||
visitor.visit_opt_lifetime_ref(typ.span, lifetime, env.clone());
|
||||
visitor.visit_ty(mutable_type.ty, env)
|
||||
}
|
||||
ty_tup(ref tuple_element_types) => {
|
||||
@ -231,19 +271,27 @@ pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
|
||||
}
|
||||
}
|
||||
ty_closure(ref function_declaration) => {
|
||||
for argument in function_declaration.decl.inputs.iter() {
|
||||
for argument in function_declaration.decl.inputs.iter() {
|
||||
visitor.visit_ty(&argument.ty, env.clone())
|
||||
}
|
||||
visitor.visit_ty(&function_declaration.decl.output, env.clone());
|
||||
for bounds in function_declaration.bounds.iter() {
|
||||
}
|
||||
visitor.visit_ty(&function_declaration.decl.output, env.clone());
|
||||
for bounds in function_declaration.bounds.iter() {
|
||||
walk_ty_param_bounds(visitor, bounds, env.clone())
|
||||
}
|
||||
}
|
||||
visitor.visit_opt_lifetime_ref(
|
||||
typ.span,
|
||||
&function_declaration.region,
|
||||
env.clone());
|
||||
walk_lifetime_decls(visitor, &function_declaration.lifetimes,
|
||||
env.clone());
|
||||
}
|
||||
ty_bare_fn(ref function_declaration) => {
|
||||
for argument in function_declaration.decl.inputs.iter() {
|
||||
visitor.visit_ty(&argument.ty, env.clone())
|
||||
}
|
||||
visitor.visit_ty(&function_declaration.decl.output, env.clone())
|
||||
visitor.visit_ty(&function_declaration.decl.output, env.clone());
|
||||
walk_lifetime_decls(visitor, &function_declaration.lifetimes,
|
||||
env.clone());
|
||||
}
|
||||
ty_path(ref path, ref bounds, _) => {
|
||||
walk_path(visitor, path, env.clone());
|
||||
@ -262,10 +310,21 @@ pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_lifetime_decls<E:Clone, V:Visitor<E>>(visitor: &mut V,
|
||||
lifetimes: &OptVec<Lifetime>,
|
||||
env: E) {
|
||||
for l in lifetimes.iter() {
|
||||
visitor.visit_lifetime_decl(l, env.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_path<E:Clone, V:Visitor<E>>(visitor: &mut V, path: &Path, env: E) {
|
||||
for segment in path.segments.iter() {
|
||||
for typ in segment.types.iter() {
|
||||
visitor.visit_ty(typ, env.clone())
|
||||
visitor.visit_ty(typ, env.clone());
|
||||
}
|
||||
for lifetime in segment.lifetimes.iter() {
|
||||
visitor.visit_lifetime_ref(lifetime, env.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -354,6 +413,7 @@ pub fn walk_generics<E:Clone, V:Visitor<E>>(visitor: &mut V,
|
||||
for type_parameter in generics.ty_params.iter() {
|
||||
walk_ty_param_bounds(visitor, &type_parameter.bounds, env.clone())
|
||||
}
|
||||
walk_lifetime_decls(visitor, &generics.lifetimes, env);
|
||||
}
|
||||
|
||||
pub fn walk_fn_decl<E:Clone, V:Visitor<E>>(visitor: &mut V,
|
||||
@ -385,18 +445,31 @@ pub fn walk_fn<E:Clone, V:Visitor<E>>(visitor: &mut V,
|
||||
function_kind: &fn_kind,
|
||||
function_declaration: &fn_decl,
|
||||
function_body: &Block,
|
||||
_: Span,
|
||||
_span: Span,
|
||||
_: NodeId,
|
||||
env: E) {
|
||||
walk_fn_decl(visitor, function_declaration, env.clone());
|
||||
let generics = generics_of_fn(function_kind);
|
||||
visitor.visit_generics(&generics, env.clone());
|
||||
|
||||
match *function_kind {
|
||||
fk_item_fn(_, generics, _, _) => {
|
||||
visitor.visit_generics(generics, env.clone());
|
||||
}
|
||||
fk_method(_, generics, method) => {
|
||||
visitor.visit_generics(generics, env.clone());
|
||||
|
||||
visitor.visit_explicit_self(&method.explicit_self, env.clone());
|
||||
}
|
||||
fk_anon(*) | fk_fn_block(*) => {
|
||||
}
|
||||
}
|
||||
|
||||
visitor.visit_block(function_body, env)
|
||||
}
|
||||
|
||||
pub fn walk_ty_method<E:Clone, V:Visitor<E>>(visitor: &mut V,
|
||||
method_type: &TypeMethod,
|
||||
env: E) {
|
||||
method_type: &TypeMethod,
|
||||
env: E) {
|
||||
visitor.visit_explicit_self(&method_type.explicit_self, env.clone());
|
||||
for argument_type in method_type.decl.inputs.iter() {
|
||||
visitor.visit_ty(&argument_type.ty, env.clone())
|
||||
}
|
||||
|
@ -28,10 +28,11 @@ impl Trait<int> for S2 {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn foo<'a>() {
|
||||
let _ = S::new::<int,f64>(1, 1.0); //~ ERROR the impl referenced by this path has 1 type parameter, but 0 type parameters were supplied
|
||||
let _ = S::<'self,int>::new::<f64>(1, 1.0); //~ ERROR this impl has no lifetime parameter
|
||||
let _ = S::<'a,int>::new::<f64>(1, 1.0); //~ ERROR expected 0 lifetime parameter(s)
|
||||
let _: S2 = Trait::new::<int,f64>(1, 1.0); //~ ERROR the trait referenced by this path has 1 type parameter, but 0 type parameters were supplied
|
||||
let _: S2 = Trait::<'self,int>::new::<f64>(1, 1.0); //~ ERROR this trait has no lifetime parameter
|
||||
let _: S2 = Trait::<'a,int>::new::<f64>(1, 1.0); //~ ERROR expected 0 lifetime parameter(s)
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern:missing method `eat`
|
||||
trait animal {
|
||||
fn eat(&self);
|
||||
}
|
||||
@ -18,6 +17,7 @@ struct cat {
|
||||
}
|
||||
|
||||
impl animal for cat {
|
||||
//~^ ERROR not all trait methods implemented, missing: `eat`
|
||||
}
|
||||
|
||||
fn cat(in_x : uint) -> cat {
|
||||
|
@ -13,6 +13,6 @@
|
||||
use std::local_data;
|
||||
|
||||
local_data_key!(key: @&int)
|
||||
//~^ ERROR only 'static is allowed
|
||||
//~^ ERROR missing lifetime specifier
|
||||
|
||||
fn main() {}
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
struct thing(uint);
|
||||
impl Ord for thing { //~ ERROR missing method `lt`
|
||||
impl Ord for thing { //~ ERROR not all trait methods implemented, missing: `lt`
|
||||
fn le(&self, other: &thing) -> bool { **self < **other }
|
||||
fn ge(&self, other: &thing) -> bool { **self < **other }
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
fn id<T>(t: T) -> T { t }
|
||||
|
||||
fn f<'r, T>(v: &'r T) -> &'r fn()->T { id::<&'r fn()->T>(|| *v) } //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements
|
||||
fn f<'r, T>(v: &'r T) -> &'r fn()->T { id::<&'r fn()->T>(|| *v) } //~ ERROR cannot infer an appropriate lifetime
|
||||
|
||||
fn main() {
|
||||
let v = &5;
|
||||
|
@ -9,12 +9,12 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn f() { }
|
||||
struct S(&fn()); //~ ERROR Illegal anonymous lifetime
|
||||
pub static C: S = S(f); //~ ERROR Illegal anonymous lifetime
|
||||
struct S(&fn()); //~ ERROR missing lifetime specifier
|
||||
pub static C: S = S(f);
|
||||
|
||||
|
||||
fn g() { }
|
||||
type T = &fn(); //~ ERROR Illegal anonymous lifetime
|
||||
pub static D: T = g; //~ ERROR Illegal anonymous lifetime
|
||||
type T = &fn(); //~ ERROR missing lifetime specifier
|
||||
pub static D: T = g;
|
||||
|
||||
fn main() {}
|
||||
|
@ -8,29 +8,24 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[feature(managed_boxes)];
|
||||
trait Repeat<A> { fn get(&self) -> A; }
|
||||
|
||||
trait repeat<A> { fn get(&self) -> A; }
|
||||
|
||||
impl<A:Clone> repeat<A> for @A {
|
||||
fn get(&self) -> A { **self }
|
||||
impl<A:Clone> Repeat<A> for A {
|
||||
fn get(&self) -> A { self.clone() }
|
||||
}
|
||||
|
||||
fn repeater<A:Clone>(v: @A) -> @repeat<A> {
|
||||
// Note: owned kind is not necessary as A appears in the trait type
|
||||
@v as @repeat<A> // No
|
||||
fn repeater<A:Clone>(v: A) -> ~Repeat:<A> {
|
||||
~v as ~Repeat:<A> // No
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Error results because the type of is inferred to be
|
||||
// @repeat<&'blk int> where blk is the lifetime of the block below.
|
||||
// ~Repeat<&'blk int> where blk is the lifetime of the block below.
|
||||
|
||||
let y = { //~ ERROR lifetime of variable does not enclose its declaration
|
||||
let x: &'blk int = &3;
|
||||
repeater(@x)
|
||||
let y = {
|
||||
let tmp0 = 3;
|
||||
let tmp1 = &tmp0; //~ ERROR borrowed value does not live long enough
|
||||
repeater(tmp1)
|
||||
};
|
||||
assert!(3 == *(y.get()));
|
||||
//~^ ERROR dereference of reference outside its lifetime
|
||||
//~^^ ERROR automatically borrowed pointer is not valid at the time of borrow
|
||||
//~^^^ ERROR lifetime of return value does not outlive the function call
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ impl MyEq for int {
|
||||
fn eq(&self, other: &int) -> bool { *self == *other }
|
||||
}
|
||||
|
||||
impl MyEq for A {} //~ ERROR missing method
|
||||
impl MyEq for A {} //~ ERROR not all trait methods implemented, missing: `eq`
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
@ -8,12 +8,19 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Check that taking the address of an argument yields a lifetime
|
||||
// bounded by the current function call.
|
||||
|
||||
fn foo(a: int) {
|
||||
let _p: &'static int = &a; //~ ERROR borrowed value does not live long enough
|
||||
}
|
||||
|
||||
fn bar(a: int) {
|
||||
let _q: &'blk int = &a;
|
||||
let _q: &int = &a;
|
||||
}
|
||||
|
||||
fn zed<'a>(a: int) -> &'a int {
|
||||
&a //~ ERROR borrowed value does not live long enough
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -14,12 +14,12 @@ struct dog {
|
||||
|
||||
impl dog {
|
||||
pub fn chase_cat(&mut self) {
|
||||
let p: &'static mut uint = &mut self.cats_chased; //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements
|
||||
let p: &'static mut uint = &mut self.cats_chased; //~ ERROR cannot infer an appropriate lifetime
|
||||
*p += 1u;
|
||||
}
|
||||
|
||||
pub fn chase_cat_2(&mut self) {
|
||||
let p: &'blk mut uint = &mut self.cats_chased;
|
||||
let p: &mut uint = &mut self.cats_chased;
|
||||
*p += 1u;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ struct dog {
|
||||
impl dog {
|
||||
pub fn chase_cat(&mut self) {
|
||||
let _f = || {
|
||||
let p: &'static mut uint = &mut self.food; //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements
|
||||
let p: &'static mut uint = &mut self.food; //~ ERROR cannot infer an appropriate lifetime
|
||||
*p = 3u;
|
||||
};
|
||||
}
|
||||
|
@ -24,9 +24,9 @@ fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) {
|
||||
of::<&fn<'b>(&'b T)>());
|
||||
|
||||
subtype::<&fn<'b>(&'b T)>(
|
||||
of::<&fn<'x>(&'x T)>());
|
||||
of::<&fn(&'x T)>());
|
||||
|
||||
subtype::<&fn<'x>(&'x T)>(
|
||||
subtype::<&fn(&'x T)>(
|
||||
of::<&fn<'b>(&'b T)>()); //~ ERROR mismatched types
|
||||
|
||||
subtype::<&fn<'a,'b>(&'a T, &'b T)>(
|
||||
@ -36,9 +36,9 @@ fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) {
|
||||
of::<&fn<'a,'b>(&'a T, &'b T)>()); //~ ERROR mismatched types
|
||||
|
||||
subtype::<&fn<'a,'b>(&'a T, &'b T)>(
|
||||
of::<&fn<'x,'y>(&'x T, &'y T)>());
|
||||
of::<&fn(&'x T, &'y T)>());
|
||||
|
||||
subtype::<&fn<'x,'y>(&'x T, &'y T)>(
|
||||
subtype::<&fn(&'x T, &'y T)>(
|
||||
of::<&fn<'a,'b>(&'a T, &'b T)>()); //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ fn ordering2<'a, 'b>(x: &'a &'b uint, y: &'a uint) -> &'b uint {
|
||||
fn ordering3<'a, 'b>(x: &'a uint, y: &'b uint) -> &'a &'b uint {
|
||||
// Do not infer an ordering from the return value.
|
||||
let z: &'b uint = &*x;
|
||||
//~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
fail!();
|
||||
}
|
||||
|
||||
|
@ -14,12 +14,6 @@
|
||||
|
||||
struct Paramd<'self> { x: &'self uint }
|
||||
|
||||
fn call1<'a>(x: &'a uint) {
|
||||
let y: uint = 3;
|
||||
let z: &'a &'blk uint = &(&y);
|
||||
//~^ ERROR pointer has a longer lifetime than the data it references
|
||||
}
|
||||
|
||||
fn call2<'a, 'b>(a: &'a uint, b: &'b uint) {
|
||||
let z: Option<&'b &'a uint> = None;
|
||||
//~^ ERROR pointer has a longer lifetime than the data it references
|
||||
|
@ -0,0 +1,24 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test various ways to construct a pointer with a longer lifetime
|
||||
// than the thing it points at and ensure that they result in
|
||||
// errors. See also regions-free-region-ordering-callee.rs
|
||||
|
||||
fn call1<'a>(x: &'a uint) {
|
||||
// Test that creating a pointer like
|
||||
// &'a &'z uint requires that 'a <= 'z:
|
||||
let y: uint = 3;
|
||||
let z: &'a & uint = &(&y);
|
||||
//~^ ERROR borrowed value does not live long enough
|
||||
//~^^ ERROR borrowed value does not live long enough
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -8,8 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
static c_x: &'blk int = &22; //~ ERROR Illegal lifetime 'blk: only 'static is allowed here
|
||||
static c_y: &int = &22; //~ ERROR Illegal anonymous lifetime: only 'static is allowed here
|
||||
static c_y: &int = &22; //~ ERROR missing lifetime specifier
|
||||
static c_z: &'static int = &22;
|
||||
|
||||
fn main() {
|
||||
|
@ -8,16 +8,10 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct item_ty_yes0<'self> {
|
||||
x: &'self uint
|
||||
}
|
||||
// Test that anonymous lifetimes are not permitted in enum declarations
|
||||
|
||||
struct item_ty_yes1<'self> {
|
||||
x: &'self uint
|
||||
}
|
||||
|
||||
struct item_ty_yes2 {
|
||||
x: &'a uint //~ ERROR only 'self is allowed
|
||||
enum Foo {
|
||||
Bar(&int) //~ ERROR missing lifetime specifier
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -8,17 +8,23 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that lifetimes must be declared for use on enums.
|
||||
// See also regions-undeclared.rs
|
||||
|
||||
enum yes0<'lt> {
|
||||
// This will eventually be legal (and in fact the only way):
|
||||
X3(&'lt uint) //~ ERROR Illegal lifetime 'lt: only 'self is allowed
|
||||
X3(&'lt uint)
|
||||
}
|
||||
|
||||
enum yes1<'self> {
|
||||
X4(&'self uint)
|
||||
}
|
||||
|
||||
enum yes2 {
|
||||
X5(&'foo uint) //~ ERROR Illegal lifetime 'foo: only 'self is allowed
|
||||
enum no0 {
|
||||
X5(&'foo uint) //~ ERROR use of undeclared lifetime name `'foo`
|
||||
}
|
||||
|
||||
enum no1 {
|
||||
X6(&'self uint) //~ ERROR use of undeclared lifetime name `'self`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -8,19 +8,10 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[feature(managed_boxes)];
|
||||
// Test that anonymous lifetimes are not permitted in struct declarations
|
||||
|
||||
struct invariant<'self> {
|
||||
f: @mut &'self int
|
||||
struct Foo {
|
||||
x: &int //~ ERROR missing lifetime specifier
|
||||
}
|
||||
|
||||
fn to_same_lifetime<'r>(bi: invariant<'r>) {
|
||||
let bj: invariant<'r> = bi;
|
||||
}
|
||||
|
||||
fn to_longer_lifetime<'r>(bi: invariant<'r>) -> invariant<'static> {
|
||||
bi //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
fn main() {}
|
@ -8,16 +8,18 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct yes0<'self> {
|
||||
x: &uint, //~ ERROR Illegal anonymous lifetime: anonymous lifetimes are not permitted here
|
||||
}
|
||||
|
||||
struct yes1<'self> {
|
||||
x: &'self uint,
|
||||
}
|
||||
|
||||
struct yes2<'self> {
|
||||
x: &'foo uint, //~ ERROR Illegal lifetime 'foo: only 'self is allowed
|
||||
struct yes2<'a> {
|
||||
x: &'a uint,
|
||||
}
|
||||
|
||||
struct StructDecl {
|
||||
a: &'a int, //~ ERROR use of undeclared lifetime name `'a`
|
||||
b: &'self int, //~ ERROR use of undeclared lifetime name `'self`
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,28 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct contravariant<'self> {
|
||||
f: &'self int
|
||||
}
|
||||
|
||||
fn to_same_lifetime<'r>(bi: contravariant<'r>) {
|
||||
let bj: contravariant<'r> = bi;
|
||||
}
|
||||
|
||||
fn to_shorter_lifetime<'r>(bi: contravariant<'r>) {
|
||||
let bj: contravariant<'blk> = bi;
|
||||
}
|
||||
|
||||
fn to_longer_lifetime<'r>(bi: contravariant<'r>) -> contravariant<'static> {
|
||||
bi //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Contravariant with respect to a region:
|
||||
//
|
||||
// You can upcast to a *smaller region* but not a larger one. This is
|
||||
// the normal case.
|
||||
|
||||
struct contravariant<'self> {
|
||||
f: &'static fn() -> &'self int
|
||||
}
|
||||
|
||||
fn to_same_lifetime<'r>(bi: contravariant<'r>) {
|
||||
let bj: contravariant<'r> = bi;
|
||||
}
|
||||
|
||||
fn to_shorter_lifetime<'r>(bi: contravariant<'r>) {
|
||||
let bj: contravariant<'blk> = bi;
|
||||
}
|
||||
|
||||
fn to_longer_lifetime<'r>(bi: contravariant<'r>) -> contravariant<'static> {
|
||||
bi //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Covariant with respect to a region:
|
||||
//
|
||||
// You can upcast to a *larger region* but not a smaller one.
|
||||
|
||||
struct covariant<'self> {
|
||||
f: &'static fn(x: &'self int) -> int
|
||||
}
|
||||
|
||||
fn to_same_lifetime<'r>(bi: covariant<'r>) {
|
||||
let bj: covariant<'r> = bi;
|
||||
}
|
||||
|
||||
fn to_shorter_lifetime<'r>(bi: covariant<'r>) {
|
||||
let bj: covariant<'blk> = bi; //~ ERROR mismatched types
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
}
|
||||
|
||||
fn to_longer_lifetime<'r>(bi: covariant<'r>) -> covariant<'static> {
|
||||
bi
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Invariance with respect to a region:
|
||||
//
|
||||
// You cannot convert between regions.
|
||||
|
||||
struct invariant<'self> {
|
||||
f: &'self fn(x: &'self int) -> &'self int
|
||||
}
|
||||
|
||||
fn to_same_lifetime<'r>(bi: invariant<'r>) {
|
||||
let bj: invariant<'r> = bi;
|
||||
}
|
||||
|
||||
fn to_shorter_lifetime<'r>(bi: invariant<'r>) {
|
||||
let bj: invariant<'blk> = bi; //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn to_longer_lifetime<'r>(bi: invariant<'r>) -> invariant<'static> {
|
||||
bi //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
// contains region pointers
|
||||
struct foo(~fn(x: &int));
|
||||
|
||||
fn take_foo(x: foo<'static>) {} //~ ERROR no region bound is allowed on `foo`
|
||||
fn take_foo(x: foo<'static>) {} //~ ERROR wrong number of lifetime parameters
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -8,19 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[feature(managed_boxes)];
|
||||
|
||||
struct invariant<'self> {
|
||||
f: @mut [&'self int]
|
||||
struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice
|
||||
x: &'a int
|
||||
}
|
||||
|
||||
fn to_same_lifetime<'r>(bi: invariant<'r>) {
|
||||
let bj: invariant<'r> = bi;
|
||||
}
|
||||
|
||||
fn to_longer_lifetime<'r>(bi: invariant<'r>) -> invariant<'static> {
|
||||
bi //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
fn main() {}
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -8,18 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn foo(cond: bool) {
|
||||
let x = 5;
|
||||
let mut y: &'blk int = &x;
|
||||
|
||||
let mut z: &'blk int;
|
||||
if cond {
|
||||
z = &x; //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements
|
||||
} else {
|
||||
let w: &'blk int = &x;
|
||||
z = w;
|
||||
}
|
||||
struct Foo<'static> { //~ ERROR illegal lifetime parameter name: `static`
|
||||
x: &'static int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
fn main() {}
|
60
src/test/compile-fail/regions-name-undeclared.rs
Normal file
60
src/test/compile-fail/regions-name-undeclared.rs
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Check that lifetime resolver enforces the lifetime name scoping
|
||||
// rules correctly in various scenarios.
|
||||
|
||||
struct Foo<'a> {
|
||||
x: &'a int
|
||||
}
|
||||
|
||||
impl<'a> Foo<'a> {
|
||||
// &'a is inherited:
|
||||
fn m1(&self, arg: &'a int) { }
|
||||
fn m2(&'a self) { }
|
||||
fn m3(&self, arg: Foo<'a>) { }
|
||||
|
||||
// &'b is not:
|
||||
fn m4(&self, arg: &'b int) { } //~ ERROR undeclared lifetime
|
||||
fn m5(&'b self) { } //~ ERROR undeclared lifetime
|
||||
fn m6(&self, arg: Foo<'b>) { } //~ ERROR undeclared lifetime
|
||||
}
|
||||
|
||||
fn bar<'a>(x: &'a int) {
|
||||
// &'a is visible to code:
|
||||
let y: &'a int = x;
|
||||
|
||||
// &'a is not visible to *items*:
|
||||
type X = Option<&'a int>; //~ ERROR undeclared lifetime
|
||||
enum E {
|
||||
E1(&'a int) //~ ERROR undeclared lifetime
|
||||
}
|
||||
struct S {
|
||||
f: &'a int //~ ERROR undeclared lifetime
|
||||
}
|
||||
fn f(a: &'a int) { } //~ ERROR undeclared lifetime
|
||||
|
||||
// &'a CAN be declared on functions and used then:
|
||||
fn g<'a>(a: &'a int) { } // OK
|
||||
fn h(a: &fn<'a>(&'a int)) { } // OK
|
||||
}
|
||||
|
||||
// Test nesting of lifetimes in fn type declarations
|
||||
fn fn_types(a: &'a int, //~ ERROR undeclared lifetime
|
||||
b: &fn<'a>(a: &'a int,
|
||||
b: &'b int, //~ ERROR undeclared lifetime
|
||||
c: &fn<'b>(a: &'a int,
|
||||
b: &'b int),
|
||||
d: &'b int), //~ ERROR undeclared lifetime
|
||||
c: &'a int) //~ ERROR undeclared lifetime
|
||||
{
|
||||
}
|
||||
|
||||
pub fn main() {}
|
@ -12,7 +12,7 @@
|
||||
// some point regions-ret-borrowed reported an error but this file did
|
||||
// not, due to special hardcoding around the anonymous region.
|
||||
|
||||
fn with<'a, R>(f: &fn(x: &'a int) -> R) -> R {
|
||||
fn with<R>(f: &fn<'a>(x: &'a int) -> R) -> R {
|
||||
f(&3)
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user