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:
bors 2013-11-09 08:36:09 -08:00
commit 8379890c05
117 changed files with 5023 additions and 3603 deletions

View File

@ -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

View File

@ -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,

View File

@ -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(

View File

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

View File

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

View File

@ -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;

View File

@ -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,

View File

@ -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
}
}

View File

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

View File

@ -121,17 +121,6 @@ pub fn encode_def_id(ebml_w: &mut writer::Encoder, id: DefId) {
ebml_w.wr_tagged_str(tag_def_id, def_to_str(id));
}
fn encode_region_param(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
it: @ast::item) {
let opt_rp = ecx.tcx.region_paramd_items.find(&it.id);
for rp in opt_rp.iter() {
ebml_w.start_tag(tag_region_param);
rp.encode(ebml_w);
ebml_w.end_tag();
}
}
#[deriving(Clone)]
struct entry<T> {
val: T,
@ -205,11 +194,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,

View File

@ -48,7 +48,10 @@ pub enum DefIdSource {
TypeWithId,
// Identifies a type parameter (`fn foo<X>() { ... }`).
TypeParameter
TypeParameter,
// Identifies a region parameter (`fn foo<'X>() { ... }`).
RegionParameter,
}
type conv_did<'self> =
&'self fn(source: DefIdSource, ast::DefId) -> ast::DefId;
@ -143,7 +146,7 @@ fn parse_path(st: &mut PState) -> @ast::Path {
segments: idents.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
lifetime: None,
lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
}).collect()
@ -165,7 +168,7 @@ fn parse_sigil(st: &mut PState) -> ast::Sigil {
}
}
fn parse_vstore(st: &mut PState) -> ty::vstore {
fn parse_vstore(st: &mut PState, conv: conv_did) -> ty::vstore {
assert_eq!(next(st), '/');
let c = peek(st);
@ -178,22 +181,22 @@ fn parse_vstore(st: &mut PState) -> ty::vstore {
match next(st) {
'~' => ty::vstore_uniq,
'@' => ty::vstore_box,
'&' => ty::vstore_slice(parse_region(st)),
'&' => ty::vstore_slice(parse_region(st, conv)),
c => st.tcx.sess.bug(format!("parse_vstore(): bad input '{}'", c))
}
}
fn parse_trait_store(st: &mut PState) -> ty::TraitStore {
fn parse_trait_store(st: &mut PState, conv: conv_did) -> ty::TraitStore {
match next(st) {
'~' => ty::UniqTraitStore,
'@' => ty::BoxTraitStore,
'&' => ty::RegionTraitStore(parse_region(st)),
'&' => ty::RegionTraitStore(parse_region(st, conv)),
c => st.tcx.sess.bug(format!("parse_trait_store(): bad input '{}'", c))
}
}
fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs {
let regions = parse_region_substs(st);
let regions = parse_region_substs(st, |x,y| conv(x,y));
let self_ty = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)) );
@ -209,13 +212,13 @@ fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs {
};
}
fn parse_region_substs(st: &mut PState) -> ty::RegionSubsts {
fn parse_region_substs(st: &mut PState, conv: conv_did) -> ty::RegionSubsts {
match next(st) {
'e' => ty::ErasedRegions,
'n' => {
let mut regions = opt_vec::Empty;
while peek(st) != '.' {
let r = parse_region(st);
let r = parse_region(st, |x,y| conv(x,y));
regions.push(r);
}
assert_eq!(next(st), '.');
@ -225,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

View File

@ -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);
}

View File

@ -15,7 +15,8 @@ use driver::session::Session;
use e = metadata::encoder;
use metadata::decoder;
use metadata::tydecode;
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter};
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
RegionParameter};
use metadata::tyencode;
use middle::freevars::freevar_entry;
use middle::typeck::{method_origin, method_map_entry};
@ -234,6 +235,12 @@ impl tr for ast::DefId {
}
}
impl tr for Option<ast::DefId> {
fn tr(&self, xcx: @ExtendedDecodeContext) -> Option<ast::DefId> {
self.map(|d| xcx.tr_def_id(d))
}
}
impl tr for Span {
fn tr(&self, xcx: @ExtendedDecodeContext) -> Span {
xcx.tr_span(*self)
@ -469,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);

View File

@ -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

View File

@ -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 {

View File

@ -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
}
}

View File

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

View File

@ -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;
}

View File

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

View File

@ -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;
}

View File

@ -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

View File

@ -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}) => {

View File

@ -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);

View File

@ -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}
}

View File

@ -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);

View File

@ -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);

View File

@ -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());

View File

@ -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.

View File

@ -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)
}
}
}

View 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)
}
}

View File

@ -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>.

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -10,155 +10,41 @@
// #[warn(deprecated_mode)];
use middle::ty;
use middle::typeck::isr_alist;
use util::common::indenter;
use util::ppaux::region_to_str;
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
use std::hashmap::HashMap;
use util::ppaux::Repr;
use util::ppaux;
use extra::list::Cons;
// Helper functions related to manipulating region types.
pub fn replace_bound_regions_in_fn_sig(
tcx: ty::ctxt,
isr: isr_alist,
opt_self_ty: Option<ty::t>,
fn_sig: &ty::FnSig,
mapf: &fn(ty::bound_region) -> ty::Region)
-> (isr_alist, Option<ty::t>, ty::FnSig)
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);
}
_ => {}

View File

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

View File

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

View File

@ -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)) => {

View File

@ -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");
}
}
}
}

View File

@ -20,15 +20,13 @@ use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::{TypeTrace, Subtype};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::isr_alist;
use syntax::ast::{Many, Once, extern_fn, impure_fn, MutImmutable, MutMutable};
use syntax::ast::{unsafe_fn};
use syntax::ast::{unsafe_fn, NodeId};
use syntax::ast::{Onceness, purity};
use std::hashmap::HashMap;
use util::common::{indenter};
use util::ppaux::mt_to_str;
use extra::list;
pub struct Glb(CombineFields); // "greatest lower bound" (common subtype)
impl Combine for Glb {
@ -132,14 +130,14 @@ impl Combine for Glb {
let snapshot = self.infcx.region_vars.start_snapshot();
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_isr) =
let (a_with_fresh, a_map) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.trace, a);
let a_vars = var_ids(self, a_isr);
let (b_with_fresh, b_isr) =
let a_vars = var_ids(self, &a_map);
let (b_with_fresh, b_map) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.trace, b);
let b_vars = var_ids(self, b_isr);
let b_vars = var_ids(self, &b_map);
// Collect constraints.
let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
@ -152,20 +150,23 @@ impl Combine for Glb {
fold_regions_in_sig(
self.infcx.tcx,
&sig0,
|r, _in_fn| generalize_region(self, snapshot,
new_vars, a_isr, a_vars, b_vars,
r));
|r| generalize_region(self, snapshot,
new_vars, sig0.binder_id,
&a_map, a_vars, b_vars,
r));
debug!("sig1 = {}", sig1.inf_str(self.infcx));
return Ok(sig1);
fn generalize_region(this: &Glb,
snapshot: uint,
new_vars: &[RegionVid],
a_isr: isr_alist,
new_binder_id: NodeId,
a_map: &HashMap<ty::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)
}
}
}

View File

@ -35,7 +35,6 @@
use middle::ty::{RegionVid, TyVar, Vid};
use middle::ty;
use middle::typeck::isr_alist;
use middle::typeck::infer::*;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::glb::Glb;
@ -43,10 +42,9 @@ use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::unify::*;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr;
use std::hashmap::HashMap;
use util::common::indenter;
use extra::list;
pub trait LatticeValue {
fn sub(cf: &CombineFields, a: &Self, b: &Self) -> ures;
fn lub(cf: &CombineFields, a: &Self, b: &Self) -> cres<Self>;
@ -366,14 +364,13 @@ impl TyLatticeDir for Glb {
}
}
pub fn super_lattice_tys<L:LatticeDir + TyLatticeDir + Combine>(
this: &L,
a: ty::t,
b: ty::t) -> cres<ty::t> {
pub fn super_lattice_tys<L:LatticeDir+TyLatticeDir+Combine>(this: &L,
a: ty::t,
b: ty::t)
-> cres<ty::t> {
debug!("{}.lattice_tys({}, {})", this.tag(),
a.inf_str(this.infcx()),
b.inf_str(this.infcx()));
let _r = indenter();
if a == b {
return Ok(a);
@ -524,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
}
}

View File

@ -20,13 +20,11 @@ use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::infer::{TypeTrace, Subtype};
use middle::typeck::isr_alist;
use util::ppaux::mt_to_str;
use extra::list;
use syntax::ast::{Many, Once, extern_fn, impure_fn};
use std::hashmap::HashMap;
use syntax::ast::{Many, Once, extern_fn, impure_fn, NodeId};
use syntax::ast::{unsafe_fn};
use syntax::ast::{Onceness, purity};
use util::ppaux::mt_to_str;
pub struct Lub(CombineFields); // least-upper-bound: common supertype
@ -125,7 +123,7 @@ impl Combine for Lub {
let snapshot = self.infcx.region_vars.start_snapshot();
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_isr) =
let (a_with_fresh, a_map) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.trace, a);
let (b_with_fresh, _) =
@ -143,17 +141,20 @@ impl Combine for Lub {
fold_regions_in_sig(
self.infcx.tcx,
&sig0,
|r, _in_fn| generalize_region(self, snapshot, new_vars,
a_isr, r));
|r| generalize_region(self, snapshot, new_vars,
sig0.binder_id, &a_map, r));
return Ok(sig1);
fn generalize_region(this: &Lub,
snapshot: uint,
new_vars: &[RegionVid],
a_isr: isr_alist,
r0: ty::Region) -> ty::Region {
new_scope: NodeId,
a_map: &HashMap<ty::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))
}
}

View File

@ -20,8 +20,11 @@ pub use middle::typeck::infer::resolve::{resolve_ivar, resolve_all};
pub use middle::typeck::infer::resolve::{resolve_nested_tvar};
pub use middle::typeck::infer::resolve::{resolve_rvar};
use extra::smallintmap::SmallIntMap;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid};
use middle::ty;
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig};
use middle::typeck::infer::coercion::Coerce;
use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys};
@ -32,19 +35,16 @@ use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::unify::{ValsAndBindings, Root};
use middle::typeck::infer::error_reporting::ErrorReporting;
use middle::typeck::isr_alist;
use util::common::indent;
use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str, Repr,
UserString};
use std::hashmap::HashMap;
use std::result;
use std::vec;
use extra::list::Nil;
use extra::smallintmap::SmallIntMap;
use syntax::ast::{MutImmutable, MutMutable};
use syntax::ast;
use syntax::codemap;
use syntax::codemap::Span;
use util::common::indent;
use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str, Repr,
UserString};
pub mod doc;
pub mod macros;
@ -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"),
}
}
}

View File

@ -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))
}
}

View File

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

View File

@ -24,8 +24,6 @@ use middle::typeck::infer::{TypeTrace, Subtype};
use util::common::{indenter};
use util::ppaux::bound_region_to_str;
use extra::list::Nil;
use extra::list;
use syntax::ast::{Onceness, purity};
pub struct Sub(CombineFields); // "subtype", "subregion" etc
@ -168,9 +166,8 @@ impl Combine for Sub {
// Second, we instantiate each bound region in the supertype with a
// fresh concrete region.
let (skol_isr, _, b_sig) = {
do replace_bound_regions_in_fn_sig(self.infcx.tcx, @Nil,
None, b) |br| {
let (skol_map, _, b_sig) = {
do replace_bound_regions_in_fn_sig(self.infcx.tcx, None, b) |br| {
let skol = self.infcx.region_vars.new_skolemized(br);
debug!("Bound region {} skolemized to {:?}",
bound_region_to_str(self.infcx.tcx, "", false, br),
@ -189,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);
}
}

View File

@ -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())) }

View File

@ -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));

View File

@ -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()
}

File diff suppressed because it is too large Load Diff

View File

@ -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))
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1566,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, "=");

View File

@ -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())
}

View File

@ -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() {}

View File

@ -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 {

View File

@ -13,6 +13,6 @@
use std::local_data;
local_data_key!(key: @&int)
//~^ ERROR only 'static is allowed
//~^ ERROR missing lifetime specifier
fn main() {}

View File

@ -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 }
}

View File

@ -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;

View File

@ -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() {}

View File

@ -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
}

View File

@ -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() {
}

View File

@ -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() {

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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
}

View File

@ -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!();
}

View File

@ -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

View File

@ -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() {}

View File

@ -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() {

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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() {
}

View File

@ -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() {
}

View File

@ -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() {
}

View File

@ -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() {
}

View File

@ -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() {
}

View File

@ -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() {}

View File

@ -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() {}

View 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() {}

View File

@ -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