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,
},
],
global: false,
segments: ids.move_iter().map(|identifier| ast::PathSegment {
identifier: identifier,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}).collect()
}
global: true,
segments: ids.move_iter().map(|identifier| ast::PathSegment {
identifier: identifier,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}).collect()
}
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;
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,
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;
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
}
}
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;
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(
@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
+ };
}
}
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.
};
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)
}
-> 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| {
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);
name,
ty::Generics {
type_param_defs: type_param_defs,
- region_param: None
+ region_param_defs: rp_defs,
},
transformed_self_ty,
fty,
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,
}
}
+fn encode_region_param_defs(ebml_w: &mut writer::Encoder,
+ ecx: &EncodeContext,
+ params: @[ty::RegionParameterDef]) {
+ for param in params.iter() {
+ ebml_w.start_tag(tag_region_param_def);
+
+ ebml_w.start_tag(tag_region_param_def_ident);
+ encode_name(ecx, ebml_w, param.ident);
+ ebml_w.end_tag();
+
+ ebml_w.wr_tagged_str(tag_region_param_def_def_id,
+ def_to_str(param.def_id));
+
+ ebml_w.end_tag();
+ }
+}
+
fn encode_bounds_and_type(ebml_w: &mut writer::Encoder,
ecx: &EncodeContext,
tpt: &ty::ty_param_bounds_and_ty) {
encode_ty_type_param_defs(ebml_w, ecx, tpt.generics.type_param_defs,
tag_items_data_item_ty_param_bounds);
+ encode_region_param_defs(ebml_w, ecx, tpt.generics.region_param_defs);
encode_type(ecx, ebml_w, tpt.ty);
}
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();
}
}
(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);
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
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);
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'I');
- encode_region_param(ecx, ebml_w, item);
let trait_def = ty::lookup_trait_def(tcx, def_id);
encode_ty_type_param_defs(ebml_w, ecx,
trait_def.generics.type_param_defs,
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;
segments: idents.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
}).collect()
}
}
-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);
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)) );
};
}
-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), '.');
}
}
-fn parse_bound_region(st: &mut PState) -> ty::bound_region {
+fn parse_bound_region(st: &mut PState, conv: conv_did) -> ty::bound_region {
match next(st) {
- 's' => ty::br_self,
- 'a' => {
- let id = parse_uint(st);
- assert_eq!(next(st), '|');
- ty::br_anon(id)
- }
- '[' => ty::br_named(st.tcx.sess.ident_of(parse_str(st, ']'))),
- 'c' => {
- let id = parse_uint(st) as int;
- assert_eq!(next(st), '|');
- ty::br_cap_avoid(id, @parse_bound_region(st))
- },
- _ => fail!("parse_bound_region: bad input")
+ 'a' => {
+ let id = parse_uint(st);
+ assert_eq!(next(st), '|');
+ ty::br_anon(id)
+ }
+ '[' => {
+ let def = parse_def(st, RegionParameter, |x,y| conv(x,y));
+ let ident = st.tcx.sess.ident_of(parse_str(st, ']'));
+ ty::br_named(def, ident)
+ }
+ 'f' => {
+ let id = parse_uint(st);
+ assert_eq!(next(st), '|');
+ ty::br_fresh(id)
+ }
+ _ => fail!("parse_bound_region: bad input")
}
}
-fn parse_region(st: &mut PState) -> ty::Region {
+fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region {
match next(st) {
'b' => {
- ty::re_bound(parse_bound_region(st))
+ assert_eq!(next(st), '[');
+ let id = parse_uint(st) as int;
+ assert_eq!(next(st), '|');
+ let br = parse_bound_region(st, |x,y| conv(x,y));
+ assert_eq!(next(st), ']');
+ ty::re_fn_bound(id, br)
+ }
+ 'B' => {
+ assert_eq!(next(st), '[');
+ let node_id = parse_uint(st) as int;
+ assert_eq!(next(st), '|');
+ let index = parse_uint(st);
+ assert_eq!(next(st), '|');
+ let nm = st.tcx.sess.ident_of(parse_str(st, ']'));
+ ty::re_type_bound(node_id, index, nm)
}
'f' => {
assert_eq!(next(st), '[');
let id = parse_uint(st) as int;
assert_eq!(next(st), '|');
- let br = parse_bound_region(st);
+ let br = parse_bound_region(st, |x,y| conv(x,y));
assert_eq!(next(st), ']');
ty::re_free(ty::FreeRegion {scope_id: id,
bound_region: br})
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);
}
}
'U' => return ty::mk_unboxed_vec(st.tcx, parse_mt(st, conv)),
'V' => {
- let mt = parse_mt(st, conv);
- let v = parse_vstore(st);
+ let mt = parse_mt(st, |x,y| conv(x,y));
+ let v = parse_vstore(st, |x,y| conv(x,y));
return ty::mk_evec(st.tcx, mt, v);
}
'v' => {
- let v = parse_vstore(st);
+ let v = parse_vstore(st, |x,y| conv(x,y));
return ty::mk_estr(st.tcx, v);
}
'T' => {
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 {
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,
fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig {
assert_eq!(next(st), '[');
+ let id = parse_uint(st) as int;
+ assert_eq!(next(st), '|');
let mut inputs = ~[];
while peek(st) != ']' {
inputs.push(parse_ty(st, |x,y| conv(x,y)));
}
st.pos += 1u; // eat the ']'
- let variadic = if peek(st) == 'A' {
- st.pos += 1; // eat the 'A'
- true
- } else { false };
- let ret_ty = parse_ty(st, conv);
- ty::FnSig {
- bound_lifetime_names: opt_vec::Empty, // FIXME(#4846)
- inputs: inputs,
- output: ret_ty,
- variadic: variadic
- }
+ let variadic = match next(st) {
+ 'V' => true,
+ 'N' => false,
+ };
+ let ret_ty = parse_ty(st, |x,y| conv(x,y));
+ ty::FnSig {binder_id: id,
+ inputs: inputs,
+ output: ret_ty,
+ variadic: variadic}
}
// Rust metadata parsing
fn enc_region(w: @mut MemWriter, cx: @ctxt, r: ty::Region) {
match r {
- ty::re_bound(br) => {
- mywrite!(w, "b");
+ ty::re_fn_bound(id, br) => {
+ mywrite!(w, "b[{}|", id);
enc_bound_region(w, cx, br);
+ mywrite!(w, "]");
+ }
+ ty::re_type_bound(node_id, index, ident) => {
+ mywrite!(w, "B[{}|{}|{}]",
+ node_id,
+ index,
+ cx.tcx.sess.str_of(ident));
}
ty::re_free(ref fr) => {
mywrite!(w, "f[{}|", fr.scope_id);
enc_bound_region(w, cx, fr.bound_region);
mywrite!(w, "]");
}
- ty::re_scope(nid) => mywrite!(w, "s{}|", nid),
- ty::re_static => mywrite!(w, "t"),
- ty::re_empty => mywrite!(w, "e"),
+ ty::re_scope(nid) => {
+ mywrite!(w, "s{}|", nid);
+ }
+ ty::re_static => {
+ mywrite!(w, "t");
+ }
+ ty::re_empty => {
+ mywrite!(w, "e");
+ }
ty::re_infer(_) => {
// these should not crop up after typeck
cx.diag.handler().bug("Cannot encode region variables");
fn enc_bound_region(w: @mut MemWriter, cx: @ctxt, br: ty::bound_region) {
match br {
- ty::br_self => mywrite!(w, "s"),
- ty::br_anon(idx) => mywrite!(w, "a{}|", idx),
- ty::br_named(s) => mywrite!(w, "[{}]", cx.tcx.sess.str_of(s)),
- ty::br_cap_avoid(id, br) => {
- mywrite!(w, "c{}|", id);
- enc_bound_region(w, cx, *br);
- }
- ty::br_fresh(id) => mywrite!(w, "{}", id),
+ ty::br_anon(idx) => {
+ mywrite!(w, "a{}|", idx);
+ }
+ ty::br_named(d, s) => {
+ mywrite!(w, "[{}|{}]",
+ (cx.ds)(d),
+ cx.tcx.sess.str_of(s));
+ }
+ ty::br_fresh(id) => {
+ mywrite!(w, "f{}|", id);
+ }
}
}
}
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);
}
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};
}
}
+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)
impl tr for ty::Region {
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::Region {
match *self {
- ty::re_bound(br) => ty::re_bound(br.tr(xcx)),
+ ty::re_fn_bound(id, br) => ty::re_fn_bound(xcx.tr_id(id),
+ br.tr(xcx)),
+ ty::re_type_bound(id, index, ident) => ty::re_type_bound(xcx.tr_id(id),
+ index,
+ ident),
ty::re_scope(id) => ty::re_scope(xcx.tr_id(id)),
ty::re_empty | ty::re_static | ty::re_infer(*) => *self,
ty::re_free(ref fr) => {
impl tr for ty::bound_region {
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::bound_region {
match *self {
- ty::br_anon(_) | ty::br_named(_) | ty::br_self |
+ ty::br_anon(_) |
ty::br_fresh(_) => *self,
- ty::br_cap_avoid(id, br) => ty::br_cap_avoid(xcx.tr_id(id),
- @br.tr(xcx))
+ ty::br_named(id, ident) => ty::br_named(xcx.tr_def_id(id),
+ ident),
}
}
}
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);
}
}
}
// 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,
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
};
@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)
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
* 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);
}
ty::re_empty |
- ty::re_bound(*) |
+ ty::re_fn_bound(*) |
+ ty::re_type_bound(*) |
ty::re_infer(*) => {
self.tcx().sess.span_bug(
cmt.span,
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
}
_ => {}
}
- true
});
fn is_re_scope(r: ty::Region) -> bool {
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];
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 \
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Generics {
ty::Generics {
type_param_defs: self.type_param_defs.subst(tcx, substs),
- region_param: self.region_param
+ region_param_defs: self.region_param_defs.subst(tcx, substs),
}
}
}
+impl Subst for ty::RegionParameterDef {
+ fn subst(&self, _: ty::ctxt, _: &ty::substs) -> ty::RegionParameterDef {
+ *self
+ }
+}
+
impl Subst for ty::Region {
- fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Region {
- // Note: This routine only handles the self region, because it
- // is only concerned with substitutions of regions that appear
- // in types. Region substitution of the bound regions that
- // appear in a function signature is done using the
- // specialized routine
+ fn subst(&self, _tcx: ty::ctxt, substs: &ty::substs) -> ty::Region {
+ // Note: This routine only handles regions that are bound on
+ // type declarationss and other outer declarations, not those
+ // bound in *fn types*. Region substitution of the bound
+ // regions that appear in a function signature is done using
+ // the specialized routine
// `middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig()`.
- // As we transition to the new region syntax this distinction
- // will most likely disappear.
match self {
- &ty::re_bound(ty::br_self) => {
+ &ty::re_type_bound(_, i, _) => {
match substs.regions {
ty::ErasedRegions => ty::re_static,
- ty::NonerasedRegions(ref regions) => {
- if regions.len() != 1 {
- tcx.sess.bug(
- format!("ty::Region\\#subst(): \
- Reference to self region when \
- given substs with no self region: {}",
- substs.repr(tcx)));
- }
- *regions.get(0)
- }
+ ty::NonerasedRegions(ref regions) => *regions.get(i),
}
}
_ => *self
* 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
/// Representation of regions:
#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
pub enum Region {
- /// Bound regions are found (primarily) in function types. They indicate
- /// region parameters that have yet to be replaced with actual regions
- /// (analogous to type parameters, except that due to the monomorphic
- /// nature of our type system, bound type parameters are always replaced
- /// with fresh type variables whenever an item is referenced, so type
- /// parameters only appear "free" in types. Regions in contrast can
- /// appear free or bound.). When a function is called, all bound regions
- /// tied to that function's node-id are replaced with fresh region
- /// variables whose value is then inferred.
- re_bound(bound_region),
+ // Region bound in a type declaration (type/enum/struct/trait),
+ // which will be substituted when an instance of the type is accessed
+ re_type_bound(/* param id */ ast::NodeId, /*index*/ uint, ast::Ident),
+
+ // Region bound in a fn scope, which will be substituted when the
+ // fn is called.
+ re_fn_bound(/* binder_id */ ast::NodeId, bound_region),
/// When checking a function body, the types of all arguments and so forth
/// that refer to bound region parameters are modified to refer to free
impl Region {
pub fn is_bound(&self) -> bool {
match self {
- &re_bound(*) => true,
+ &ty::re_type_bound(*) => true,
+ &ty::re_fn_bound(*) => true,
_ => false
}
}
}
-#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
+#[deriving(Clone, Eq, TotalOrd, TotalEq, IterBytes, Encodable, Decodable, ToStr)]
pub struct FreeRegion {
scope_id: NodeId,
bound_region: bound_region
}
-#[deriving(Clone, Eq, IterBytes, Encodable, Decodable, ToStr)]
+#[deriving(Clone, Eq, TotalEq, TotalOrd, IterBytes, Encodable, Decodable, ToStr)]
pub enum bound_region {
- /// The self region for structs, impls (&T in a type defn or &'self T)
- br_self,
-
/// An anonymous region parameter for a given fn (&T)
br_anon(uint),
/// Named region parameters for functions (a in &'a T)
- br_named(ast::Ident),
+ ///
+ /// The def-id is needed to distinguish free regions in
+ /// the event of shadowing.
+ br_named(ast::DefId, ast::Ident),
/// Fresh bound identifiers created during GLB computations.
br_fresh(uint),
-
- /**
- * Handles capture-avoiding substitution in a rather subtle case. If you
- * have a closure whose argument types are being inferred based on the
- * expected type, and the expected type includes bound regions, then we
- * will wrap those bound regions in a br_cap_avoid() with the id of the
- * fn expression. This ensures that the names are not "captured" by the
- * enclosing scope, which may define the same names. For an example of
- * where this comes up, see src/test/compile-fail/regions-ret-borrowed.rs
- * and regions-ret-borrowed-1.rs. */
- br_cap_avoid(ast::NodeId, @bound_region),
}
/**
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 {
}
}
+/// 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
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
hash.result_u64()
}
+
+pub fn construct_parameter_environment(
+ tcx: ctxt,
+ self_bound: Option<@TraitRef>,
+ item_type_params: &[TypeParameterDef],
+ method_type_params: &[TypeParameterDef],
+ item_region_params: &[RegionParameterDef],
+ free_id: ast::NodeId)
+ -> ParameterEnvironment
+{
+ /*! See `ParameterEnvironment` struct def'n for details */
+
+ //
+ // Construct the free substs.
+ //
+
+ // map Self => Self
+ let self_ty = self_bound.map(|t| ty::mk_self(tcx, t.def_id));
+
+ // map A => A
+ let num_item_type_params = item_type_params.len();
+ let num_method_type_params = method_type_params.len();
+ let num_type_params = num_item_type_params + num_method_type_params;
+ let type_params = vec::from_fn(num_type_params, |i| {
+ let def_id = if i < num_item_type_params {
+ item_type_params[i].def_id
+ } else {
+ method_type_params[i - num_item_type_params].def_id
+ };
+
+ ty::mk_param(tcx, i, def_id)
+ });
+
+ // map bound 'a => free 'a
+ let region_params = item_region_params.iter().
+ map(|r| ty::re_free(ty::FreeRegion {
+ scope_id: free_id,
+ bound_region: ty::br_named(r.def_id, r.ident)})).
+ collect();
+
+ let free_substs = substs {
+ self_ty: self_ty,
+ tps: type_params,
+ regions: ty::NonerasedRegions(region_params)
+ };
+
+ //
+ // Compute the bounds on Self and the type parameters.
+ //
+
+ let self_bound_substd = self_bound.map(|b| b.subst(tcx, &free_substs));
+ let type_param_bounds_substd = vec::from_fn(num_type_params, |i| {
+ if i < num_item_type_params {
+ (*item_type_params[i].bounds).subst(tcx, &free_substs)
+ } else {
+ let j = i - num_item_type_params;
+ (*method_type_params[j].bounds).subst(tcx, &free_substs)
+ }
+ });
+
+ ty::ParameterEnvironment {
+ free_substs: free_substs,
+ self_param_bound: self_bound_substd,
+ type_param_bounds: type_param_bounds_substd,
+ }
+}
+
+impl substs {
+ pub fn empty() -> substs {
+ substs {
+ self_ty: None,
+ tps: ~[],
+ regions: NonerasedRegions(opt_vec::Empty)
+ }
+ }
+}
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`.
// If the type is parameterized by the this region, then replace this
// region with the current anon region binding (in other words,
// whatever & would get replaced with).
- let regions = match (&decl_generics.region_param,
- &path.segments.last().lifetime) {
- (&None, &None) => {
- opt_vec::Empty
- }
- (&None, &Some(_)) => {
+ let expected_num_region_params = decl_generics.region_param_defs.len();
+ let supplied_num_region_params = path.segments.last().lifetimes.len();
+ let regions = if expected_num_region_params == supplied_num_region_params {
+ path.segments.last().lifetimes.map(
+ |l| ast_region_to_region(this.tcx(), l))
+ } else {
+ let anon_regions =
+ rscope.anon_regions(path.span, expected_num_region_params);
+
+ if supplied_num_region_params != 0 || anon_regions.is_none() {
tcx.sess.span_err(
path.span,
- format!("no region bound is allowed on `{}`, \
- which is not declared as containing region pointers",
- ty::item_path_str(tcx, def_id)));
- opt_vec::Empty
- }
- (&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)
+ format!("wrong number of lifetime parameters: \
+ expected {} but found {}",
+ expected_num_region_params,
+ supplied_num_region_params));
}
- (&Some(_), &Some(_)) => {
- opt_vec::with(
- ast_region_to_region(this,
- rscope,
- path.span,
- &path.segments.last().lifetime))
+
+ match anon_regions {
+ Some(v) => opt_vec::from(v),
+ None => opt_vec::from(vec::from_fn(expected_num_region_params,
+ |_| ty::re_static)) // hokey
}
};
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 }
}
ast_path_substs(
this,
rscope,
- trait_def.trait_ref.def_id,
&trait_def.generics,
self_ty,
path);
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) => {
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) => {
}
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");
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 {
});
let fn_decl = ty_of_closure(this,
rscope,
+ ast_ty.id,
f.sigil,
f.purity,
f.onceness,
&f.region,
&f.decl,
None,
- &f.lifetimes,
ast_ty.span);
ty::mk_closure(tcx, fn_decl)
}
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)
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
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>(
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,
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
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}
}
}
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;
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};
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) => {
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 */ }
}
param_ty: param_ty) {
debug!("push_inherent_candidates_from_param(param_ty={:?})",
param_ty);
- let _indenter = indenter();
-
- let tcx = self.tcx();
- let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) {
- Some(t) => t,
- None => {
- tcx.sess.span_bug(
- self.expr.span,
- format!("No param def for {:?}", param_ty));
- }
- };
-
self.push_inherent_candidates_from_bounds(
- rcvr_ty, type_param_def.bounds.trait_bounds,
+ rcvr_ty,
+ self.fcx.inh.param_env.type_param_bounds[param_ty.idx].trait_bounds,
param_numbered(param_ty.idx));
}
fn push_inherent_candidates_from_self(&self,
- self_ty: ty::t,
- did: DefId) {
- let tcx = self.tcx();
-
- let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref;
+ rcvr_ty: ty::t) {
+ debug!("push_inherent_candidates_from_self()");
self.push_inherent_candidates_from_bounds(
- self_ty, &[trait_ref], param_self);
+ rcvr_ty,
+ [self.fcx.inh.param_env.self_param_bound.unwrap()],
+ param_self)
}
fn push_inherent_candidates_from_bounds(&self,
// 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
};
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();
use middle::pat_util::pat_id_map;
use middle::pat_util;
use middle::lint::unreachable_code;
+use middle::subst::Subst;
use middle::ty::{FnSig, VariantInfo};
use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
use middle::ty;
+use middle::ty_fold::TypeFolder;
use middle::typeck::astconv::AstConv;
use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
use middle::typeck::astconv;
use middle::typeck::CrateCtxt;
use middle::typeck::infer::{resolve_type, force_tvar};
use middle::typeck::infer;
-use middle::typeck::rscope::bound_self_region;
-use middle::typeck::rscope::{RegionError};
use middle::typeck::rscope::RegionScope;
-use middle::typeck::{isr_alist, lookup_def_ccx};
+use middle::typeck::{lookup_def_ccx};
use middle::typeck::no_params;
use middle::typeck::{require_same_types, method_map, vtable_map};
use util::common::{block_query, indenter, loop_query};
-use util::ppaux::{bound_region_ptr_to_str};
+use util::ppaux::UserString;
use util::ppaux;
-
use std::hashmap::HashMap;
use std::result;
use std::util::replace;
use std::vec;
-use extra::list::Nil;
use syntax::abi::AbiSet;
use syntax::ast::{provided, required};
use syntax::ast;
use syntax::opt_vec::OptVec;
use syntax::opt_vec;
use syntax::parse::token;
-use syntax::parse::token::special_idents;
use syntax::print::pprust;
use syntax::visit;
use syntax::visit::Visitor;
/// Here, the function `foo()` and the closure passed to
/// `bar()` will each have their own `FnCtxt`, but they will
/// share the inherited fields.
-pub struct inherited {
+pub struct Inherited {
infcx: @mut infer::InferCtxt,
locals: @mut HashMap<ast::NodeId, ty::t>,
+ param_env: ty::ParameterEnvironment,
// Temporary tables:
node_types: @mut HashMap<ast::NodeId, ty::t>,
// function return type.
fn_kind: FnKind,
- in_scope_regions: isr_alist,
-
- inh: @inherited,
+ inh: @Inherited,
ccx: @mut CrateCtxt,
}
-pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited {
- @inherited {
- infcx: infer::new_infer_ctxt(ccx.tcx),
- locals: @mut HashMap::new(),
- node_types: @mut HashMap::new(),
- node_type_substs: @mut HashMap::new(),
- adjustments: @mut HashMap::new(),
- method_map: @mut HashMap::new(),
- vtable_map: @mut HashMap::new(),
+impl Inherited {
+ fn new(tcx: ty::ctxt,
+ param_env: ty::ParameterEnvironment)
+ -> Inherited {
+ Inherited {
+ infcx: infer::new_infer_ctxt(tcx),
+ locals: @mut HashMap::new(),
+ param_env: param_env,
+ node_types: @mut HashMap::new(),
+ node_type_substs: @mut HashMap::new(),
+ adjustments: @mut HashMap::new(),
+ method_map: @mut HashMap::new(),
+ vtable_map: @mut HashMap::new(),
+ }
}
}
pub fn blank_fn_ctxt(ccx: @mut CrateCtxt,
rty: ty::t,
region_bnd: ast::NodeId)
- -> @mut FnCtxt {
-// It's kind of a kludge to manufacture a fake function context
-// and statement context, but we might as well do write the code only once
+ -> @mut FnCtxt {
+ // It's kind of a kludge to manufacture a fake function context
+ // and statement context, but we might as well do write the code only once
+ let param_env = ty::ParameterEnvironment { free_substs: substs::empty(),
+ self_param_bound: None,
+ type_param_bounds: ~[] };
@mut FnCtxt {
err_count_on_creation: ccx.tcx.sess.err_count(),
ret_ty: rty,
ps: PurityState::function(ast::impure_fn, 0),
region_lb: region_bnd,
- in_scope_regions: @Nil,
fn_kind: Vanilla,
- inh: blank_inherited(ccx),
+ inh: @Inherited::new(ccx.tcx, param_env),
ccx: ccx
}
}
decl: &ast::fn_decl,
body: &ast::Block,
id: ast::NodeId,
- self_info: Option<SelfInfo>) {
- let fty = ty::node_id_to_type(ccx.tcx, id);
+ self_info: Option<SelfInfo>,
+ fty: ty::t,
+ param_env: ty::ParameterEnvironment) {
match ty::get(fty).sty {
ty::ty_bare_fn(ref fn_ty) => {
let fcx =
check_fn(ccx, self_info, fn_ty.purity,
&fn_ty.sig, decl, id, body, Vanilla,
- @Nil, blank_inherited(ccx));;
+ @Inherited::new(ccx.tcx, param_env));
vtable::resolve_in_block(fcx, body);
regionck::regionck_fn(fcx, body);
id: ast::NodeId,
body: &ast::Block,
fn_kind: FnKind,
- inherited_isr: isr_alist,
- inherited: @inherited) -> @mut FnCtxt
+ inherited: @Inherited) -> @mut FnCtxt
{
/*!
- *
* Helper used by check_bare_fn and check_expr_fn. Does the
* grungy work of checking a function body and returns the
* function context used for that purpose, since in the case of a
* fn item there is still a bit more to do.
*
* - ...
- * - inherited_isr: regions in scope from the enclosing fn (if any)
* - inherited: other fields inherited from the enclosing fn (if any)
*/
let tcx = ccx.tcx;
let err_count_on_creation = tcx.sess.err_count();
- // ______________________________________________________________________
// First, we have to replace any bound regions in the fn and self
// types with free ones. The free region references will be bound
// the node_id of the body block.
- let (isr, opt_self_info, fn_sig) = {
+ let (opt_self_info, fn_sig) = {
let opt_self_ty = opt_self_info.map(|i| i.self_ty);
- let (isr, opt_self_ty, fn_sig) =
+ let (_, opt_self_ty, fn_sig) =
replace_bound_regions_in_fn_sig(
- tcx, inherited_isr, opt_self_ty, fn_sig,
+ tcx, opt_self_ty, fn_sig,
|br| ty::re_free(ty::FreeRegion {scope_id: body.id,
bound_region: br}));
let opt_self_info =
opt_self_info.map(
|si| SelfInfo {self_ty: opt_self_ty.unwrap(), .. si});
- (isr, opt_self_info, fn_sig)
+ (opt_self_info, fn_sig)
};
relate_free_regions(tcx, opt_self_info.map(|s| s.self_ty), &fn_sig);
ppaux::ty_to_str(tcx, ret_ty),
opt_self_info.map(|si| ppaux::ty_to_str(tcx, si.self_ty)));
- // ______________________________________________________________________
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
let fcx: @mut FnCtxt = {
ret_ty: ret_ty,
ps: PurityState::function(purity, id),
region_lb: body.id,
- in_scope_regions: isr,
fn_kind: fn_kind,
inh: inherited,
ccx: ccx
}
}
-pub fn check_method(ccx: @mut CrateCtxt,
- method: @ast::method)
-{
- let method_def_id = local_def(method.id);
- let method_ty = ty::method(ccx.tcx, method_def_id);
- let opt_self_info = method_ty.transformed_self_ty.map(|ty| {
- SelfInfo {self_ty: ty,
- self_id: method.self_id,
- span: method.explicit_self.span}
- });
-
- check_bare_fn(
- ccx,
- &method.decl,
- &method.body,
- method.id,
- opt_self_info
- );
-}
-
pub fn check_no_duplicate_fields(tcx: ty::ctxt,
fields: ~[(ast::Ident, Span)]) {
let mut field_names = HashMap::new();
match orig_sp {
Some(orig_sp) => {
tcx.sess.span_err(sp, format!("Duplicate field name {} in record type declaration",
- tcx.sess.str_of(id)));
+ tcx.sess.str_of(id)));
tcx.sess.span_note(orig_sp, "First declaration of this field occurred here");
break;
}
it.id);
}
ast::item_fn(ref decl, _, _, _, ref body) => {
- check_bare_fn(ccx, decl, body, it.id, None);
+ let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
+
+ // FIXME -- this won't fly for the case where people reference
+ // a lifetime from within a type parameter. That's actually fairly
+ // tricky.
+ let param_env = ty::construct_parameter_environment(
+ ccx.tcx,
+ None,
+ *fn_tpt.generics.type_param_defs,
+ [],
+ [],
+ body.id);
+
+ check_bare_fn(ccx, decl, body, it.id, None, fn_tpt.ty, param_env);
}
- ast::item_impl(_, _, _, ref ms) => {
- let rp = ccx.tcx.region_paramd_items.find(&it.id).map(|x| *x);
- debug!("item_impl {} with id {} rp {:?}",
- ccx.tcx.sess.str_of(it.ident), it.id, rp);
+ ast::item_impl(_, ref opt_trait_ref, _, ref ms) => {
+ debug!("item_impl {} with id {}", ccx.tcx.sess.str_of(it.ident), it.id);
+
+ let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
for m in ms.iter() {
- check_method(ccx, *m);
+ check_method_body(ccx, &impl_tpt.generics, None, *m);
}
vtable::resolve_impl(ccx, it);
}
ast::item_trait(_, _, ref trait_methods) => {
+ let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
for trait_method in (*trait_methods).iter() {
match *trait_method {
required(*) => {
// bodies to check.
}
provided(m) => {
- check_method(ccx, m);
+ check_method_body(ccx, &trait_def.generics,
+ Some(trait_def.trait_ref), m);
}
}
}
}
}
+fn check_method_body(ccx: @mut CrateCtxt,
+ item_generics: &ty::Generics,
+ self_bound: Option<@ty::TraitRef>,
+ method: @ast::method) {
+ /*!
+ * Type checks a method body.
+ *
+ * # Parameters
+ * - `item_generics`: generics defined on the impl/trait that contains
+ * the method
+ * - `self_bound`: bound for the `Self` type parameter, if any
+ * - `method`: the method definition
+ */
+
+ debug!("check_method_body(item_generics={}, \
+ self_bound={}, \
+ method.id={})",
+ item_generics.repr(ccx.tcx),
+ self_bound.repr(ccx.tcx),
+ method.id);
+ let method_def_id = local_def(method.id);
+ let method_ty = ty::method(ccx.tcx, method_def_id);
+ let method_generics = &method_ty.generics;
+
+ let param_env =
+ ty::construct_parameter_environment(
+ ccx.tcx,
+ self_bound,
+ *item_generics.type_param_defs,
+ *method_generics.type_param_defs,
+ item_generics.region_param_defs,
+ method.body.id);
+
+ // Compute the self type and fty from point of view of inside fn
+ let opt_self_info = method_ty.transformed_self_ty.map(|ty| {
+ SelfInfo {self_ty: ty.subst(ccx.tcx, ¶m_env.free_substs),
+ self_id: method.self_id,
+ span: method.explicit_self.span}
+ });
+ let fty = ty::node_id_to_type(ccx.tcx, method.id);
+ let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
+
+ check_bare_fn(
+ ccx,
+ &method.decl,
+ &method.body,
+ method.id,
+ opt_self_info,
+ fty,
+ param_env);
+}
+
impl AstConv for FnCtxt {
fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
pub fn infcx(&self) -> @mut infer::InferCtxt {
self.inh.infcx
}
+
pub fn err_count_since_creation(&self) -> uint {
self.ccx.tcx.sess.err_count() - self.err_count_on_creation
}
- pub fn search_in_scope_regions(&self,
- span: Span,
- br: ty::bound_region)
- -> Result<ty::Region, RegionError> {
- let in_scope_regions = self.in_scope_regions;
- match in_scope_regions.find(br) {
- Some(r) => result::Ok(r),
- None => {
- let blk_br = ty::br_named(special_idents::blk);
- if br == blk_br {
- result::Ok(self.block_region())
- } else {
- result::Err(RegionError {
- msg: {
- format!("named region `{}` not in scope here",
- bound_region_ptr_to_str(self.tcx(), br))
- },
- replacement: {
- self.infcx().next_region_var(
- infer::BoundRegionError(span))
- }
- })
- }
- }
+
+ pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
+ VtableContext {
+ infcx: self.infcx(),
+ param_env: &self.inh.param_env
}
}
}
-impl RegionScope for FnCtxt {
- fn anon_region(&self, span: Span) -> Result<ty::Region, RegionError> {
- result::Ok(self.infcx().next_region_var(infer::MiscVariable(span)))
- }
- fn self_region(&self, span: Span) -> Result<ty::Region, RegionError> {
- self.search_in_scope_regions(span, ty::br_self)
- }
- fn named_region(&self,
+impl RegionScope for @mut infer::InferCtxt {
+ fn anon_regions(&self,
span: Span,
- id: ast::Ident) -> Result<ty::Region, RegionError> {
- self.search_in_scope_regions(span, ty::br_named(id))
+ count: uint) -> Option<~[ty::Region]> {
+ Some(vec::from_fn(
+ count,
+ |_| self.next_region_var(infer::MiscVariable(span))))
}
}
}
pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
- ast_ty_to_ty(self, self, ast_t)
+ ast_ty_to_ty(self, &self.infcx(), ast_t)
}
pub fn pat_to_str(&self, pat: @ast::Pat) -> ~str {
Some(&t) => t,
None => {
self.tcx().sess.bug(format!("no type for expr in fcx {}",
- self.tag()));
+ self.tag()));
}
}
}
None => {
self.tcx().sess.bug(
format!("no type for node {}: {} in fcx {}",
- id, ast_map::node_id_to_str(
- self.tcx().items, id,
- token::get_ident_interner()),
- self.tag()));
+ id, ast_map::node_id_to_str(
+ self.tcx().items, id,
+ token::get_ident_interner()),
+ self.tag()));
}
}
}
None => {
self.tcx().sess.bug(
format!("no type substs for node {}: {} in fcx {}",
- id, ast_map::node_id_to_str(
- self.tcx().items, id,
- token::get_ident_interner()),
- self.tag()));
+ id, ast_map::node_id_to_str(self.tcx().items, id,
+ token::get_ident_interner()),
+ self.tag()));
}
}
}
v
}
- pub fn region_var_if_parameterized(&self,
- rp: Option<ty::region_variance>,
- span: Span)
- -> OptVec<ty::Region> {
- match rp {
- None => opt_vec::Empty,
- Some(_) => {
- opt_vec::with(
- self.infcx().next_region_var(
- infer::BoundRegionInTypeOrImpl(span)))
- }
- }
- }
-
pub fn type_error_message(&self,
sp: Span,
mk_msg: &fn(~str) -> ~str,
-> ty_param_substs_and_ty {
let tcx = vcx.tcx();
- let (n_tps, region_param, raw_ty) = {
+ let (n_tps, n_rps, raw_ty) = {
let ity = ty::lookup_item_type(tcx, did);
- (ity.generics.type_param_defs.len(), ity.generics.region_param, ity.ty)
+ (ity.generics.type_param_defs.len(),
+ ity.generics.region_param_defs.len(),
+ ity.ty)
};
- let regions = ty::NonerasedRegions(if region_param.is_some() {
- opt_vec::with(vcx.infcx.next_region_var(
- infer::BoundRegionInTypeOrImpl(location_info.span)))
- } else {
- opt_vec::Empty
- });
+ let rps =
+ vcx.infcx.next_region_vars(
+ infer::BoundRegionInTypeOrImpl(location_info.span),
+ n_rps);
let tps = vcx.infcx.next_ty_vars(n_tps);
- let substs = substs {regions: regions, self_ty: None, tps: tps};
+ let substs = substs {regions: ty::NonerasedRegions(opt_vec::from(rps)),
+ self_ty: None,
+ tps: tps};
let substd_ty = ty::subst(tcx, &substs, raw_ty);
ty_param_substs_and_ty { substs: substs, ty: substd_ty }
// Verify that no lifetimes or type parameters are present anywhere
// except the final two elements of the path.
for i in range(0, path.segments.len() - 2) {
- match path.segments[i].lifetime {
- None => {}
- Some(lifetime) => {
- function_context.tcx()
- .sess
- .span_err(lifetime.span,
- "lifetime parameters may not \
- appear here")
- }
+ for lifetime in path.segments[i].lifetimes.iter() {
+ function_context.tcx()
+ .sess
+ .span_err(lifetime.span,
+ "lifetime parameters may not \
+ appear here");
+ break;
}
for typ in path.segments[i].types.iter() {
function_context.tcx()
.sess
.span_err(typ.span,
- "type parameters may not appear here")
+ "type parameters may not appear here");
+ break;
}
}
// rest of typechecking will (attempt to) infer everything.
if path.segments
.iter()
- .all(|s| s.lifetime.is_none() && s.types.is_empty()) {
+ .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
return
}
// Make sure lifetime parameterization agrees with the trait or
// implementation type.
- match (generics.region_param, trait_segment.lifetime) {
- (Some(_), None) => {
- function_context.tcx()
- .sess
- .span_err(path.span,
- format!("this {} has a lifetime \
- parameter but no \
- lifetime was specified",
- name))
- }
- (None, Some(_)) => {
- function_context.tcx()
- .sess
- .span_err(path.span,
- format!("this {} has no lifetime \
- parameter but a lifetime \
- was specified",
- name))
- }
- (Some(_), Some(_)) | (None, None) => {}
+ let trait_region_parameter_count = generics.region_param_defs.len();
+ let supplied_region_parameter_count = trait_segment.lifetimes.len();
+ if trait_region_parameter_count != supplied_region_parameter_count
+ && supplied_region_parameter_count != 0 {
+ function_context.tcx()
+ .sess
+ .span_err(path.span,
+ format!("expected {} lifetime parameter(s), \
+ found {} lifetime parameter(s)",
+ trait_region_parameter_count,
+ supplied_region_parameter_count));
}
// Make sure the number of type parameters supplied on the trait
// Verify that no lifetimes or type parameters are present on
// the penultimate segment of the path.
let segment = &path.segments[path.segments.len() - 2];
- match segment.lifetime {
- None => {}
- Some(lifetime) => {
- function_context.tcx()
- .sess
- .span_err(lifetime.span,
- "lifetime parameters may not
- appear here")
- }
+ for lifetime in segment.lifetimes.iter() {
+ function_context.tcx()
+ .sess
+ .span_err(lifetime.span,
+ "lifetime parameters may not
+ appear here");
+ break;
}
for typ in segment.types.iter() {
function_context.tcx()
.span_err(typ.span,
"type parameters may not appear \
here");
- function_context.tcx()
- .sess
- .span_note(typ.span,
- format!("this is a {:?}", def));
+ break;
}
}
}
// In that case, we check each argument against "error" in order to
// set up all the node type bindings.
let error_fn_sig = FnSig {
- bound_lifetime_names: opt_vec::Empty,
+ binder_id: ast::CRATE_NODE_ID,
inputs: err_args(args.len()),
output: ty::mk_err(),
variadic: false
// signature with region variables
let (_, _, fn_sig) =
replace_bound_regions_in_fn_sig(fcx.tcx(),
- @Nil,
None,
fn_sig,
|br| fcx.infcx()
expected: Option<ty::t>) {
let tcx = fcx.ccx.tcx;
- // Find the expected input/output types (if any). Careful to
- // avoid capture of bound regions in the expected type. See
- // def'n of br_cap_avoid() for a more lengthy explanation of
- // what's going on here.
+ // Find the expected input/output types (if any). Substitute
+ // fresh bound regions for any bound regions we find in the
+ // expected types so as to avoid capture.
+ //
// Also try to pick up inferred purity and sigil, defaulting
// to impure and block. Note that we only will use those for
// block syntax lambdas; that is, lambdas without explicit
expected_bounds) = {
match expected_sty {
Some(ty::ty_closure(ref cenv)) => {
- let id = expr.id;
let (_, _, sig) =
replace_bound_regions_in_fn_sig(
- tcx, @Nil, None, &cenv.sig,
- |br| ty::re_bound(ty::br_cap_avoid(id, @br)));
+ tcx, None, &cenv.sig,
+ |_| fcx.inh.infcx.fresh_bound_region(expr.id));
(Some(sig), cenv.purity, cenv.sigil,
cenv.onceness, cenv.bounds)
}
// construct the function type
let fn_ty = astconv::ty_of_closure(fcx,
- fcx,
+ &fcx.infcx(),
+ expr.id,
sigil,
purity,
expected_onceness,
&None,
decl,
expected_sig,
- &opt_vec::Empty,
expr.span);
let fty_sig;
let fty = if error_happened {
fty_sig = FnSig {
- bound_lifetime_names: opt_vec::Empty,
+ binder_id: ast::CRATE_NODE_ID,
inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()),
output: ty::mk_err(),
variadic: false
sigil);
check_fn(fcx.ccx, None, inherited_purity, &fty_sig,
- decl, id, body, fn_kind, fcx.in_scope_regions, fcx.inh);
+ decl, id, body, fn_kind, fcx.inh);
}
// Look up the number of type parameters and the raw type, and
// determine whether the class is region-parameterized.
- let type_parameter_count;
- let region_parameterized;
- let raw_type;
- if class_id.crate == ast::LOCAL_CRATE {
- region_parameterized =
- tcx.region_paramd_items.find(&class_id.node).
- map(|x| *x);
- match tcx.items.find(&class_id.node) {
- Some(&ast_map::node_item(@ast::item {
- node: ast::item_struct(_, ref generics),
- _
- }, _)) => {
-
- type_parameter_count = generics.ty_params.len();
-
- let self_region =
- bound_self_region(region_parameterized);
-
- raw_type = ty::mk_struct(tcx, class_id, substs {
- regions: ty::NonerasedRegions(self_region),
- self_ty: None,
- tps: ty::ty_params_to_tys(
- tcx,
- generics)
- });
- }
- _ => {
- tcx.sess.span_bug(span,
- "resolve didn't map this to a class");
- }
- }
- } else {
- let item_type = ty::lookup_item_type(tcx, class_id);
- type_parameter_count = item_type.generics.type_param_defs.len();
- region_parameterized = item_type.generics.region_param;
- raw_type = item_type.ty;
- }
+ let item_type = ty::lookup_item_type(tcx, class_id);
+ let type_parameter_count = item_type.generics.type_param_defs.len();
+ let region_parameter_count = item_type.generics.region_param_defs.len();
+ let raw_type = item_type.ty;
// Generate the struct type.
- let regions =
- fcx.region_var_if_parameterized(region_parameterized, span);
+ let regions = fcx.infcx().next_region_vars(
+ infer::BoundRegionInTypeOrImpl(span),
+ region_parameter_count);
let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
let substitutions = substs {
- regions: ty::NonerasedRegions(regions),
+ regions: ty::NonerasedRegions(opt_vec::from(regions)),
self_ty: None,
tps: type_parameters
};
// Look up the number of type parameters and the raw type, and
// determine whether the enum is region-parameterized.
- let type_parameter_count;
- let region_parameterized;
- let raw_type;
- if enum_id.crate == ast::LOCAL_CRATE {
- region_parameterized =
- tcx.region_paramd_items.find(&enum_id.node).map(|x| *x);
- match tcx.items.find(&enum_id.node) {
- Some(&ast_map::node_item(@ast::item {
- node: ast::item_enum(_, ref generics),
- _
- }, _)) => {
-
- type_parameter_count = generics.ty_params.len();
-
- let regions = bound_self_region(region_parameterized);
-
- raw_type = ty::mk_enum(tcx, enum_id, substs {
- regions: ty::NonerasedRegions(regions),
- self_ty: None,
- tps: ty::ty_params_to_tys(
- tcx,
- generics)
- });
- }
- _ => {
- tcx.sess.span_bug(span,
- "resolve didn't map this to an enum");
- }
- }
- } else {
- let item_type = ty::lookup_item_type(tcx, enum_id);
- type_parameter_count = item_type.generics.type_param_defs.len();
- region_parameterized = item_type.generics.region_param;
- raw_type = item_type.ty;
- }
+ let item_type = ty::lookup_item_type(tcx, enum_id);
+ let type_parameter_count = item_type.generics.type_param_defs.len();
+ let region_parameter_count = item_type.generics.region_param_defs.len();
+ let raw_type = item_type.ty;
// Generate the enum type.
- let regions =
- fcx.region_var_if_parameterized(region_parameterized, span);
+ let regions = fcx.infcx().next_region_vars(
+ infer::BoundRegionInTypeOrImpl(span),
+ region_parameter_count);
let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
let substitutions = substs {
- regions: ty::NonerasedRegions(regions),
+ regions: ty::NonerasedRegions(opt_vec::from(regions)),
self_ty: None,
tps: type_parameters
};
ty_param_count,
ty_substs_len);
- // determine the region bound, using the value given by the user
+ // determine the region parameters, using the value given by the user
// (if any) and otherwise using a fresh region variable
- let regions = match pth.segments.last().lifetime {
- Some(_) => { // user supplied a lifetime parameter...
- match tpt.generics.region_param {
- None => { // ...but the type is not lifetime parameterized!
- fcx.ccx.tcx.sess.span_err
- (span, "this item is not region-parameterized");
- opt_vec::Empty
- }
- Some(_) => { // ...and the type is lifetime parameterized, ok.
- opt_vec::with(
- ast_region_to_region(fcx,
- fcx,
- span,
- &pth.segments.last().lifetime))
- }
- }
- }
- None => { // no lifetime parameter supplied, insert default
- fcx.region_var_if_parameterized(tpt.generics.region_param, span)
+ let num_expected_regions = tpt.generics.region_param_defs.len();
+ let num_supplied_regions = pth.segments.last().lifetimes.len();
+ let regions = if num_expected_regions == num_supplied_regions {
+ pth.segments.last().lifetimes.map(
+ |l| ast_region_to_region(fcx.tcx(), l))
+ } else {
+ if num_supplied_regions != 0 {
+ fcx.ccx.tcx.sess.span_err(
+ span,
+ format!("expected {} lifetime parameter(s), \
+ found {} lifetime parameter(s)",
+ num_expected_regions, num_supplied_regions));
}
+
+ opt_vec::from(fcx.infcx().next_region_vars(
+ infer::BoundRegionInTypeOrImpl(span),
+ num_expected_regions))
};
// Special case: If there is a self parameter, omit it from the list of
if tps.len() == 0u { return; }
let mut tps_used = vec::from_elem(tps.len(), false);
- ty::walk_regions_and_ty(
- ccx.tcx, ty,
- |_r| {},
- |t| {
+ ty::walk_ty(ty, |t| {
match ty::get(t).sty {
- ty::ty_param(param_ty {idx, _}) => {
- debug!("Found use of ty param \\#{}", idx);
- tps_used[idx] = true;
- }
- _ => ()
+ ty::ty_param(param_ty {idx, _}) => {
+ debug!("Found use of ty param \\#{}", idx);
+ tps_used[idx] = true;
+ }
+ _ => ()
}
- true
});
for (i, b) in tps_used.iter().enumerate() {
//We only care about the operation here
match split[1] {
"cxchg" => (0, ~[ty::mk_mut_rptr(tcx,
- ty::re_bound(ty::br_anon(0)),
+ ty::re_fn_bound(it.id, ty::br_anon(0)),
ty::mk_int()),
ty::mk_int(),
ty::mk_int()
], ty::mk_int()),
"load" => (0,
~[
- ty::mk_imm_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int())
+ ty::mk_imm_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int())
],
ty::mk_int()),
"store" => (0,
~[
- ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()),
+ ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()),
ty::mk_int()
],
ty::mk_nil()),
"xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
"min" | "umax" | "umin" => {
(0, ~[ty::mk_mut_rptr(tcx,
- ty::re_bound(ty::br_anon(0)),
+ ty::re_fn_bound(it.id, ty::br_anon(0)),
ty::mk_int()), ty::mk_int() ], ty::mk_int())
}
"fence" => {
"move_val" | "move_val_init" => {
(1u,
~[
- ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), param(ccx, 0)),
+ ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), param(ccx, 0)),
param(ccx, 0u)
],
ty::mk_nil())
"atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => {
(0,
~[
- ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()),
+ ty::mk_mut_rptr(tcx, ty::re_fn_bound(it.id, ty::br_anon(0)), ty::mk_int()),
ty::mk_int()
],
ty::mk_int())
Ok(t) => t,
Err(s) => { tcx.sess.span_fatal(it.span, s); }
};
- let region = ty::re_bound(ty::br_anon(0));
+ let region = ty::re_fn_bound(it.id, ty::br_anon(0));
let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
Ok((_, vot)) => vot,
Err(s) => { tcx.sess.span_fatal(it.span, s); }
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
purity: ast::unsafe_fn,
abis: AbiSet::Intrinsic(),
- sig: FnSig {
- bound_lifetime_names: opt_vec::Empty,
- inputs: inputs,
- output: output,
- variadic: false
- }
+ sig: FnSig {binder_id: it.id,
+ inputs: inputs,
+ output: output,
+ variadic: false}
});
let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
let i_n_tps = i_ty.generics.type_param_defs.len();
ppaux::ty_to_str(ccx.tcx, fty)));
}
}
+
//! 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
let callee_region = ty::re_scope(callee_scope);
for &arg_expr in arg_exprs.iter() {
+ debug!("Argument");
+
// ensure that any regions appearing in the argument type are
// valid for at least the lifetime of the function:
constrain_regions_in_type_of_node(
// 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 {
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.
// #[warn(deprecated_mode)];
-
use middle::ty;
-
-use middle::typeck::isr_alist;
-use util::common::indenter;
-use util::ppaux::region_to_str;
+use middle::ty_fold;
+use middle::ty_fold::TypeFolder;
+use std::hashmap::HashMap;
+use util::ppaux::Repr;
use util::ppaux;
-use extra::list::Cons;
-
// Helper functions related to manipulating region types.
pub fn replace_bound_regions_in_fn_sig(
tcx: ty::ctxt,
- isr: isr_alist,
opt_self_ty: Option<ty::t>,
fn_sig: &ty::FnSig,
mapf: &fn(ty::bound_region) -> ty::Region)
- -> (isr_alist, Option<ty::t>, ty::FnSig)
+ -> (HashMap<ty::bound_region,ty::Region>, Option<ty::t>, ty::FnSig)
{
- let mut all_tys = ty::tys_in_fn_sig(fn_sig);
-
- 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 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)));
- }
+ debug!("replace_bound_regions_in_fn_sig(self_ty={}, fn_sig={})",
+ opt_self_ty.repr(tcx),
+ fn_sig.repr(tcx));
+
+ let mut map = HashMap::new();
+ let (fn_sig, opt_self_ty) = {
+ let mut f = ty_fold::RegionFolder::regions(tcx, |r| {
+ debug!("region r={}", r.to_str());
+ match r {
+ ty::re_fn_bound(s, br) if s == fn_sig.binder_id => {
+ *map.find_or_insert_with(br, |_| mapf(br))
}
- }
-
- // 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
- }
- }
+ _ => r
+ }});
+ (ty_fold::super_fold_sig(&mut f, fn_sig),
+ ty_fold::fold_opt_ty(&mut f, opt_self_ty))
+ };
+ debug!("resulting map: {}", map.to_str());
+ (map, opt_self_ty, fn_sig)
}
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
* Hence, in the second example above, `'r2` must be a subregion of `'r3`.
*/
- let mut the_stack = ~[];
- for &r in opt_region.iter() { the_stack.push(r); }
- walk_ty(tcx, &mut the_stack, ty, relate_op);
+ let mut rr = RegionRelator { tcx: tcx,
+ stack: ~[],
+ relate_op: relate_op };
+ match opt_region {
+ Some(o_r) => { rr.stack.push(o_r); }
+ None => {}
+ }
+ rr.fold_ty(ty);
- fn walk_ty(tcx: ty::ctxt,
- the_stack: &mut ~[ty::Region],
- ty: ty::t,
- relate_op: &fn(ty::Region, ty::Region))
- {
- match ty::get(ty).sty {
- ty::ty_rptr(r, ref mt) |
- ty::ty_evec(ref mt, ty::vstore_slice(r)) => {
- relate(*the_stack, r, |x,y| relate_op(x,y));
- the_stack.push(r);
- walk_ty(tcx, the_stack, mt.ty, |x,y| relate_op(x,y));
- the_stack.pop();
- }
- _ => {
- ty::fold_regions_and_ty(
- tcx,
- ty,
- |r| { relate( *the_stack, r, |x,y| relate_op(x,y)); r },
- |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t },
- |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t });
+ struct RegionRelator<'self> {
+ tcx: ty::ctxt,
+ stack: ~[ty::Region],
+ relate_op: &'self fn(ty::Region, ty::Region),
+ }
+
+ // FIXME we should define more precisely when a
+ // region is considered "nested" and take variance into account.
+ //
+ // I can't decide whether skipping closure parameter types and
+ // so on is necessary or not. What is the difference, after all,
+ // between `&'a |&'b T|` and `&'a Fn<&'b T>`? And yet in the
+ // latter case I'm inclined to think we should probably track
+ // the relationship (but then again maybe we should just skip
+ // all such cases until it "proves necessary")
+
+ impl<'self> TypeFolder for RegionRelator<'self> {
+ fn tcx(&self) -> ty::ctxt {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, ty: ty::t) -> ty::t {
+ match ty::get(ty).sty {
+ ty::ty_rptr(r, ref mt) |
+ ty::ty_evec(ref mt, ty::vstore_slice(r)) => {
+ self.relate(r);
+ self.stack.push(r);
+ ty_fold::super_fold_ty(self, mt.ty);
+ self.stack.pop();
+ }
+
+ _ => {
+ ty_fold::super_fold_ty(self, ty);
+ }
}
+
+ ty
+ }
+
+ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+ self.relate(r);
+ r
}
}
- fn relate(the_stack: &[ty::Region],
- r_sub: ty::Region,
- relate_op: &fn(ty::Region, ty::Region))
- {
- for &r in the_stack.iter() {
- if !r.is_bound() && !r_sub.is_bound() {
- relate_op(r, r_sub);
+ impl<'self> RegionRelator<'self> {
+ fn relate(&mut self, r_sub: ty::Region) {
+ for &r in self.stack.iter() {
+ if !r.is_bound() && !r_sub.is_bound() {
+ (self.relate_op)(r, r_sub);
+ }
}
}
}
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;
/// 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 {
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 =
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 => {
// 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)
}
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;
ty: ty::t,
trait_ref: @ty::TraitRef,
is_early: bool)
- -> Option<vtable_origin>
-{
+ -> Option<vtable_origin> {
let tcx = vcx.tcx();
let mut found = ~[];
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),
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) {
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);
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 {
(&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 {
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);
-
- // 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);
-
- // Now, locate the vtable for the impl itself. The real
- // purpose of this is to check for supertrait impls,
- // but that falls out of doing this.
- let param_bounds = ty::ParamBounds {
- builtin_bounds: ty::EmptyBuiltinBounds(),
- trait_bounds: ~[trait_ref]
- };
- let t = ty::node_id_to_type(ccx.tcx, impl_item.id);
- debug!("=== Doing a self lookup now.");
- // Right now, we don't have any place to store this.
- // We will need to make one so we can use this information
- // for compiling default methods that refer to supertraits.
- let self_vtable_res =
- lookup_vtables_for_param(&vcx, &loc_info, None,
- ¶m_bounds, t, false);
-
-
- let res = impl_res {
- trait_vtables: vtbls,
- self_vtables: self_vtable_res
- };
- ccx.tcx.impl_vtables.insert(def_id, res);
- }
- }
+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);
+
+ let impl_trait_ref = @impl_trait_ref.subst(ccx.tcx, ¶m_env.free_substs);
+
+ let infcx = infer::new_infer_ctxt(ccx.tcx);
+ let vcx = VtableContext { infcx: infcx, param_env: ¶m_env };
+ let loc_info = location_info_for_item(impl_item);
+
+ // First, check that the impl implements any trait bounds
+ // on the trait.
+ let trait_def = ty::lookup_trait_def(ccx.tcx, impl_trait_ref.def_id);
+ let vtbls = lookup_vtables(&vcx,
+ &loc_info,
+ *trait_def.generics.type_param_defs,
+ &impl_trait_ref.substs,
+ false);
+
+ // Now, locate the vtable for the impl itself. The real
+ // purpose of this is to check for supertrait impls,
+ // but that falls out of doing this.
+ let param_bounds = ty::ParamBounds {
+ builtin_bounds: ty::EmptyBuiltinBounds(),
+ trait_bounds: ~[impl_trait_ref]
+ };
+ let t = ty::node_id_to_type(ccx.tcx, impl_item.id);
+ let t = t.subst(ccx.tcx, ¶m_env.free_substs);
+ debug!("=== Doing a self lookup now.");
+
+ // Right now, we don't have any place to store this.
+ // We will need to make one so we can use this information
+ // for compiling default methods that refer to supertraits.
+ let self_vtable_res =
+ lookup_vtables_for_param(&vcx, &loc_info, None,
+ ¶m_bounds, t, false);
+
+
+ let res = impl_res {
+ trait_vtables: vtbls,
+ self_vtables: self_vtable_res
+ };
+ 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 {
@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,
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
};
use middle::typeck::astconv::{AstConv, ty_of_arg};
use middle::typeck::astconv::{ast_ty_to_ty};
use middle::typeck::astconv;
-use middle::typeck::infer;
use middle::typeck::rscope::*;
-use middle::typeck::rscope;
use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
-use util::common::pluralize;
use util::ppaux;
-use util::ppaux::UserString;
-use std::result;
use std::vec;
use syntax::abi::AbiSet;
use syntax::ast::{RegionTyParamBound, TraitTyParamBound};
use syntax::ast_util::{local_def, split_trait_methods};
use syntax::codemap::Span;
use syntax::codemap;
-use syntax::print::pprust::{path_to_str, explicit_self_to_str};
+use syntax::print::pprust::{path_to_str};
use syntax::visit;
use syntax::opt_vec::OptVec;
-use syntax::opt_vec;
use syntax::parse::token::special_idents;
struct CollectItemTypesVisitor {
}
pub trait ToTy {
- fn to_ty<RS:RegionScope + Clone + 'static>(
- &self,
- rs: &RS,
- ast_ty: &ast::Ty)
- -> ty::t;
+ fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t;
}
impl ToTy for CrateCtxt {
- fn to_ty<RS:RegionScope + Clone + 'static>(
- &self,
- rs: &RS,
- ast_ty: &ast::Ty)
- -> ty::t {
+ fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t {
ast_ty_to_ty(self, rs, ast_ty)
}
}
pub fn get_enum_variant_types(ccx: &CrateCtxt,
enum_ty: ty::t,
variants: &[ast::variant],
- generics: &ast::Generics,
- rp: Option<ty::region_variance>) {
+ generics: &ast::Generics) {
let tcx = ccx.tcx;
// Create a set of parameter types shared among all the variants.
for variant in variants.iter() {
- let region_parameterization =
- RegionParameterization::from_variance_and_generics(rp, generics);
-
// Nullary enum constructors get turned into constants; n-ary enum
// constructors get turned into functions.
- let result_ty;
- match variant.node.kind {
+ let scope = variant.node.id;
+ let result_ty = match variant.node.kind {
ast::tuple_variant_kind(ref args) if args.len() > 0 => {
- let rs = TypeRscope(region_parameterization);
+ let rs = ExplicitRscope;
let input_tys = args.map(|va| ccx.to_ty(&rs, &va.ty));
- result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty));
+ ty::mk_ctor_fn(tcx, scope, input_tys, enum_ty)
}
ast::tuple_variant_kind(_) => {
- result_ty = Some(enum_ty);
+ enum_ty
}
ast::struct_variant_kind(struct_def) => {
let tpt = ty_param_bounds_and_ty {
- generics: ty_generics(ccx, rp, generics, 0),
+ generics: ty_generics(ccx, generics, 0),
ty: enum_ty
};
- convert_struct(ccx,
- rp,
- struct_def,
- generics,
- tpt,
- variant.node.id);
+ convert_struct(ccx, struct_def, tpt, variant.node.id);
let input_tys = struct_def.fields.map(
|f| ty::node_id_to_type(ccx.tcx, f.node.id));
- result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty));
+ ty::mk_ctor_fn(tcx, scope, input_tys, enum_ty)
}
};
- match result_ty {
- None => {}
- Some(result_ty) => {
- let tpt = ty_param_bounds_and_ty {
- generics: ty_generics(ccx, rp, generics, 0),
- ty: result_ty
- };
- tcx.tcache.insert(local_def(variant.node.id), tpt);
- write_ty_to_tcx(tcx, variant.node.id, result_ty);
- }
- }
+ let tpt = ty_param_bounds_and_ty {
+ generics: ty_generics(ccx, generics, 0),
+ ty: result_ty
+ };
+ tcx.tcache.insert(local_def(variant.node.id), tpt);
+ write_ty_to_tcx(tcx, variant.node.id, result_ty);
}
}
trait_id: ast::NodeId)
{
let tcx = ccx.tcx;
- let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|x| *x);
match tcx.items.get_copy(&trait_id) {
ast_map::node_item(@ast::item {
node: ast::item_trait(ref generics, _, ref ms),
_
}, _) => {
- let trait_ty_generics = ty_generics(ccx, region_paramd, generics, 0);
+ let trait_ty_generics =
+ ty_generics(ccx, generics, 0);
// For each method, construct a suitable ty::Method and
// store it into the `tcx.methods` table:
let ty_method = @match m {
&ast::required(ref m) => {
ty_method_of_trait_method(
- ccx, trait_id, region_paramd, generics,
+ ccx, trait_id, &trait_ty_generics,
&m.id, &m.ident, &m.explicit_self,
&m.generics, &m.purity, &m.decl)
}
&ast::provided(ref m) => {
ty_method_of_trait_method(
- ccx, trait_id, region_paramd, generics,
+ ccx, trait_id, &trait_ty_generics,
&m.id, &m.ident, &m.explicit_self,
&m.generics, &m.purity, &m.decl)
}
trait_ty_generics: &ty::Generics) {
// If declaration is
//
- // trait<A,B,C> {
- // fn foo<D,E,F>(...) -> Self;
+ // trait<'a,'b,'c,A,B,C> {
+ // fn foo<'d,'e,'f,D,E,F>(...) -> Self;
// }
//
// and we will create a function like
//
- // fn foo<A',B',C',D',E',F',G'>(...) -> D' {}
+ // fn foo<'a,'b,'c,'d,'e,'f,A',B',C',D',E',F',G'>(...) -> D' {}
//
// Note that `Self` is replaced with an explicit type
// parameter D' that is sandwiched in between the trait params
m.generics.type_param_defs[i].def_id)
};
+ // Convert the regions 'a, 'b, 'c defined on the trait into
+ // bound regions on the fn.
+ let rps_from_trait = trait_ty_generics.region_param_defs.iter().map(|d| {
+ ty::re_fn_bound(m.fty.sig.binder_id,
+ ty::br_named(d.def_id, d.ident))
+ }).collect();
+
// build up the substitution from
// A,B,C => A',B',C'
// Self => D'
// D,E,F => E',F',G'
let substs = substs {
- regions: ty::NonerasedRegions(opt_vec::Empty),
+ regions: ty::NonerasedRegions(rps_from_trait),
self_ty: Some(self_param),
tps: non_shifted_trait_tps + shifted_method_tps
};
ty_param_bounds_and_ty {
generics: ty::Generics {
type_param_defs: @new_type_param_defs,
- region_param: trait_ty_generics.region_param
+ region_param_defs: @[], // fn items
},
ty: ty
});
fn ty_method_of_trait_method(this: &CrateCtxt,
trait_id: ast::NodeId,
- trait_rp: Option<ty::region_variance>,
- trait_generics: &ast::Generics,
+ trait_generics: &ty::Generics,
m_id: &ast::NodeId,
m_ident: &ast::Ident,
m_explicit_self: &ast::explicit_self,
m_decl: &ast::fn_decl) -> ty::Method
{
let trait_self_ty = ty::mk_self(this.tcx, local_def(trait_id));
- let rscope = MethodRscope::new(m_explicit_self.node, trait_rp, trait_generics);
let (transformed_self_ty, fty) =
- astconv::ty_of_method(this, &rscope, *m_purity, &m_generics.lifetimes,
+ astconv::ty_of_method(this, *m_id, *m_purity,
trait_self_ty, *m_explicit_self, m_decl);
- let num_trait_type_params = trait_generics.ty_params.len();
+ let num_trait_type_params = trait_generics.type_param_defs.len();
ty::Method::new(
*m_ident,
- ty_generics(this, None, m_generics, num_trait_type_params),
+ // FIXME -- what about lifetime parameters here?
+ ty_generics(this, m_generics, num_trait_type_params),
transformed_self_ty,
fty,
m_explicit_self.node,
pub fn ensure_supertraits(ccx: &CrateCtxt,
id: ast::NodeId,
sp: codemap::Span,
- rp: Option<ty::region_variance>,
- ast_trait_refs: &[ast::trait_ref],
- generics: &ast::Generics) -> ty::BuiltinBounds
+ ast_trait_refs: &[ast::trait_ref])
+ -> ty::BuiltinBounds
{
let tcx = ccx.tcx;
// FIXME(#8559): Need to instantiate the trait_ref whether or not it's a
// builtin trait, so that the trait's node id appears in the tcx trait_ref
// map. This is only needed for metadata; see the similar fixme in encoder.rs.
- let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, rp,
- generics, self_ty);
+ let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, self_ty);
if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) {
// FIXME(#5527) Could have same trait multiple times
} // fn
pub fn convert_field(ccx: &CrateCtxt,
- rp: Option<ty::region_variance>,
- type_param_defs: @~[ty::TypeParameterDef],
- v: &ast::struct_field,
- generics: &ast::Generics) {
- let region_parameterization =
- RegionParameterization::from_variance_and_generics(rp, generics);
- let tt = ccx.to_ty(&TypeRscope(region_parameterization), &v.node.ty);
+ struct_generics: &ty::Generics,
+ v: &ast::struct_field) {
+ let tt = ccx.to_ty(&ExplicitRscope, &v.node.ty);
write_ty_to_tcx(ccx.tcx, v.node.id, tt);
/* add the field to the tcache */
ccx.tcx.tcache.insert(local_def(v.node.id),
ty::ty_param_bounds_and_ty {
- generics: ty::Generics {
- type_param_defs: type_param_defs,
- region_param: rp
- },
+ generics: struct_generics.clone(),
ty: tt
});
}
-pub struct ConvertedMethod {
- mty: @ty::Method,
- id: ast::NodeId,
- span: Span,
- body_id: ast::NodeId
-}
-
-pub fn convert_methods(ccx: &CrateCtxt,
- container: MethodContainer,
- ms: &[@ast::method],
- untransformed_rcvr_ty: ty::t,
- rcvr_ty_generics: &ty::Generics,
- rcvr_ast_generics: &ast::Generics,
- rcvr_visibility: ast::visibility)
- -> ~[ConvertedMethod]
+fn convert_methods(ccx: &CrateCtxt,
+ container: MethodContainer,
+ ms: &[@ast::method],
+ untransformed_rcvr_ty: ty::t,
+ rcvr_ty_generics: &ty::Generics,
+ rcvr_ast_generics: &ast::Generics,
+ rcvr_visibility: ast::visibility)
{
let tcx = ccx.tcx;
- return ms.iter().map(|m| {
+ for m in ms.iter() {
let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs.len();
- let m_ty_generics =
- ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics,
- num_rcvr_ty_params);
+ let m_ty_generics = ty_generics(ccx, &m.generics, num_rcvr_ty_params);
let mty = @ty_of_method(ccx,
container,
*m,
- rcvr_ty_generics.region_param,
untransformed_rcvr_ty,
rcvr_ast_generics,
- rcvr_visibility,
- &m.generics);
+ rcvr_visibility);
let fty = ty::mk_bare_fn(tcx, mty.fty.clone());
+ debug!("method {} (id {}) has type {}",
+ m.ident.repr(ccx.tcx),
+ m.id,
+ fty.repr(ccx.tcx));
tcx.tcache.insert(
local_def(m.id),
// n.b.: the type of a method is parameterized by both
- // the tps on the receiver and those on the method itself
+ // the parameters on the receiver and those on the method itself
ty_param_bounds_and_ty {
generics: ty::Generics {
type_param_defs: @vec::append(
(*rcvr_ty_generics.type_param_defs).clone(),
*m_ty_generics.type_param_defs),
- region_param: rcvr_ty_generics.region_param
+ region_param_defs: rcvr_ty_generics.region_param_defs,
},
ty: fty
});
write_ty_to_tcx(tcx, m.id, fty);
tcx.methods.insert(mty.def_id, mty);
- ConvertedMethod {mty: mty, id: m.id,
- span: m.span, body_id: m.body.id}
- }).collect();
+ }
fn ty_of_method(ccx: &CrateCtxt,
container: MethodContainer,
m: &ast::method,
- rp: Option<ty::region_variance>,
untransformed_rcvr_ty: ty::t,
rcvr_generics: &ast::Generics,
- rcvr_visibility: ast::visibility,
- method_generics: &ast::Generics) -> ty::Method
+ rcvr_visibility: ast::visibility) -> ty::Method
{
- let rscope = MethodRscope::new(m.explicit_self.node,
- rp,
- rcvr_generics);
let (transformed_self_ty, fty) =
- astconv::ty_of_method(ccx, &rscope, m.purity,
- &method_generics.lifetimes,
+ astconv::ty_of_method(ccx, m.id, m.purity,
untransformed_rcvr_ty,
m.explicit_self, &m.decl);
let num_rcvr_type_params = rcvr_generics.ty_params.len();
ty::Method::new(
m.ident,
- ty_generics(ccx, None, &m.generics, num_rcvr_type_params),
+ // FIXME region param
+ ty_generics(ccx, &m.generics, num_rcvr_type_params),
transformed_self_ty,
fty,
m.explicit_self.node,
pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
let tcx = ccx.tcx;
- let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x);
- debug!("convert: item {} with id {} rp {:?}",
- tcx.sess.str_of(it.ident), it.id, rp);
+ debug!("convert: item {} with id {}", tcx.sess.str_of(it.ident), it.id);
match it.node {
- // These don't define types.
- ast::item_foreign_mod(_) | ast::item_mod(_) => {}
- ast::item_enum(ref enum_definition, ref generics) => {
- ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration");
- let tpt = ty_of_item(ccx, it);
- write_ty_to_tcx(tcx, it.id, tpt.ty);
- get_enum_variant_types(ccx,
- tpt.ty,
- enum_definition.variants,
- generics,
- rp);
- }
+ // These don't define types.
+ ast::item_foreign_mod(_) | ast::item_mod(_) => {}
+ ast::item_enum(ref enum_definition, ref generics) => {
+ ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration");
+ let tpt = ty_of_item(ccx, it);
+ write_ty_to_tcx(tcx, it.id, tpt.ty);
+ get_enum_variant_types(ccx,
+ tpt.ty,
+ enum_definition.variants,
+ generics);
+ }
ast::item_impl(ref generics, ref opt_trait_ref, ref selfty, ref ms) => {
- let i_ty_generics = ty_generics(ccx, rp, generics, 0);
- let region_parameterization =
- RegionParameterization::from_variance_and_generics(rp, generics);
- let selfty = ccx.to_ty(&TypeRscope(region_parameterization), selfty);
+ let i_ty_generics = ty_generics(ccx, generics, 0);
+ let selfty = ccx.to_ty(&ExplicitRscope, selfty);
write_ty_to_tcx(tcx, it.id, selfty);
tcx.tcache.insert(local_def(it.id),
ty_param_bounds_and_ty {
it.vis
};
- let cms = convert_methods(ccx,
- ImplContainer(local_def(it.id)),
- *ms,
- selfty,
- &i_ty_generics,
- generics,
- parent_visibility);
- for t in opt_trait_ref.iter() {
+ convert_methods(ccx,
+ ImplContainer(local_def(it.id)),
+ *ms,
+ selfty,
+ &i_ty_generics,
+ generics,
+ parent_visibility);
+
+ for trait_ref in opt_trait_ref.iter() {
+ let trait_ref = instantiate_trait_ref(ccx, trait_ref, selfty);
+
// Prevent the builtin kind traits from being manually implemented.
- let trait_def_id = ty::trait_ref_to_def_id(tcx, t);
- if tcx.lang_items.to_builtin_kind(trait_def_id).is_some() {
+ if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_some() {
tcx.sess.span_err(it.span,
"cannot provide an explicit implementation \
for a builtin kind");
}
}
ast::item_trait(ref generics, _, ref trait_methods) => {
- let _trait_def = trait_def_of_item(ccx, it);
+ let trait_def = trait_def_of_item(ccx, it);
// Run convert_methods on the provided methods.
let (_, provided_methods) =
split_trait_methods(*trait_methods);
let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id));
- let (ty_generics, _) = mk_item_substs(ccx, generics, rp,
- Some(untransformed_rcvr_ty));
- let _ = convert_methods(ccx,
- TraitContainer(local_def(it.id)),
- provided_methods,
- untransformed_rcvr_ty,
- &ty_generics,
- generics,
- it.vis);
+ convert_methods(ccx,
+ TraitContainer(local_def(it.id)),
+ provided_methods,
+ untransformed_rcvr_ty,
+ &trait_def.generics,
+ generics,
+ it.vis);
// We need to do this *after* converting methods, since
// convert_methods produces a tcache entry that is wrong for
write_ty_to_tcx(tcx, it.id, tpt.ty);
tcx.tcache.insert(local_def(it.id), tpt);
- convert_struct(ccx, rp, struct_def, generics, tpt, it.id);
+ convert_struct(ccx, struct_def, tpt, it.id);
}
ast::item_ty(_, ref generics) => {
ensure_no_ty_param_bounds(ccx, it.span, generics, "type");
}
pub fn convert_struct(ccx: &CrateCtxt,
- rp: Option<ty::region_variance>,
struct_def: &ast::struct_def,
- generics: &ast::Generics,
tpt: ty::ty_param_bounds_and_ty,
id: ast::NodeId) {
let tcx = ccx.tcx;
// Write the type of each of the members
for f in struct_def.fields.iter() {
- convert_field(ccx, rp, tpt.generics.type_param_defs, *f, generics);
+ convert_field(ccx, &tpt.generics, *f);
}
- let (_, substs) = mk_item_substs(ccx, generics, rp, None);
+ let substs = mk_item_substs(ccx, &tpt.generics, None);
let selfty = ty::mk_struct(tcx, local_def(id), substs);
// If this struct is enum-like or tuple-like, create the type of its
struct_def.fields.map(
|field| ccx.tcx.tcache.get(
&local_def(field.node.id)).ty);
- let ctor_fn_ty = ty::mk_ctor_fn(tcx, inputs, selfty);
+ let ctor_fn_ty = ty::mk_ctor_fn(tcx, ctor_id, inputs, selfty);
write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty);
tcx.tcache.insert(local_def(ctor_id), ty_param_bounds_and_ty {
generics: tpt.generics,
pub fn instantiate_trait_ref(ccx: &CrateCtxt,
ast_trait_ref: &ast::trait_ref,
- rp: Option<ty::region_variance>,
- generics: &ast::Generics,
self_ty: ty::t) -> @ty::TraitRef
{
/*!
* trait. Fails if the type is a type other than an trait type.
*/
- let rp = RegionParameterization::from_variance_and_generics(rp, generics);
-
- let rscope = TypeRscope(rp);
+ let rscope = ExplicitRscope; // FIXME
match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) {
ast::DefTrait(trait_did) => {
Some(&def) => return def,
_ => {}
}
- let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x);
match it.node {
ast::item_trait(ref generics, ref supertraits, _) => {
let self_ty = ty::mk_self(tcx, def_id);
- let (ty_generics, substs) = mk_item_substs(ccx, generics, rp,
- Some(self_ty));
- let bounds = ensure_supertraits(ccx, it.id, it.span, rp,
- *supertraits, generics);
+ let ty_generics = ty_generics(ccx, generics, 0);
+ let substs = mk_item_substs(ccx, &ty_generics, Some(self_ty));
+ let bounds = ensure_supertraits(ccx, it.id, it.span, *supertraits);
let trait_ref = @ty::TraitRef {def_id: def_id,
substs: substs};
let trait_def = @ty::TraitDef {generics: ty_generics,
}
pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::item)
- -> ty::ty_param_bounds_and_ty {
+ -> ty::ty_param_bounds_and_ty {
let def_id = local_def(it.id);
let tcx = ccx.tcx;
match tcx.tcache.find(&def_id) {
- Some(&tpt) => return tpt,
- _ => {}
+ Some(&tpt) => return tpt,
+ _ => {}
}
- let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x);
match it.node {
- ast::item_static(ref t, _, _) => {
- let typ = ccx.to_ty(&EmptyRscope, t);
- let tpt = no_params(typ);
- tcx.tcache.insert(local_def(it.id), tpt);
- return tpt;
- }
- ast::item_fn(ref decl, purity, abi, ref generics, _) => {
- assert!(rp.is_none());
- let ty_generics = ty_generics(ccx, None, generics, 0);
- let tofd = astconv::ty_of_bare_fn(ccx,
- &EmptyRscope,
- purity,
- abi,
- &generics.lifetimes,
- decl);
- let tpt = ty_param_bounds_and_ty {
- generics: ty::Generics {
- type_param_defs: ty_generics.type_param_defs,
- region_param: None
- },
- ty: ty::mk_bare_fn(ccx.tcx, tofd)
- };
- debug!("type of {} (id {}) is {}",
- tcx.sess.str_of(it.ident),
- it.id,
- ppaux::ty_to_str(tcx, tpt.ty));
- ccx.tcx.tcache.insert(local_def(it.id), tpt);
- return tpt;
- }
- ast::item_ty(ref t, ref generics) => {
- match tcx.tcache.find(&local_def(it.id)) {
- Some(&tpt) => return tpt,
- None => { }
+ ast::item_static(ref t, _, _) => {
+ let typ = ccx.to_ty(&ExplicitRscope, t);
+ let tpt = no_params(typ);
+ tcx.tcache.insert(local_def(it.id), tpt);
+ return tpt;
}
-
- let rp = tcx.region_paramd_items.find(&it.id).map(|x| *x);
- let region_parameterization =
- RegionParameterization::from_variance_and_generics(rp, generics);
- let tpt = {
- let ty = ccx.to_ty(&TypeRscope(region_parameterization), t);
- ty_param_bounds_and_ty {
- generics: ty_generics(ccx, rp, generics, 0),
- ty: ty
+ ast::item_fn(ref decl, purity, abi, ref generics, _) => {
+ let ty_generics = ty_generics(ccx, generics, 0);
+ let tofd = astconv::ty_of_bare_fn(ccx,
+ it.id,
+ purity,
+ abi,
+ decl);
+ let tpt = ty_param_bounds_and_ty {
+ generics: ty::Generics {
+ type_param_defs: ty_generics.type_param_defs,
+ region_param_defs: @[],
+ },
+ ty: ty::mk_bare_fn(ccx.tcx, tofd)
+ };
+ debug!("type of {} (id {}) is {}",
+ tcx.sess.str_of(it.ident),
+ it.id,
+ ppaux::ty_to_str(tcx, tpt.ty));
+ ccx.tcx.tcache.insert(local_def(it.id), tpt);
+ return tpt;
+ }
+ ast::item_ty(ref t, ref generics) => {
+ match tcx.tcache.find(&local_def(it.id)) {
+ Some(&tpt) => return tpt,
+ None => { }
}
- };
- tcx.tcache.insert(local_def(it.id), tpt);
- return tpt;
- }
- ast::item_enum(_, ref generics) => {
- // Create a new generic polytype.
- let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None);
- let t = ty::mk_enum(tcx, local_def(it.id), substs);
- let tpt = ty_param_bounds_and_ty {
- generics: ty_generics,
- ty: t
- };
- tcx.tcache.insert(local_def(it.id), tpt);
- return tpt;
- }
- ast::item_trait(*) => {
- tcx.sess.span_bug(
- it.span,
- format!("Invoked ty_of_item on trait"));
- }
- ast::item_struct(_, ref generics) => {
- let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None);
- let t = ty::mk_struct(tcx, local_def(it.id), substs);
- let tpt = ty_param_bounds_and_ty {
- generics: ty_generics,
- ty: t
- };
- tcx.tcache.insert(local_def(it.id), tpt);
- return tpt;
- }
- ast::item_impl(*) | ast::item_mod(_) |
- ast::item_foreign_mod(_) => fail!(),
- ast::item_mac(*) => fail!("item macros unimplemented")
+ let tpt = {
+ let ty = ccx.to_ty(&ExplicitRscope, t);
+ ty_param_bounds_and_ty {
+ generics: ty_generics(ccx, generics, 0),
+ ty: ty
+ }
+ };
+
+ tcx.tcache.insert(local_def(it.id), tpt);
+ return tpt;
+ }
+ ast::item_enum(_, ref generics) => {
+ // Create a new generic polytype.
+ let ty_generics = ty_generics(ccx, generics, 0);
+ let substs = mk_item_substs(ccx, &ty_generics, None);
+ let t = ty::mk_enum(tcx, local_def(it.id), substs);
+ let tpt = ty_param_bounds_and_ty {
+ generics: ty_generics,
+ ty: t
+ };
+ tcx.tcache.insert(local_def(it.id), tpt);
+ return tpt;
+ }
+ ast::item_trait(*) => {
+ tcx.sess.span_bug(
+ it.span,
+ format!("Invoked ty_of_item on trait"));
+ }
+ ast::item_struct(_, ref generics) => {
+ let ty_generics = ty_generics(ccx, generics, 0);
+ let substs = mk_item_substs(ccx, &ty_generics, None);
+ let t = ty::mk_struct(tcx, local_def(it.id), substs);
+ let tpt = ty_param_bounds_and_ty {
+ generics: ty_generics,
+ ty: t
+ };
+ tcx.tcache.insert(local_def(it.id), tpt);
+ return tpt;
+ }
+ ast::item_impl(*) | ast::item_mod(_) |
+ ast::item_foreign_mod(_) => fail!(),
+ ast::item_mac(*) => fail!("item macros unimplemented")
}
}
ty::ty_param_bounds_and_ty {
generics: ty::Generics {
type_param_defs: @~[],
- region_param: None,
+ region_param_defs: @[],
},
- ty: ast_ty_to_ty(ccx, &EmptyRscope, t)
+ ty: ast_ty_to_ty(ccx, &ExplicitRscope, t)
}
}
}
}
pub fn ty_generics(ccx: &CrateCtxt,
- rp: Option<ty::region_variance>,
generics: &ast::Generics,
base_index: uint) -> ty::Generics {
return ty::Generics {
- region_param: rp,
+ region_param_defs: generics.lifetimes.iter().map(|l| {
+ ty::RegionParameterDef { ident: l.ident,
+ def_id: local_def(l.id) }
+ }).collect(),
type_param_defs: @generics.ty_params.mapi_to_vec(|offset, param| {
match ccx.tcx.ty_param_defs.find(¶m.id) {
Some(&def) => def,
None => {
let param_ty = ty::param_ty {idx: base_index + offset,
def_id: local_def(param.id)};
- let bounds = @compute_bounds(ccx, rp, generics,
- param_ty, ¶m.bounds);
+ let bounds = @compute_bounds(ccx, param_ty, ¶m.bounds);
let def = ty::TypeParameterDef {
ident: param.ident,
def_id: local_def(param.id),
fn compute_bounds(
ccx: &CrateCtxt,
- rp: Option<ty::region_variance>,
- generics: &ast::Generics,
param_ty: ty::param_ty,
ast_bounds: &OptVec<ast::TyParamBound>) -> ty::ParamBounds
{
/*!
- *
* Translate the AST's notion of ty param bounds (which are an
* enum consisting of a newtyped Ty or a region) to ty's
* notion of ty param bounds, which can either be user-defined
match *ast_bound {
TraitTyParamBound(ref b) => {
let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id);
- let trait_ref = instantiate_trait_ref(ccx, b, rp, generics, ty);
+ let trait_ref = instantiate_trait_ref(ccx, b, ty);
if !ty::try_add_builtin_trait(
ccx.tcx, trait_ref.def_id,
&mut param_bounds.builtin_bounds)
ast_generics: &ast::Generics,
abis: AbiSet)
-> ty::ty_param_bounds_and_ty {
- let ty_generics = ty_generics(ccx, None, ast_generics, 0);
- let region_param_names = RegionParamNames::from_generics(ast_generics);
- let rb = in_binding_rscope(&EmptyRscope, region_param_names);
+ let ty_generics = ty_generics(ccx, ast_generics, 0);
+ let rb = BindingRscope::new(def_id.node);
let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, &rb, a, None) );
let output_ty = ast_ty_to_ty(ccx, &rb, &decl.output);
ty::BareFnTy {
abis: abis,
purity: ast::unsafe_fn,
- sig: ty::FnSig {
- bound_lifetime_names: opt_vec::Empty,
- inputs: input_tys,
- output: output_ty,
- variadic: decl.variadic
- }
+ sig: ty::FnSig {binder_id: def_id.node,
+ inputs: input_tys,
+ output: output_ty,
+ variadic: decl.variadic}
});
let tpt = ty_param_bounds_and_ty {
generics: ty_generics,
}
pub fn mk_item_substs(ccx: &CrateCtxt,
- ast_generics: &ast::Generics,
- rp: Option<ty::region_variance>,
- self_ty: Option<ty::t>) -> (ty::Generics, ty::substs)
+ ty_generics: &ty::Generics,
+ self_ty: Option<ty::t>) -> ty::substs
{
- let mut i = 0;
- let ty_generics = ty_generics(ccx, rp, ast_generics, 0);
- let params = ast_generics.ty_params.map_to_vec(|atp| {
- let t = ty::mk_param(ccx.tcx, i, local_def(atp.id));
- i += 1u;
- t
- });
- let regions = rscope::bound_self_region(rp);
- (ty_generics, substs {regions: ty::NonerasedRegions(regions),
- self_ty: self_ty,
- tps: params})
+ let params: ~[ty::t] =
+ ty_generics.type_param_defs.iter().enumerate().map(
+ |(i, t)| ty::mk_param(ccx.tcx, i, t.def_id)).collect();
+
+ let regions: OptVec<ty::Region> =
+ ty_generics.region_param_defs.iter().enumerate().map(
+ |(i, l)| ty::re_type_bound(l.def_id.node, i, l.ident)).collect();
+
+ substs {regions: ty::NonerasedRegions(regions),
+ self_ty: self_ty,
+ tps: params}
}
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) |
unify_float_variable(this, !this.a_is_expected(), v_id, v)
}
+ (&ty::ty_char, _) |
(&ty::ty_nil, _) |
(&ty::ty_bool, _) |
(&ty::ty_int(_), _) |
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 {
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));
fold_regions_in_sig(
self.infcx.tcx,
&sig0,
- |r, _in_fn| generalize_region(self, snapshot,
- new_vars, a_isr, a_vars, b_vars,
- r));
+ |r| generalize_region(self, snapshot,
+ new_vars, sig0.binder_id,
+ &a_map, a_vars, b_vars,
+ r));
debug!("sig1 = {}", sig1.inf_str(self.infcx));
return Ok(sig1);
fn generalize_region(this: &Glb,
snapshot: uint,
new_vars: &[RegionVid],
- a_isr: isr_alist,
+ new_binder_id: NodeId,
+ a_map: &HashMap<ty::bound_region, ty::Region>,
a_vars: &[RegionVid],
b_vars: &[RegionVid],
r0: ty::Region) -> ty::Region {
if !is_var_in_set(new_vars, r0) {
+ assert!(!r0.is_bound());
return r0;
}
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);
}
}
}
- // NB---I do not believe this algorithm computes
- // (necessarily) the GLB. As written it can
- // spuriously fail. In particular, if there is a case
- // like: &fn(fn(&a)) and fn(fn(&b)), where a and b are
- // free, it will return fn(&c) where c = GLB(a,b). If
- // however this GLB is not defined, then the result is
- // an error, even though something like
- // "fn<X>(fn(&X))" where X is bound would be a
- // subtype of both of those.
- //
- // The problem is that if we were to return a bound
- // variable, we'd be computing a lower-bound, but not
- // necessarily the *greatest* lower-bound.
+ // NB---I do not believe this algorithm computes
+ // (necessarily) the GLB. As written it can
+ // spuriously fail. In particular, if there is a case
+ // like: &fn(fn(&a)) and fn(fn(&b)), where a and b are
+ // free, it will return fn(&c) where c = GLB(a,b). If
+ // however this GLB is not defined, then the result is
+ // an error, even though something like
+ // "fn<X>(fn(&X))" where X is bound would be a
+ // subtype of both of those.
+ //
+ // The problem is that if we were to return a bound
+ // variable, we'd be computing a lower-bound, but not
+ // necessarily the *greatest* lower-bound.
+ //
+ // Unfortunately, this problem is non-trivial to solve,
+ // because we do not know at the time of computing the GLB
+ // whether a GLB(a,b) exists or not, because we haven't
+ // run region inference (or indeed, even fully computed
+ // the region hierarchy!). The current algorithm seems to
+ // works ok in practice.
if a_r.is_some() && b_r.is_some() && only_new_vars {
// Related to exactly one bound variable from each fn:
- return rev_lookup(this, a_isr, a_r.unwrap());
+ return rev_lookup(this, a_map, new_binder_id, a_r.unwrap());
} else if a_r.is_none() && b_r.is_none() {
// Not related to bound variables from either fn:
+ assert!(!r0.is_bound());
return r0;
} else {
// Other:
- return fresh_bound_variable(this);
+ return fresh_bound_variable(this, new_binder_id);
}
}
fn rev_lookup(this: &Glb,
- a_isr: isr_alist,
+ a_map: &HashMap<ty::bound_region, ty::Region>,
+ new_binder_id: NodeId,
r: ty::Region) -> ty::Region
{
- let mut ret = None;
- do list::each(a_isr) |pair| {
- let (a_br, a_r) = *pair;
- if a_r == r {
- ret = Some(ty::re_bound(a_br));
- false
- } else {
- true
+ for (a_br, a_r) in a_map.iter() {
+ if *a_r == r {
+ return ty::re_fn_bound(new_binder_id, *a_br);
}
- };
-
- match ret {
- Some(x) => x,
- None => this.infcx.tcx.sess.span_bug(
- this.trace.origin.span(),
- format!("could not find original bound region for {:?}", r))
}
+ this.infcx.tcx.sess.span_bug(
+ this.trace.origin.span(),
+ format!("could not find original bound region for {:?}", r))
}
- fn fresh_bound_variable(this: &Glb) -> ty::Region {
- this.infcx.region_vars.new_bound()
+ fn fresh_bound_variable(this: &Glb, binder_id: NodeId) -> ty::Region {
+ this.infcx.region_vars.new_bound(binder_id)
}
}
}
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;
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>;
}
}
-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);
// Random utility functions used by LUB/GLB when computing LUB/GLB of
// fn types
-pub fn var_ids<T:Combine>(this: &T, isr: isr_alist) -> ~[RegionVid] {
- let mut result = ~[];
- do list::each(isr) |pair| {
- match pair.second() {
- ty::re_infer(ty::ReVar(r)) => { result.push(r); }
+pub fn var_ids<T:Combine>(this: &T,
+ map: &HashMap<ty::bound_region, ty::Region>)
+ -> ~[RegionVid] {
+ map.iter().map(|(_, r)| match *r {
+ ty::re_infer(ty::ReVar(r)) => { r }
r => {
this.infcx().tcx.sess.span_bug(
this.trace().origin.span(),
format!("Found non-region-vid: {:?}", r));
}
- }
- true
- };
- result
+ }).collect()
}
pub fn is_var_in_set(new_vars: &[RegionVid], r: ty::Region) -> bool {
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
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, _) =
fold_regions_in_sig(
self.infcx.tcx,
&sig0,
- |r, _in_fn| generalize_region(self, snapshot, new_vars,
- a_isr, r));
+ |r| generalize_region(self, snapshot, new_vars,
+ sig0.binder_id, &a_map, r));
return Ok(sig1);
fn generalize_region(this: &Lub,
snapshot: uint,
new_vars: &[RegionVid],
- a_isr: isr_alist,
- r0: ty::Region) -> ty::Region {
+ new_scope: NodeId,
+ a_map: &HashMap<ty::bound_region, ty::Region>,
+ r0: ty::Region)
+ -> ty::Region {
// Regions that pre-dated the LUB computation stay as they are.
if !is_var_in_set(new_vars, r0) {
+ assert!(!r0.is_bound());
debug!("generalize_region(r0={:?}): not new variable", r0);
return r0;
}
debug!("generalize_region(r0={:?}): \
non-new-variables found in {:?}",
r0, tainted);
+ assert!(!r0.is_bound());
return r0;
}
// in both A and B. Replace the variable with the "first"
// bound region from A that we find it to be associated
// with.
- let mut ret = None;
- do list::each(a_isr) |pair| {
- let (a_br, a_r) = *pair;
- if tainted.iter().any(|x| x == &a_r) {
+ for (a_br, a_r) in a_map.iter() {
+ if tainted.iter().any(|x| x == a_r) {
debug!("generalize_region(r0={:?}): \
replacing with {:?}, tainted={:?}",
- r0, a_br, tainted);
- ret = Some(ty::re_bound(a_br));
- false
- } else {
- true
+ r0, *a_br, tainted);
+ return ty::re_fn_bound(new_scope, *a_br);
}
- };
-
- match ret {
- Some(x) => x,
- None => this.infcx.tcx.sess.span_bug(
- this.trace.origin.span(),
- format!("Region {:?} is not associated with \
- any bound region from A!", r0))
}
+
+ this.infcx.tcx.sess.span_bug(
+ this.trace.origin.span(),
+ format!("Region {:?} is not associated with \
+ any bound region from A!", r0))
}
}
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};
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;
BoundRegionInTypeOrImpl(Span),
BoundRegionInCoherence,
-
- BoundRegionError(Span),
}
pub enum fixup_err {
/// 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
ty::re_infer(ty::ReVar(self.region_vars.new_region_var(origin)))
}
+ pub fn next_region_vars(&mut self,
+ origin: RegionVariableOrigin,
+ count: uint)
+ -> ~[ty::Region] {
+ vec::from_fn(count, |_| self.next_region_var(origin))
+ }
+
+ pub fn fresh_bound_region(&mut self, binder_id: ast::NodeId) -> ty::Region {
+ self.region_vars.new_bound(binder_id)
+ }
+
pub fn resolve_regions(@mut self) {
let errors = self.region_vars.resolve_regions();
self.report_region_errors(&errors); // see error_reporting.rs
pub fn replace_bound_regions_with_fresh_regions(&mut self,
trace: TypeTrace,
fsig: &ty::FnSig)
- -> (ty::FnSig, isr_alist) {
- let(isr, _, fn_sig) =
- replace_bound_regions_in_fn_sig(self.tcx, @Nil, None, fsig, |br| {
+ -> (ty::FnSig,
+ HashMap<ty::bound_region,
+ ty::Region>) {
+ let (map, _, fn_sig) =
+ replace_bound_regions_in_fn_sig(self.tcx, None, fsig, |br| {
let rvar = self.next_region_var(
BoundRegionInFnType(trace.origin.span(), br));
debug!("Bound region {} maps to {:?}",
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 {
BoundRegionInFnType(a, _) => a,
BoundRegionInTypeOrImpl(a) => a,
BoundRegionInCoherence => codemap::dummy_sp(),
- BoundRegionError(a) => a,
}
}
}
BoundRegionInTypeOrImpl(a) => format!("BoundRegionInTypeOrImpl({})",
a.repr(tcx)),
BoundRegionInCoherence => format!("BoundRegionInCoherence"),
- BoundRegionError(a) => format!("BoundRegionError({})", a.repr(tcx)),
}
}
}
use middle::ty;
use middle::ty::{FreeRegion, Region, RegionVid};
-use middle::ty::{re_empty, re_static, re_infer, re_free, re_bound};
+use middle::ty::{re_empty, re_static, re_infer, re_free, re_type_bound,
+ re_fn_bound};
use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh};
use middle::typeck::infer::cres;
use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin};
re_infer(ReSkolemized(sc, br))
}
- pub fn new_bound(&mut self) -> Region {
+ pub fn new_bound(&mut self, binder_id: ast::NodeId) -> Region {
// Creates a fresh bound variable for use in GLB computations.
// See discussion of GLB computation in the large comment at
// the top of this file for more details.
//
- // This computation is mildly wrong in the face of rollover.
- // It's conceivable, if unlikely, that one might wind up with
- // accidental capture for nested functions in that case, if
- // the outer function had bound regions created a very long
- // time before and the inner function somehow wound up rolling
- // over such that supposedly fresh identifiers were in fact
- // shadowed. We should convert our bound_region
- // representation to use deBruijn indices or something like
- // that to eliminate that possibility.
+ // This computation is potentially wrong in the face of
+ // rollover. It's conceivable, if unlikely, that one might
+ // wind up with accidental capture for nested functions in
+ // that case, if the outer function had bound regions created
+ // a very long time before and the inner function somehow
+ // wound up rolling over such that supposedly fresh
+ // identifiers were in fact shadowed. For now, we just assert
+ // that there is no rollover -- eventually we should try to be
+ // robust against this possibility, either by checking the set
+ // of bound identifiers that appear in a given expression and
+ // ensure that we generate one that is distinct, or by
+ // changing the representation of bound regions in a fn
+ // declaration
let sc = self.bound_count;
self.bound_count += 1;
- re_bound(br_fresh(sc))
+
+ if sc >= self.bound_count {
+ self.tcx.sess.bug("Rollover in RegionInference new_bound()");
+ }
+
+ re_fn_bound(binder_id, br_fresh(sc))
}
pub fn add_constraint(&mut self,
debug!("RegionVarBindings: make_subregion({:?}, {:?})", sub, sup);
match (sub, sup) {
+ (re_type_bound(*), _) |
+ (re_fn_bound(*), _) |
+ (_, re_type_bound(*)) |
+ (_, re_fn_bound(*)) => {
+ self.tcx.sess.span_bug(
+ origin.span(),
+ format!("Cannot relate bound region: {} <= {}",
+ sub.repr(self.tcx),
+ sup.repr(self.tcx)));
+ }
(re_infer(ReVar(sub_id)), re_infer(ReVar(sup_id))) => {
self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin);
}
(re_infer(ReVar(sub_id)), r) => {
self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
}
- (re_bound(br), _) => {
- self.tcx.sess.span_bug(
- origin.span(),
- format!("Cannot relate bound region as subregion: {:?}", br));
- }
- (_, re_bound(br)) => {
- self.tcx.sess.span_bug(
- origin.span(),
- format!("Cannot relate bound region as superregion: {:?}", br));
- }
_ => {
self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
}
fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
match (a, b) {
+ (re_fn_bound(*), _) |
+ (_, re_fn_bound(*)) |
+ (re_type_bound(*), _) |
+ (_, re_type_bound(*)) => {
+ self.tcx.sess.bug(
+ format!("Cannot relate bound region: LUB({}, {})",
+ a.repr(self.tcx),
+ b.repr(self.tcx)));
+ }
+
(re_static, _) | (_, re_static) => {
re_static // nothing lives longer than static
}
// For these types, we cannot define any additional
// relationship:
(re_infer(ReSkolemized(*)), _) |
- (_, re_infer(ReSkolemized(*))) |
- (re_bound(_), re_bound(_)) |
- (re_bound(_), re_free(_)) |
- (re_bound(_), re_scope(_)) |
- (re_free(_), re_bound(_)) |
- (re_scope(_), re_bound(_)) => {
+ (_, re_infer(ReSkolemized(*))) => {
if a == b {a} else {re_static}
}
}
-> cres<Region> {
debug!("glb_concrete_regions({:?}, {:?})", a, b);
match (a, b) {
+ (re_fn_bound(*), _) |
+ (_, re_fn_bound(*)) |
+ (re_type_bound(*), _) |
+ (_, re_type_bound(*)) => {
+ self.tcx.sess.bug(
+ format!("Cannot relate bound region: GLB({}, {})",
+ a.repr(self.tcx),
+ b.repr(self.tcx)));
+ }
+
(re_static, r) | (r, re_static) => {
// static lives longer than everything else
Ok(r)
// For these types, we cannot define any additional
// relationship:
(re_infer(ReSkolemized(*)), _) |
- (_, re_infer(ReSkolemized(*))) |
- (re_bound(_), re_bound(_)) |
- (re_bound(_), re_free(_)) |
- (re_bound(_), re_scope(_)) |
- (re_free(_), re_bound(_)) |
- (re_scope(_), re_bound(_)) => {
+ (_, re_infer(ReSkolemized(*))) => {
if a == b {
Ok(a)
} else {
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;
}
}
+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
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
}
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
// 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),
// 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
// 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);
}
}
use syntax::codemap::Span;
use syntax::print::pprust::*;
use syntax::{ast, ast_map, abi};
-use syntax::opt_vec;
pub mod check;
pub mod rscope;
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
}
}
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
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()))
use metadata::encoder;
use middle::ty::{ReSkolemized, ReVar};
-use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid};
+use middle::ty::{bound_region, br_anon, br_named};
use middle::ty::{br_fresh, ctxt, field};
use middle::ty::{mt, t, param_ty};
-use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region,
+use middle::ty::{re_free, re_scope, re_infer, re_static, Region,
re_empty};
use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure};
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)
// I believe these cases should not occur (except when debugging,
// perhaps)
- re_infer(_) | re_bound(_) => {
+ ty::re_infer(_) | ty::re_type_bound(*) | ty::re_fn_bound(*) => {
(format!("lifetime {:?}", region), None)
}
};
br: bound_region) -> ~str {
let space_str = if space { " " } else { "" };
- if cx.sess.verbose() { return format!("{}{:?}{}", prefix, br, space_str); }
+ if cx.sess.verbose() {
+ return format!("{}{}{}", prefix, br.repr(cx), space_str);
+ }
match br {
- br_named(id) => format!("{}'{}{}", prefix, cx.sess.str_of(id), space_str),
- br_self => format!("{}'self{}", prefix, space_str),
+ br_named(_, ident) => format!("{}'{}{}", prefix,
+ cx.sess.str_of(ident), space_str),
br_anon(_) => prefix.to_str(),
br_fresh(_) => prefix.to_str(),
- br_cap_avoid(_, br) => bound_region_to_str(cx, prefix, space, *br)
}
}
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
// to fit that into a short string. Hence the recommendation to use
// `explain_region()` or `note_and_explain_region()`.
match region {
- re_scope(_) => prefix.to_str(),
- re_bound(br) => bound_region_to_str(cx, prefix, space, br),
- re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region),
- re_infer(ReSkolemized(_, br)) => {
+ ty::re_scope(_) => prefix.to_str(),
+ ty::re_type_bound(_, _, ident) => cx.sess.str_of(ident).to_owned(),
+ ty::re_fn_bound(_, br) => bound_region_to_str(cx, prefix, space, br),
+ ty::re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region),
+ ty::re_infer(ReSkolemized(_, br)) => {
bound_region_to_str(cx, prefix, space, br)
}
- re_infer(ReVar(_)) => prefix.to_str(),
- re_static => format!("{}'static{}", prefix, space_str),
- re_empty => format!("{}'<empty>{}", prefix, space_str)
+ ty::re_infer(ReVar(_)) => prefix.to_str(),
+ ty::re_static => format!("{}'static{}", prefix, space_str),
+ ty::re_empty => format!("{}'<empty>{}", prefix, space_str)
}
}
}
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 {
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)
}
}
}
}
+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({}: {})",
impl Repr for ty::bound_region {
fn repr(&self, tcx: ctxt) -> ~str {
- bound_region_ptr_to_str(tcx, *self)
+ match *self {
+ ty::br_anon(id) => format!("br_anon({})", id),
+ ty::br_named(id, ident) => format!("br_named({}, {})",
+ id.repr(tcx),
+ ident.repr(tcx)),
+ ty::br_fresh(id) => format!("br_fresh({})", id),
+ }
}
}
impl Repr for ty::Region {
fn repr(&self, tcx: ctxt) -> ~str {
- region_to_str(tcx, "", false, *self)
+ match *self {
+ ty::re_type_bound(id, index, ident) => {
+ format!("re_type_bound({}, {}, {})",
+ id, index, ident.repr(tcx))
+ }
+
+ ty::re_fn_bound(binder_id, ref bound_region) => {
+ format!("re_fn_bound({}, {})",
+ binder_id, bound_region.repr(tcx))
+ }
+
+ ty::re_free(ref fr) => {
+ format!("re_free({}, {})",
+ fr.scope_id,
+ fr.bound_region.repr(tcx))
+ }
+
+ ty::re_scope(id) => {
+ format!("re_scope({})", id)
+ }
+
+ ty::re_static => {
+ format!("re_static")
+ }
+
+ ty::re_infer(ReVar(ref vid)) => {
+ format!("re_infer({})", vid.id)
+ }
+
+ ty::re_infer(ReSkolemized(id, ref bound_region)) => {
+ format!("re_skolemized({}, {})",
+ id, bound_region.repr(tcx))
+ }
+
+ ty::re_empty => {
+ format!("re_empty")
+ }
+ }
}
}
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))
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct PathSegment {
name: ~str,
- lifetime: Option<Lifetime>,
+ lifetimes: ~[Lifetime],
types: ~[Type],
}
fn clean(&self) -> PathSegment {
PathSegment {
name: self.identifier.clean(),
- lifetime: self.lifetime.clean(),
+ lifetimes: self.lifetimes.clean(),
types: self.types.clean()
}
}
if i > 0 { f.buf.write("::".as_bytes()) }
f.buf.write(seg.name.as_bytes());
- if seg.lifetime.is_some() || seg.types.len() > 0 {
+ if seg.lifetimes.len() > 0 || seg.types.len() > 0 {
f.buf.write("<".as_bytes());
- match seg.lifetime {
- Some(ref lifetime) => write!(f.buf, "{}", *lifetime),
- None => {}
+ let mut comma = false;
+ for lifetime in seg.lifetimes.iter() {
+ if comma { f.buf.write(", ".as_bytes()); }
+ comma = true;
+ write!(f.buf, "{}", *lifetime);
}
- for (i, ty) in seg.types.iter().enumerate() {
- if i > 0 || seg.lifetime.is_some() {
- f.buf.write(", ".as_bytes());
- }
+ for ty in seg.types.iter() {
+ if comma { f.buf.write(", ".as_bytes()); }
+ comma = true;
write!(f.buf, "{}", *ty);
}
f.buf.write(">".as_bytes());
// The generics will get written to both the title and link
let mut generics = ~"";
let last = path.segments.last();
- if last.lifetime.is_some() || last.types.len() > 0 {
+ if last.lifetimes.len() > 0 || last.types.len() > 0 {
+ let mut counter = 0;
generics.push_str("<");
- match last.lifetime {
- Some(ref lifetime) => generics.push_str(format!("{}", *lifetime)),
- None => {}
+ for lifetime in last.lifetimes.iter() {
+ if counter > 0 { generics.push_str(", "); }
+ counter += 1;
+ generics.push_str(format!("{}", *lifetime));
}
- for (i, ty) in last.types.iter().enumerate() {
- if i > 0 || last.lifetime.is_some() {
- generics.push_str(", ");
- }
+ for ty in last.types.iter() {
+ if counter > 0 { generics.push_str(", "); }
+ counter += 1;
generics.push_str(format!("{}", *ty));
}
generics.push_str(">");
global: false,
segments: ~[clean::PathSegment {
name: v.name.clone(),
- lifetime: None,
+ lifetimes: ~[],
types: ~[],
}]
};
use clone::Clone;
use container::Container;
-use iter::Iterator;
+use iter::{Iterator, FromIterator};
use option::{Option, Some, None};
use mem;
use unstable::raw::Repr;
}
}
+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 {
// 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 {
/// 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;
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>,
}
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,
_ => 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))
+ }
+ }
+}
segments: ~[
ast::PathSegment {
identifier: identifier,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
],
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;
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() {
fn path_all(&self, sp: Span,
global: bool,
idents: ~[ast::Ident],
- rp: Option<ast::Lifetime>,
+ lifetimes: OptVec<ast::Lifetime>,
types: ~[ast::Ty])
-> ast::Path;
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();
.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 {
self.ident_of("option"),
self.ident_of("Option")
],
- None,
+ opt_vec::Empty,
~[ ty ]), None)
}
segments: ~[
ast::PathSegment {
identifier: res,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
]
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(
use ext::base::ExtCtxt;
use ext::build::{AstBuilder};
use ext::deriving::generic::*;
+use opt_vec;
pub fn expand_deriving_rand(cx: @ExtCtxt,
span: Span,
let rand_name = cx.path_all(span,
true,
rand_ident.clone(),
- None,
+ opt_vec::Empty,
~[]);
let rand_name = cx.expr_path(rand_name);
use ext::build::AstBuilder;
use codemap::{Span,respan};
use opt_vec;
+use opt_vec::OptVec;
/// The types of pointers
pub enum PtrTy<'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)
}
}
+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,
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) => {
segments: ~[
ast::PathSegment {
identifier: ident,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
],
segments: [
ast::PathSegment {
identifier: id,
- lifetime: _,
+ lifetimes: _,
types: _
}
]
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;
sp,
true,
rtpath("Method"),
- Some(life),
+ opt_vec::with(life),
~[]
), None);
let st = ast::item_static(ty, ast::MutImmutable, method);
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(
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),
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),
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)),
})
}
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*/
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)}
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),
}
}
}
}
+
+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
+ }
+}
segments: ~[
ast::PathSegment {
identifier: str_to_ident("a"),
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
],
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,
}
]
segments: ~[
ast::PathSegment {
identifier: str_to_ident("d"),
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
],
segments: ~[
ast::PathSegment {
identifier: str_to_ident("b"),
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
],
segments: ~[
ast::PathSegment {
identifier: str_to_ident("b"),
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
],
ast::PathSegment {
identifier:
str_to_ident("int"),
- 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,
}
],
identifier:
str_to_ident(
"b"),
- lifetime:
- None,
+ lifetimes:
+ opt_vec::Empty,
types:
opt_vec::Empty
}
segments.push(PathSegmentAndBoundSet {
segment: ast::PathSegment {
identifier: identifier,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
},
bound_set: bound_set
}
// 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
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
};
}
segments: path.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
}).collect()
segments: path.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
}).collect()
segments: path.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
}).collect()
segments: path.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
- lifetime: None,
+ lifetimes: opt_vec::Empty,
types: opt_vec::Empty,
}
}).collect()
}
}
- if segment.lifetime.is_some() || !segment.types.is_empty() {
+ if !segment.lifetimes.is_empty() || !segment.types.is_empty() {
if colons_before_params {
word(s.s, "::")
}
word(s.s, "<");
- for lifetime in segment.lifetime.iter() {
+ for lifetime in segment.lifetimes.iter() {
print_lifetime(s, lifetime);
if !segment.types.is_empty() {
word_space(s, ",")
pub fn print_view_path(s: @ps, vp: &ast::view_path) {
match vp.node {
ast::view_path_simple(ident, ref path, _) => {
- if path.segments.last().identifier != ident {
+ // FIXME can't compare identifiers directly here
+ if path.segments.last().identifier.name != ident.name {
print_ident(s, ident);
space(s.s);
word_space(s, "=");