Introduce VecPerParamSpace and use it to represent sets of types and

parameters

This involves numerous substeps:

1. Treat Self same as any other parameter.
2. No longer compute offsets for method parameters.
3. Store all generic types (both trait/impl and method) with a method,
   eliminating odd discrepancies.
4. Stop doing unspeakable things to static methods and instead just use
   the natural types, now that we can easily add the type parameters from
   trait into the method's polytype.
5. No doubt some more. It was hard to separate these into distinct commits.

Fixes #13564
This commit is contained in:
Niko Matsakis 2014-05-31 18:53:13 -04:00
parent 0422934e24
commit 9153d8ad6c
49 changed files with 2577 additions and 2232 deletions

View file

@ -189,9 +189,7 @@ pub static tag_impls_impl: uint = 0x81;
pub static tag_items_data_item_inherent_impl: uint = 0x82; pub static tag_items_data_item_inherent_impl: uint = 0x82;
pub static tag_items_data_item_extension_impl: uint = 0x83; pub static tag_items_data_item_extension_impl: uint = 0x83;
pub static tag_region_param_def: uint = 0x84; // GAP 0x84, 0x85, 0x86
pub static tag_region_param_def_ident: uint = 0x85;
pub static tag_region_param_def_def_id: uint = 0x86;
pub static tag_native_libraries: uint = 0x87; pub static tag_native_libraries: uint = 0x87;
pub static tag_native_libraries_lib: uint = 0x88; pub static tag_native_libraries_lib: uint = 0x88;
@ -217,3 +215,9 @@ pub struct LinkMeta {
pub crateid: CrateId, pub crateid: CrateId,
pub crate_hash: Svh, pub crate_hash: Svh,
} }
pub static tag_region_param_def: uint = 0x90;
pub static tag_region_param_def_ident: uint = 0x91;
pub static tag_region_param_def_def_id: uint = 0x92;
pub static tag_region_param_def_space: uint = 0x93;
pub static tag_region_param_def_index: uint = 0x94;

View file

@ -18,6 +18,7 @@ use metadata::decoder;
use middle::lang_items; use middle::lang_items;
use middle::ty; use middle::ty;
use middle::typeck; use middle::typeck;
use middle::subst::VecPerParamSpace;
use serialize::ebml; use serialize::ebml;
use serialize::ebml::reader; use serialize::ebml::reader;
@ -223,8 +224,8 @@ pub fn get_field_type(tcx: &ty::ctxt, class_id: ast::DefId,
}); });
let ty = decoder::item_type(def, the_field, tcx, &*cdata); let ty = decoder::item_type(def, the_field, tcx, &*cdata);
ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty {
generics: ty::Generics {type_param_defs: Rc::new(Vec::new()), generics: ty::Generics {types: VecPerParamSpace::empty(),
region_param_defs: Rc::new(Vec::new())}, regions: VecPerParamSpace::empty()},
ty: ty ty: ty
} }
} }
@ -240,7 +241,8 @@ pub fn get_impl_trait(tcx: &ty::ctxt,
// Given a def_id for an impl, return information about its vtables // Given a def_id for an impl, return information about its vtables
pub fn get_impl_vtables(tcx: &ty::ctxt, pub fn get_impl_vtables(tcx: &ty::ctxt,
def: ast::DefId) -> typeck::impl_res { def: ast::DefId)
-> typeck::vtable_res {
let cstore = &tcx.sess.cstore; let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate); let cdata = cstore.get_crate_data(def.krate);
decoder::get_impl_vtables(&*cdata, def.node, tcx) decoder::get_impl_vtables(&*cdata, def.node, tcx)

View file

@ -23,6 +23,7 @@ use metadata::tydecode::{parse_ty_data, parse_def_id,
parse_bare_fn_ty_data, parse_trait_ref_data}; parse_bare_fn_ty_data, parse_trait_ref_data};
use middle::lang_items; use middle::lang_items;
use middle::def; use middle::def;
use middle::subst;
use middle::ty::{ImplContainer, TraitContainer}; use middle::ty::{ImplContainer, TraitContainer};
use middle::ty; use middle::ty;
use middle::typeck; use middle::typeck;
@ -257,21 +258,22 @@ fn item_ty_param_defs(item: ebml::Doc,
tcx: &ty::ctxt, tcx: &ty::ctxt,
cdata: Cmd, cdata: Cmd,
tag: uint) tag: uint)
-> Rc<Vec<ty::TypeParameterDef> > { -> subst::VecPerParamSpace<ty::TypeParameterDef> {
let mut bounds = Vec::new(); let mut bounds = subst::VecPerParamSpace::empty();
reader::tagged_docs(item, tag, |p| { reader::tagged_docs(item, tag, |p| {
let bd = parse_type_param_def_data( let bd = parse_type_param_def_data(
p.data, p.start, cdata.cnum, tcx, p.data, p.start, cdata.cnum, tcx,
|_, did| translate_def_id(cdata, did)); |_, did| translate_def_id(cdata, did));
bounds.push(bd); bounds.push(bd.space, bd);
true true
}); });
Rc::new(bounds) bounds
} }
fn item_region_param_defs(item_doc: ebml::Doc, cdata: Cmd) fn item_region_param_defs(item_doc: ebml::Doc, cdata: Cmd)
-> Rc<Vec<ty::RegionParameterDef> > { -> subst::VecPerParamSpace<ty::RegionParameterDef>
let mut v = Vec::new(); {
let mut v = subst::VecPerParamSpace::empty();
reader::tagged_docs(item_doc, tag_region_param_def, |rp_doc| { reader::tagged_docs(item_doc, tag_region_param_def, |rp_doc| {
let ident_str_doc = reader::get_doc(rp_doc, let ident_str_doc = reader::get_doc(rp_doc,
tag_region_param_def_ident); tag_region_param_def_ident);
@ -280,11 +282,20 @@ fn item_region_param_defs(item_doc: ebml::Doc, cdata: Cmd)
tag_region_param_def_def_id); tag_region_param_def_def_id);
let def_id = reader::with_doc_data(def_id_doc, parse_def_id); let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
let def_id = translate_def_id(cdata, def_id); let def_id = translate_def_id(cdata, def_id);
v.push(ty::RegionParameterDef { name: ident.name,
def_id: def_id }); let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint);
let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
let index = reader::doc_as_u64(doc) as uint;
v.push(space, ty::RegionParameterDef { name: ident.name,
def_id: def_id,
space: space,
index: index });
true true
}); });
Rc::new(v) v
} }
fn enum_variant_ids(item: ebml::Doc, cdata: Cmd) -> Vec<ast::DefId> { fn enum_variant_ids(item: ebml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
@ -403,8 +414,8 @@ pub fn get_trait_def(cdata: Cmd,
} }
ty::TraitDef { ty::TraitDef {
generics: ty::Generics {type_param_defs: tp_defs, generics: ty::Generics {types: tp_defs,
region_param_defs: rp_defs}, regions: rp_defs},
bounds: bounds, bounds: bounds,
trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata)) trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata))
} }
@ -422,8 +433,8 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
let rp_defs = item_region_param_defs(item, cdata); let rp_defs = item_region_param_defs(item, cdata);
ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty {
generics: ty::Generics {type_param_defs: tp_defs, generics: ty::Generics {types: tp_defs,
region_param_defs: rp_defs}, regions: rp_defs},
ty: t ty: t
} }
} }
@ -440,16 +451,13 @@ pub fn get_impl_trait(cdata: Cmd,
pub fn get_impl_vtables(cdata: Cmd, pub fn get_impl_vtables(cdata: Cmd,
id: ast::NodeId, id: ast::NodeId,
tcx: &ty::ctxt) -> typeck::impl_res tcx: &ty::ctxt)
-> typeck::vtable_res
{ {
let item_doc = lookup_item(id, cdata.data()); let item_doc = lookup_item(id, cdata.data());
let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables); let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables);
let mut decoder = reader::Decoder::new(vtables_doc); let mut decoder = reader::Decoder::new(vtables_doc);
decoder.read_vtable_res(tcx, cdata)
typeck::impl_res {
trait_vtables: decoder.read_vtable_res(tcx, cdata),
self_vtables: decoder.read_vtable_param_res(tcx, cdata)
}
} }
@ -802,8 +810,8 @@ pub fn get_method(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId,
ty::Method::new( ty::Method::new(
name, name,
ty::Generics { ty::Generics {
type_param_defs: type_param_defs, types: type_param_defs,
region_param_defs: rp_defs, regions: rp_defs,
}, },
fty, fty,
explicit_self, explicit_self,

View file

@ -19,6 +19,7 @@ use metadata::common::*;
use metadata::cstore; use metadata::cstore;
use metadata::decoder; use metadata::decoder;
use metadata::tyencode; use metadata::tyencode;
use middle::subst::VecPerParamSpace;
use middle::ty::{node_id_to_type, lookup_item_type}; use middle::ty::{node_id_to_type, lookup_item_type};
use middle::astencode; use middle::astencode;
use middle::ty; use middle::ty;
@ -128,10 +129,9 @@ fn encode_trait_ref(ebml_w: &mut Encoder,
fn encode_impl_vtables(ebml_w: &mut Encoder, fn encode_impl_vtables(ebml_w: &mut Encoder,
ecx: &EncodeContext, ecx: &EncodeContext,
vtables: &typeck::impl_res) { vtables: &typeck::vtable_res) {
ebml_w.start_tag(tag_item_impl_vtables); ebml_w.start_tag(tag_item_impl_vtables);
astencode::encode_vtable_res(ecx, ebml_w, &vtables.trait_vtables); astencode::encode_vtable_res(ecx, ebml_w, vtables);
astencode::encode_vtable_param_res(ecx, ebml_w, &vtables.self_vtables);
ebml_w.end_tag(); ebml_w.end_tag();
} }
@ -148,7 +148,7 @@ pub fn def_to_str(did: DefId) -> String {
fn encode_ty_type_param_defs(ebml_w: &mut Encoder, fn encode_ty_type_param_defs(ebml_w: &mut Encoder,
ecx: &EncodeContext, ecx: &EncodeContext,
params: &[ty::TypeParameterDef], params: &VecPerParamSpace<ty::TypeParameterDef>,
tag: uint) { tag: uint) {
let ty_str_ctxt = &tyencode::ctxt { let ty_str_ctxt = &tyencode::ctxt {
diag: ecx.diag, diag: ecx.diag,
@ -164,7 +164,7 @@ fn encode_ty_type_param_defs(ebml_w: &mut Encoder,
} }
fn encode_region_param_defs(ebml_w: &mut Encoder, fn encode_region_param_defs(ebml_w: &mut Encoder,
params: &[ty::RegionParameterDef]) { params: &VecPerParamSpace<ty::RegionParameterDef>) {
for param in params.iter() { for param in params.iter() {
ebml_w.start_tag(tag_region_param_def); ebml_w.start_tag(tag_region_param_def);
@ -175,6 +175,12 @@ fn encode_region_param_defs(ebml_w: &mut Encoder,
ebml_w.wr_tagged_str(tag_region_param_def_def_id, ebml_w.wr_tagged_str(tag_region_param_def_def_id,
def_to_str(param.def_id).as_slice()); def_to_str(param.def_id).as_slice());
ebml_w.wr_tagged_u64(tag_region_param_def_space,
param.space.to_uint() as u64);
ebml_w.wr_tagged_u64(tag_region_param_def_index,
param.index as u64);
ebml_w.end_tag(); ebml_w.end_tag();
} }
} }
@ -191,9 +197,9 @@ fn encode_item_variances(ebml_w: &mut Encoder,
fn encode_bounds_and_type(ebml_w: &mut Encoder, fn encode_bounds_and_type(ebml_w: &mut Encoder,
ecx: &EncodeContext, ecx: &EncodeContext,
tpt: &ty::ty_param_bounds_and_ty) { tpt: &ty::ty_param_bounds_and_ty) {
encode_ty_type_param_defs(ebml_w, ecx, tpt.generics.type_param_defs(), encode_ty_type_param_defs(ebml_w, ecx, &tpt.generics.types,
tag_items_data_item_ty_param_bounds); tag_items_data_item_ty_param_bounds);
encode_region_param_defs(ebml_w, tpt.generics.region_param_defs()); encode_region_param_defs(ebml_w, &tpt.generics.regions);
encode_type(ecx, ebml_w, tpt.ty); encode_type(ecx, ebml_w, tpt.ty);
} }
@ -725,8 +731,7 @@ fn encode_method_ty_fields(ecx: &EncodeContext,
method_ty: &ty::Method) { method_ty: &ty::Method) {
encode_def_id(ebml_w, method_ty.def_id); encode_def_id(ebml_w, method_ty.def_id);
encode_name(ebml_w, method_ty.ident.name); encode_name(ebml_w, method_ty.ident.name);
encode_ty_type_param_defs(ebml_w, ecx, encode_ty_type_param_defs(ebml_w, ecx, &method_ty.generics.types,
method_ty.generics.type_param_defs(),
tag_item_method_tps); tag_item_method_tps);
encode_method_fty(ecx, ebml_w, &method_ty.fty); encode_method_fty(ecx, ebml_w, &method_ty.fty);
encode_visibility(ebml_w, method_ty.vis); encode_visibility(ebml_w, method_ty.vis);
@ -770,10 +775,8 @@ fn encode_info_for_method(ecx: &EncodeContext,
} }
for &ast_method in ast_method_opt.iter() { for &ast_method in ast_method_opt.iter() {
let num_params = tpt.generics.type_param_defs().len(); let any_types = !tpt.generics.types.is_empty();
if num_params > 0u || if any_types || is_default_impl || should_inline(ast_method.attrs.as_slice()) {
is_default_impl ||
should_inline(ast_method.attrs.as_slice()) {
encode_inlined_item(ecx, ebml_w, encode_inlined_item(ecx, ebml_w,
IIMethodRef(local_def(parent_id), false, IIMethodRef(local_def(parent_id), false,
&*ast_method)); &*ast_method));
@ -1125,9 +1128,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_item_variances(ebml_w, ecx, item.id); encode_item_variances(ebml_w, ecx, item.id);
let trait_def = ty::lookup_trait_def(tcx, def_id); let trait_def = ty::lookup_trait_def(tcx, def_id);
encode_ty_type_param_defs(ebml_w, ecx, encode_ty_type_param_defs(ebml_w, ecx,
trait_def.generics.type_param_defs(), &trait_def.generics.types,
tag_items_data_item_ty_param_bounds); tag_items_data_item_ty_param_bounds);
encode_region_param_defs(ebml_w, trait_def.generics.region_param_defs()); encode_region_param_defs(ebml_w, &trait_def.generics.regions);
encode_trait_ref(ebml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref); encode_trait_ref(ebml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
encode_name(ebml_w, item.ident.name); encode_name(ebml_w, item.ident.name);
encode_attributes(ebml_w, item.attrs.as_slice()); encode_attributes(ebml_w, item.attrs.as_slice());

View file

@ -17,6 +17,7 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use middle::subst; use middle::subst;
use middle::subst::VecPerParamSpace;
use middle::ty; use middle::ty;
use std::rc::Rc; use std::rc::Rc;
@ -114,26 +115,45 @@ pub fn parse_state_from_data<'a>(data: &'a [u8], crate_num: ast::CrateNum,
} }
} }
fn data_log_string(data: &[u8], pos: uint) -> String {
let mut buf = String::new();
buf.push_str("<<");
for i in range(pos, data.len()) {
let c = data[i];
if c > 0x20 && c <= 0x7F {
buf.push_char(c as char);
} else {
buf.push_char('.');
}
}
buf.push_str(">>");
buf
}
pub fn parse_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, pub fn parse_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
conv: conv_did) -> ty::t { conv: conv_did) -> ty::t {
debug!("parse_ty_data {}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx); let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_ty(&mut st, conv) parse_ty(&mut st, conv)
} }
pub fn parse_bare_fn_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, pub fn parse_bare_fn_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
conv: conv_did) -> ty::BareFnTy { conv: conv_did) -> ty::BareFnTy {
debug!("parse_bare_fn_ty_data {}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx); let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_bare_fn_ty(&mut st, conv) parse_bare_fn_ty(&mut st, conv)
} }
pub fn parse_trait_ref_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, pub fn parse_trait_ref_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
conv: conv_did) -> ty::TraitRef { conv: conv_did) -> ty::TraitRef {
debug!("parse_trait_ref_data {}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx); let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_trait_ref(&mut st, conv) parse_trait_ref(&mut st, conv)
} }
pub fn parse_substs_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, pub fn parse_substs_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
conv: conv_did) -> subst::Substs { conv: conv_did) -> subst::Substs {
debug!("parse_substs_data {}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx); let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_substs(&mut st, conv) parse_substs(&mut st, conv)
} }
@ -162,34 +182,39 @@ fn parse_trait_store(st: &mut PState, conv: conv_did) -> ty::TraitStore {
} }
} }
fn parse_substs(st: &mut PState, conv: conv_did) -> subst::Substs { fn parse_vec_per_param_space<T>(st: &mut PState,
let regions = parse_region_substs(st, |x,y| conv(x,y)); f: |&mut PState| -> T)
-> VecPerParamSpace<T>
let self_ty = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)) ); {
let mut r = VecPerParamSpace::empty();
for &space in subst::ParamSpace::all().iter() {
assert_eq!(next(st), '['); assert_eq!(next(st), '[');
let mut params: Vec<ty::t> = Vec::new(); while peek(st) != ']' {
while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); } r.push(space, f(st));
st.pos = st.pos + 1u; }
assert_eq!(next(st), ']');
}
r
}
return subst::Substs { fn parse_substs(st: &mut PState, conv: conv_did) -> subst::Substs {
regions: regions, let regions =
self_ty: self_ty, parse_region_substs(st, |x,y| conv(x,y));
tps: params
}; let types =
parse_vec_per_param_space(st, |st| parse_ty(st, |x,y| conv(x,y)));
return subst::Substs { types: types,
regions: regions };
} }
fn parse_region_substs(st: &mut PState, conv: conv_did) -> subst::RegionSubsts { fn parse_region_substs(st: &mut PState, conv: conv_did) -> subst::RegionSubsts {
match next(st) { match next(st) {
'e' => subst::ErasedRegions, 'e' => subst::ErasedRegions,
'n' => { 'n' => {
let mut regions = vec!(); subst::NonerasedRegions(
while peek(st) != '.' { parse_vec_per_param_space(
let r = parse_region(st, |x,y| conv(x,y)); st, |st| parse_region(st, |x,y| conv(x,y))))
regions.push(r);
}
assert_eq!(next(st), '.');
subst::NonerasedRegions(regions)
} }
_ => fail!("parse_bound_region: bad input") _ => fail!("parse_bound_region: bad input")
} }
@ -230,10 +255,12 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region {
assert_eq!(next(st), '['); assert_eq!(next(st), '[');
let node_id = parse_uint(st) as ast::NodeId; let node_id = parse_uint(st) as ast::NodeId;
assert_eq!(next(st), '|'); assert_eq!(next(st), '|');
let space = parse_param_space(st);
assert_eq!(next(st), '|');
let index = parse_uint(st); let index = parse_uint(st);
assert_eq!(next(st), '|'); assert_eq!(next(st), '|');
let nm = token::str_to_ident(parse_str(st, ']').as_slice()); let nm = token::str_to_ident(parse_str(st, ']').as_slice());
ty::ReEarlyBound(node_id, index, nm.name) ty::ReEarlyBound(node_id, space, index, nm.name)
} }
'f' => { 'f' => {
assert_eq!(next(st), '['); assert_eq!(next(st), '[');
@ -327,11 +354,11 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
'p' => { 'p' => {
let did = parse_def(st, TypeParameter, |x,y| conv(x,y)); let did = parse_def(st, TypeParameter, |x,y| conv(x,y));
debug!("parsed ty_param: did={:?}", did); debug!("parsed ty_param: did={:?}", did);
return ty::mk_param(st.tcx, parse_uint(st), did); let index = parse_uint(st);
} assert_eq!(next(st), '|');
's' => { let space = parse_param_space(st);
let did = parse_def(st, TypeParameter, |x,y| conv(x,y)); assert_eq!(next(st), '|');
return ty::mk_self(st.tcx, did); return ty::mk_param(st.tcx, space, index, did);
} }
'@' => return ty::mk_box(st.tcx, parse_ty(st, |x,y| conv(x,y))), '@' => return ty::mk_box(st.tcx, parse_ty(st, |x,y| conv(x,y))),
'~' => return ty::mk_uniq(st.tcx, parse_ty(st, |x,y| conv(x,y))), '~' => return ty::mk_uniq(st.tcx, parse_ty(st, |x,y| conv(x,y))),
@ -395,6 +422,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
assert_eq!(next(st), ']'); assert_eq!(next(st), ']');
return ty::mk_struct(st.tcx, did, substs); return ty::mk_struct(st.tcx, did, substs);
} }
'e' => {
return ty::mk_err();
}
c => { fail!("unexpected char in type string: {}", c);} c => { fail!("unexpected char in type string: {}", c);}
} }
} }
@ -427,6 +457,10 @@ fn parse_uint(st: &mut PState) -> uint {
}; };
} }
fn parse_param_space(st: &mut PState) -> subst::ParamSpace {
subst::ParamSpace::from_uint(parse_uint(st))
}
fn parse_hex(st: &mut PState) -> uint { fn parse_hex(st: &mut PState) -> uint {
let mut n = 0u; let mut n = 0u;
loop { loop {
@ -546,11 +580,22 @@ pub fn parse_type_param_def_data(data: &[u8], start: uint,
} }
fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef { fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef {
let ident = parse_ident(st, ':');
let def_id = parse_def(st, NominalType, |x,y| conv(x,y));
let space = parse_param_space(st);
assert_eq!(next(st), '|');
let index = parse_uint(st);
assert_eq!(next(st), '|');
let bounds = Rc::new(parse_bounds(st, |x,y| conv(x,y)));
let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)));
ty::TypeParameterDef { ty::TypeParameterDef {
ident: parse_ident(st, ':'), ident: ident,
def_id: parse_def(st, NominalType, |x,y| conv(x,y)), def_id: def_id,
bounds: Rc::new(parse_bounds(st, |x,y| conv(x,y))), space: space,
default: parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y))) index: index,
bounds: bounds,
default: default
} }
} }

View file

@ -18,7 +18,8 @@ use std::collections::HashMap;
use std::io::MemWriter; use std::io::MemWriter;
use middle::subst; use middle::subst;
use middle::ty::param_ty; use middle::subst::VecPerParamSpace;
use middle::ty::ParamTy;
use middle::ty; use middle::ty;
use syntax::abi::Abi; use syntax::abi::Abi;
@ -118,12 +119,23 @@ fn enc_opt<T>(w: &mut MemWriter, t: Option<T>, enc_f: |&mut MemWriter, T|) {
} }
} }
fn enc_vec_per_param_space<T>(w: &mut MemWriter,
cx: &ctxt,
v: &VecPerParamSpace<T>,
op: |&mut MemWriter, &ctxt, &T|) {
for &space in subst::ParamSpace::all().iter() {
mywrite!(w, "[");
for t in v.get_vec(space).iter() {
op(w, cx, t);
}
mywrite!(w, "]");
}
}
pub fn enc_substs(w: &mut MemWriter, cx: &ctxt, substs: &subst::Substs) { pub fn enc_substs(w: &mut MemWriter, cx: &ctxt, substs: &subst::Substs) {
enc_region_substs(w, cx, &substs.regions); enc_region_substs(w, cx, &substs.regions);
enc_opt(w, substs.self_ty, |w, t| enc_ty(w, cx, t)); enc_vec_per_param_space(w, cx, &substs.types,
mywrite!(w, "["); |w, cx, &ty| enc_ty(w, cx, ty));
for t in substs.tps.iter() { enc_ty(w, cx, *t); }
mywrite!(w, "]");
} }
fn enc_region_substs(w: &mut MemWriter, cx: &ctxt, substs: &subst::RegionSubsts) { fn enc_region_substs(w: &mut MemWriter, cx: &ctxt, substs: &subst::RegionSubsts) {
@ -133,10 +145,8 @@ fn enc_region_substs(w: &mut MemWriter, cx: &ctxt, substs: &subst::RegionSubsts)
} }
subst::NonerasedRegions(ref regions) => { subst::NonerasedRegions(ref regions) => {
mywrite!(w, "n"); mywrite!(w, "n");
for &r in regions.iter() { enc_vec_per_param_space(w, cx, regions,
enc_region(w, cx, r); |w, cx, &r| enc_region(w, cx, r));
}
mywrite!(w, ".");
} }
} }
} }
@ -148,9 +158,10 @@ fn enc_region(w: &mut MemWriter, cx: &ctxt, r: ty::Region) {
enc_bound_region(w, cx, br); enc_bound_region(w, cx, br);
mywrite!(w, "]"); mywrite!(w, "]");
} }
ty::ReEarlyBound(node_id, index, name) => { ty::ReEarlyBound(node_id, space, index, name) => {
mywrite!(w, "B[{}|{}|{}]", mywrite!(w, "B[{}|{}|{}|{}]",
node_id, node_id,
space.to_uint(),
index, index,
token::get_name(name)); token::get_name(name));
} }
@ -293,18 +304,17 @@ fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) {
ty::ty_infer(_) => { ty::ty_infer(_) => {
cx.diag.handler().bug("cannot encode inference variable types"); cx.diag.handler().bug("cannot encode inference variable types");
} }
ty::ty_param(param_ty {idx: id, def_id: did}) => { ty::ty_param(ParamTy {space, idx: id, def_id: did}) => {
mywrite!(w, "p{}|{}", (cx.ds)(did), id); mywrite!(w, "p{}|{}|{}|", (cx.ds)(did), id, space.to_uint())
}
ty::ty_self(did) => {
mywrite!(w, "s{}|", (cx.ds)(did));
} }
ty::ty_struct(def, ref substs) => { ty::ty_struct(def, ref substs) => {
mywrite!(w, "a[{}|", (cx.ds)(def)); mywrite!(w, "a[{}|", (cx.ds)(def));
enc_substs(w, cx, substs); enc_substs(w, cx, substs);
mywrite!(w, "]"); mywrite!(w, "]");
} }
ty::ty_err => fail!("shouldn't encode error type") ty::ty_err => {
mywrite!(w, "e");
}
} }
} }
@ -378,7 +388,9 @@ fn enc_bounds(w: &mut MemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
} }
pub fn enc_type_param_def(w: &mut MemWriter, cx: &ctxt, v: &ty::TypeParameterDef) { pub fn enc_type_param_def(w: &mut MemWriter, cx: &ctxt, v: &ty::TypeParameterDef) {
mywrite!(w, "{}:{}|", token::get_ident(v.ident), (cx.ds)(v.def_id)); mywrite!(w, "{}:{}|{}|{}|",
token::get_ident(v.ident), (cx.ds)(v.def_id),
v.space.to_uint(), v.index);
enc_bounds(w, cx, &*v.bounds); enc_bounds(w, cx, &*v.bounds);
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
} }

View file

@ -25,6 +25,7 @@ use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
RegionParameter}; RegionParameter};
use metadata::tyencode; use metadata::tyencode;
use middle::subst; use middle::subst;
use middle::subst::VecPerParamSpace;
use middle::typeck::{MethodCall, MethodCallee, MethodOrigin}; use middle::typeck::{MethodCall, MethodCallee, MethodOrigin};
use middle::{ty, typeck}; use middle::{ty, typeck};
use util::ppaux::ty_to_str; use util::ppaux::ty_to_str;
@ -39,7 +40,7 @@ use libc;
use std::io::Seek; use std::io::Seek;
use std::io::MemWriter; use std::io::MemWriter;
use std::mem; use std::mem;
use std::rc::Rc; use std::string::String;
use serialize::ebml::reader; use serialize::ebml::reader;
use serialize::ebml; use serialize::ebml;
@ -433,7 +434,7 @@ impl tr for def::Def {
def::DefTrait(did) => def::DefTrait(did.tr(xcx)), def::DefTrait(did) => def::DefTrait(did.tr(xcx)),
def::DefTy(did) => def::DefTy(did.tr(xcx)), def::DefTy(did) => def::DefTy(did.tr(xcx)),
def::DefPrimTy(p) => def::DefPrimTy(p), def::DefPrimTy(p) => def::DefPrimTy(p),
def::DefTyParam(did, v) => def::DefTyParam(did.tr(xcx), v), def::DefTyParam(s, did, v) => def::DefTyParam(s, did.tr(xcx), v),
def::DefBinding(nid, bm) => def::DefBinding(xcx.tr_id(nid), bm), def::DefBinding(nid, bm) => def::DefBinding(xcx.tr_id(nid), bm),
def::DefUse(did) => def::DefUse(did.tr(xcx)), def::DefUse(did) => def::DefUse(did.tr(xcx)),
def::DefUpvar(nid1, def, nid2, nid3) => { def::DefUpvar(nid1, def, nid2, nid3) => {
@ -476,13 +477,18 @@ impl tr for ty::AutoRef {
impl tr for ty::Region { impl tr for ty::Region {
fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::Region { fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::Region {
match *self { match *self {
ty::ReLateBound(id, br) => ty::ReLateBound(xcx.tr_id(id), ty::ReLateBound(id, br) => {
br.tr(xcx)), ty::ReLateBound(xcx.tr_id(id), br.tr(xcx))
ty::ReEarlyBound(id, index, ident) => ty::ReEarlyBound(xcx.tr_id(id), }
index, ty::ReEarlyBound(id, space, index, ident) => {
ident), ty::ReEarlyBound(xcx.tr_id(id), space, index, ident)
ty::ReScope(id) => ty::ReScope(xcx.tr_id(id)), }
ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) => *self, ty::ReScope(id) => {
ty::ReScope(xcx.tr_id(id))
}
ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) => {
*self
}
ty::ReFree(ref fr) => { ty::ReFree(ref fr) => {
ty::ReFree(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id), ty::ReFree(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id),
bound_region: fr.bound_region.tr(xcx)}) bound_region: fr.bound_region.tr(xcx)})
@ -640,9 +646,10 @@ pub fn encode_vtable_res(ecx: &e::EncodeContext,
// ty::t doesn't work, and there is no way (atm) to have // ty::t doesn't work, and there is no way (atm) to have
// hand-written encoding routines combine with auto-generated // hand-written encoding routines combine with auto-generated
// ones. perhaps we should fix this. // ones. perhaps we should fix this.
ebml_w.emit_from_vec(dr.as_slice(), |ebml_w, param_tables| { encode_vec_per_param_space(
Ok(encode_vtable_param_res(ecx, ebml_w, param_tables)) ebml_w, dr,
}).unwrap() |ebml_w, param_tables| encode_vtable_param_res(ecx, ebml_w,
param_tables))
} }
pub fn encode_vtable_param_res(ecx: &e::EncodeContext, pub fn encode_vtable_param_res(ecx: &e::EncodeContext,
@ -673,7 +680,7 @@ pub fn encode_vtable_origin(ecx: &e::EncodeContext,
}) })
} }
typeck::vtable_param(pn, bn) => { typeck::vtable_param(pn, bn) => {
ebml_w.emit_enum_variant("vtable_param", 1u, 2u, |ebml_w| { ebml_w.emit_enum_variant("vtable_param", 1u, 3u, |ebml_w| {
ebml_w.emit_enum_variant_arg(0u, |ebml_w| { ebml_w.emit_enum_variant_arg(0u, |ebml_w| {
pn.encode(ebml_w) pn.encode(ebml_w)
}); });
@ -682,11 +689,19 @@ pub fn encode_vtable_origin(ecx: &e::EncodeContext,
}) })
}) })
} }
typeck::vtable_error => {
ebml_w.emit_enum_variant("vtable_error", 2u, 3u, |_ebml_w| {
Ok(())
})
}
} }
}).unwrap() }).unwrap()
} }
pub trait vtable_decoder_helpers { pub trait vtable_decoder_helpers {
fn read_vec_per_param_space<T>(&mut self,
f: |&mut Self| -> T)
-> VecPerParamSpace<T>;
fn read_vtable_res_with_key(&mut self, fn read_vtable_res_with_key(&mut self,
tcx: &ty::ctxt, tcx: &ty::ctxt,
cdata: &cstore::crate_metadata) cdata: &cstore::crate_metadata)
@ -703,6 +718,16 @@ pub trait vtable_decoder_helpers {
} }
impl<'a> vtable_decoder_helpers for reader::Decoder<'a> { impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
fn read_vec_per_param_space<T>(&mut self,
f: |&mut reader::Decoder<'a>| -> T)
-> VecPerParamSpace<T>
{
let types = self.read_to_vec(|this| Ok(f(this))).unwrap();
let selfs = self.read_to_vec(|this| Ok(f(this))).unwrap();
let fns = self.read_to_vec(|this| Ok(f(this))).unwrap();
VecPerParamSpace::new(types, selfs, fns)
}
fn read_vtable_res_with_key(&mut self, fn read_vtable_res_with_key(&mut self,
tcx: &ty::ctxt, tcx: &ty::ctxt,
cdata: &cstore::crate_metadata) cdata: &cstore::crate_metadata)
@ -718,10 +743,12 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
} }
fn read_vtable_res(&mut self, fn read_vtable_res(&mut self,
tcx: &ty::ctxt, cdata: &cstore::crate_metadata) tcx: &ty::ctxt,
-> typeck::vtable_res { cdata: &cstore::crate_metadata)
self.read_to_vec(|this| Ok(this.read_vtable_param_res(tcx, cdata))) -> typeck::vtable_res
.unwrap().move_iter().collect() {
self.read_vec_per_param_space(
|this| this.read_vtable_param_res(tcx, cdata))
} }
fn read_vtable_param_res(&mut self, fn read_vtable_param_res(&mut self,
@ -737,7 +764,7 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
self.read_enum("vtable_origin", |this| { self.read_enum("vtable_origin", |this| {
this.read_enum_variant(["vtable_static", this.read_enum_variant(["vtable_static",
"vtable_param", "vtable_param",
"vtable_self"], "vtable_error"],
|this, i| { |this, i| {
Ok(match i { Ok(match i {
0 => { 0 => {
@ -763,7 +790,9 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
}).unwrap() }).unwrap()
) )
} }
// hard to avoid - user input 2 => {
typeck::vtable_error
}
_ => fail!("bad enum variant") _ => fail!("bad enum variant")
}) })
}) })
@ -771,6 +800,18 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
} }
} }
// ___________________________________________________________________________
//
fn encode_vec_per_param_space<T>(ebml_w: &mut Encoder,
v: &subst::VecPerParamSpace<T>,
f: |&mut Encoder, &T|) {
for &space in subst::ParamSpace::all().iter() {
ebml_w.emit_from_vec(v.get_vec(space).as_slice(),
|ebml_w, n| Ok(f(ebml_w, n))).unwrap();
}
}
// ______________________________________________________________________ // ______________________________________________________________________
// Encoding and decoding the side tables // Encoding and decoding the side tables
@ -827,14 +868,15 @@ impl<'a> ebml_writer_helpers for Encoder<'a> {
self.emit_struct("ty_param_bounds_and_ty", 2, |this| { self.emit_struct("ty_param_bounds_and_ty", 2, |this| {
this.emit_struct_field("generics", 0, |this| { this.emit_struct_field("generics", 0, |this| {
this.emit_struct("Generics", 2, |this| { this.emit_struct("Generics", 2, |this| {
this.emit_struct_field("type_param_defs", 0, |this| { this.emit_struct_field("types", 0, |this| {
this.emit_from_vec(tpbt.generics.type_param_defs(), Ok(encode_vec_per_param_space(
|this, type_param_def| { this, &tpbt.generics.types,
Ok(this.emit_type_param_def(ecx, type_param_def)) |this, def| this.emit_type_param_def(ecx, def)))
})
}); });
this.emit_struct_field("region_param_defs", 1, |this| { this.emit_struct_field("regions", 1, |this| {
tpbt.generics.region_param_defs().encode(this) Ok(encode_vec_per_param_space(
this, &tpbt.generics.regions,
|this, def| def.encode(this).unwrap()))
}) })
}) })
}); });
@ -1186,21 +1228,16 @@ impl<'a> ebml_decoder_decoder_helpers for reader::Decoder<'a> {
generics: this.read_struct_field("generics", 0, |this| { generics: this.read_struct_field("generics", 0, |this| {
this.read_struct("Generics", 2, |this| { this.read_struct("Generics", 2, |this| {
Ok(ty::Generics { Ok(ty::Generics {
type_param_defs: types:
this.read_struct_field("type_param_defs", this.read_struct_field("types", 0, |this| {
0, Ok(this.read_vec_per_param_space(
|this| { |this| this.read_type_param_def(xcx)))
Ok(Rc::new(this.read_to_vec(|this|
Ok(this.read_type_param_def(xcx)))
.unwrap()
.move_iter()
.collect()))
}).unwrap(), }).unwrap(),
region_param_defs:
this.read_struct_field("region_param_defs", regions:
1, this.read_struct_field("regions", 1, |this| {
|this| { Ok(this.read_vec_per_param_space(
Decodable::decode(this) |this| Decodable::decode(this).unwrap()))
}).unwrap() }).unwrap()
}) })
}) })

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use middle::subst::ParamSpace;
use syntax::ast; use syntax::ast;
use syntax::ast_util::local_def; use syntax::ast_util::local_def;
@ -27,7 +28,7 @@ pub enum Def {
DefTy(ast::DefId), DefTy(ast::DefId),
DefTrait(ast::DefId), DefTrait(ast::DefId),
DefPrimTy(ast::PrimTy), DefPrimTy(ast::PrimTy),
DefTyParam(ast::DefId, uint), DefTyParam(ParamSpace, ast::DefId, uint),
DefBinding(ast::NodeId, ast::BindingMode), DefBinding(ast::NodeId, ast::BindingMode),
DefUse(ast::DefId), DefUse(ast::DefId),
DefUpvar(ast::NodeId, // id of closed over var DefUpvar(ast::NodeId, // id of closed over var
@ -61,7 +62,7 @@ impl Def {
match *self { match *self {
DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(id) | DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(id) |
DefForeignMod(id) | DefStatic(id, _) | DefForeignMod(id) | DefStatic(id, _) |
DefVariant(_, id, _) | DefTy(id) | DefTyParam(id, _) | DefVariant(_, id, _) | DefTy(id) | DefTyParam(_, id, _) |
DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => { DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => {
id id
} }

View file

@ -86,12 +86,9 @@ fn check_struct_safe_for_destructor(cx: &mut Context,
span: Span, span: Span,
struct_did: DefId) { struct_did: DefId) {
let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did); let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
if !struct_tpt.generics.has_type_params() { if !struct_tpt.generics.has_type_params(subst::TypeSpace) {
let struct_ty = ty::mk_struct(cx.tcx, struct_did, subst::Substs { let struct_ty = ty::mk_struct(cx.tcx, struct_did,
regions: subst::NonerasedRegions(Vec::new()), subst::Substs::empty());
self_ty: None,
tps: Vec::new()
});
if !ty::type_is_sendable(cx.tcx, struct_ty) { if !ty::type_is_sendable(cx.tcx, struct_ty) {
cx.tcx.sess.span_err(span, cx.tcx.sess.span_err(span,
"cannot implement a destructor on a \ "cannot implement a destructor on a \
@ -245,51 +242,7 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
debug!("kind::check_expr({})", expr_to_str(e)); debug!("kind::check_expr({})", expr_to_str(e));
// Handle any kind bounds on type parameters // Handle any kind bounds on type parameters
{ check_bounds_on_type_parameters(cx, e);
let method_map = cx.tcx.method_map.borrow();
let method = method_map.find(&typeck::MethodCall::expr(e.id));
let item_substs = cx.tcx.item_substs.borrow();
let r = match method {
Some(method) => Some(&method.substs.tps),
None => item_substs.find(&e.id).map(|s| &s.substs.tps)
};
for ts in r.iter() {
let def_map = cx.tcx.def_map.borrow();
let type_param_defs = match e.node {
ExprPath(_) => {
let did = def_map.get_copy(&e.id).def_id();
ty::lookup_item_type(cx.tcx, did).generics.type_param_defs.clone()
}
_ => {
// Type substitutions should only occur on paths and
// method calls, so this needs to be a method call.
// Even though the callee_id may have been the id with
// node_type_substs, e.id is correct here.
match method {
Some(method) => {
ty::method_call_type_param_defs(cx.tcx, method.origin)
}
None => {
cx.tcx.sess.span_bug(e.span,
"non path/method call expr has type substs??");
}
}
}
};
if ts.len() != type_param_defs.len() {
// Fail earlier to make debugging easier
fail!("internal error: in kind::check_expr, length \
mismatch between actual and declared bounds: actual = \
{}, declared = {}",
ts.repr(cx.tcx),
type_param_defs.repr(cx.tcx));
}
for (&ty, type_param_def) in ts.iter().zip(type_param_defs.iter()) {
check_typaram_bounds(cx, e.span, ty, type_param_def)
}
}
}
match e.node { match e.node {
ExprUnary(UnBox, ref interior) => { ExprUnary(UnBox, ref interior) => {
@ -331,6 +284,77 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
visit::walk_expr(cx, e, ()); visit::walk_expr(cx, e, ());
} }
fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) {
let method_map = cx.tcx.method_map.borrow();
let method = method_map.find(&typeck::MethodCall::expr(e.id));
// Find the values that were provided (if any)
let item_substs = cx.tcx.item_substs.borrow();
let (types, is_object_call) = match method {
Some(method) => {
let is_object_call = match method.origin {
typeck::MethodObject(..) => true,
typeck::MethodStatic(..) | typeck::MethodParam(..) => false
};
(&method.substs.types, is_object_call)
}
None => {
match item_substs.find(&e.id) {
None => { return; }
Some(s) => { (&s.substs.types, false) }
}
}
};
// Find the relevant type parameter definitions
let def_map = cx.tcx.def_map.borrow();
let type_param_defs = match e.node {
ExprPath(_) => {
let did = def_map.get_copy(&e.id).def_id();
ty::lookup_item_type(cx.tcx, did).generics.types.clone()
}
_ => {
// Type substitutions should only occur on paths and
// method calls, so this needs to be a method call.
// Even though the callee_id may have been the id with
// node_type_substs, e.id is correct here.
match method {
Some(method) => {
ty::method_call_type_param_defs(cx.tcx, method.origin)
}
None => {
cx.tcx.sess.span_bug(e.span,
"non path/method call expr has type substs??");
}
}
}
};
// Check that the value provided for each definition meets the
// kind requirements
for type_param_def in type_param_defs.iter() {
let ty = *types.get(type_param_def.space, type_param_def.index);
// If this is a call to an object method (`foo.bar()` where
// `foo` has a type like `Trait`), then the self type is
// unknown (after all, this is a virtual call). In that case,
// we will have put a ty_err in the substitutions, and we can
// just skip over validating the bounds (because the bounds
// would have been enforced when the object instance was
// created).
if is_object_call && type_param_def.space == subst::SelfSpace {
assert_eq!(type_param_def.index, 0);
assert!(ty::type_is_error(ty));
continue;
}
debug!("type_param_def space={} index={} ty={}",
type_param_def.space, type_param_def.index, ty.repr(cx.tcx));
check_typaram_bounds(cx, e.span, ty, type_param_def)
}
}
fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) { fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) {
check_cast_for_escaping_regions(cx, source_ty, target_ty, span); check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
match ty::get(target_ty).sty { match ty::get(target_ty).sty {
@ -350,12 +374,10 @@ fn check_ty(cx: &mut Context, aty: &Ty) {
let def_map = cx.tcx.def_map.borrow(); let def_map = cx.tcx.def_map.borrow();
let did = def_map.get_copy(&id).def_id(); let did = def_map.get_copy(&id).def_id();
let generics = ty::lookup_item_type(cx.tcx, did).generics; let generics = ty::lookup_item_type(cx.tcx, did).generics;
let type_param_defs = generics.type_param_defs(); for def in generics.types.iter() {
for (&ty, type_param_def) in let ty = *item_substs.substs.types.get(def.space,
item_substs.substs.tps.iter().zip( def.index);
type_param_defs.iter()) check_typaram_bounds(cx, aty.span, ty, def)
{
check_typaram_bounds(cx, aty.span, ty, type_param_def)
} }
} }
} }
@ -555,7 +577,12 @@ pub fn check_cast_for_escaping_regions(
|ty| { |ty| {
match ty::get(ty).sty { match ty::get(ty).sty {
ty::ty_param(source_param) => { ty::ty_param(source_param) => {
if target_params.iter().any(|x| x == &source_param) { if source_param.space == subst::SelfSpace {
// FIXME (#5723) -- there is no reason that
// Self should be exempt from this check,
// except for historical accident. Bottom
// line, we need proper region bounding.
} else if target_params.iter().any(|x| x == &source_param) {
/* case (2) */ /* case (2) */
} else { } else {
check_static(cx.tcx, ty, source_span); /* case (3) */ check_static(cx.tcx, ty, source_span); /* case (3) */

View file

@ -17,6 +17,7 @@ use middle::def::*;
use middle::lang_items::LanguageItems; use middle::lang_items::LanguageItems;
use middle::lint::{UnnecessaryQualification, UnusedImports}; use middle::lint::{UnnecessaryQualification, UnusedImports};
use middle::pat_util::pat_bindings; use middle::pat_util::pat_bindings;
use middle::subst::{ParamSpace, FnSpace, TypeSpace};
use util::nodemap::{NodeMap, DefIdSet, FnvHashMap}; use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
use syntax::ast::*; use syntax::ast::*;
@ -227,22 +228,17 @@ enum FallbackSuggestion {
} }
enum TypeParameters<'a> { enum TypeParameters<'a> {
NoTypeParameters, //< No type parameters. NoTypeParameters,
HasTypeParameters(&'a Generics, //< Type parameters. HasTypeParameters(
NodeId, //< ID of the enclosing item // Type parameters.
&'a Generics,
// The index to start numbering the type parameters at. // Identifies the things that these parameters
// This is zero if this is the outermost set of type // were declared on (type, fn, etc)
// parameters, or equal to the number of outer type ParamSpace,
// parameters. For example, if we have:
// // ID of the enclosing item.
// impl I<T> { NodeId,
// fn method<U>() { ... }
// }
//
// The index at the method site will be 1, because the
// outer T had index 0.
uint,
// The kind of the rib used for type parameters. // The kind of the rib used for type parameters.
RibKind) RibKind)
@ -1532,8 +1528,8 @@ impl<'a> Resolver<'a> {
self.with_type_parameter_rib( self.with_type_parameter_rib(
HasTypeParameters(generics, HasTypeParameters(generics,
FnSpace,
foreign_item.id, foreign_item.id,
0,
NormalRibKind), NormalRibKind),
f); f);
} }
@ -3439,7 +3435,7 @@ impl<'a> Resolver<'a> {
// If the def is a ty param, and came from the parent // If the def is a ty param, and came from the parent
// item, it's ok // item, it's ok
match def { match def {
DefTyParam(did, _) if { DefTyParam(_, did, _) if {
self.def_map.borrow().find(&did.node).map(|x| *x) self.def_map.borrow().find(&did.node).map(|x| *x)
== Some(DefTyParamBinder(item_id)) == Some(DefTyParamBinder(item_id))
} => { } => {
@ -3574,8 +3570,8 @@ impl<'a> Resolver<'a> {
// but maybe it's okay since the first time will signal an // but maybe it's okay since the first time will signal an
// error if there is one? -- tjc // error if there is one? -- tjc
self.with_type_parameter_rib(HasTypeParameters(generics, self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
item.id, item.id,
0,
ItemRibKind), ItemRibKind),
|this| { |this| {
visit::walk_item(this, item, ()); visit::walk_item(this, item, ());
@ -3584,8 +3580,8 @@ impl<'a> Resolver<'a> {
ItemTy(_, ref generics) => { ItemTy(_, ref generics) => {
self.with_type_parameter_rib(HasTypeParameters(generics, self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
item.id, item.id,
0,
ItemRibKind), ItemRibKind),
|this| { |this| {
visit::walk_item(this, item, ()); visit::walk_item(this, item, ());
@ -3615,8 +3611,8 @@ impl<'a> Resolver<'a> {
// Create a new rib for the trait-wide type parameters. // Create a new rib for the trait-wide type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics, self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
item.id, item.id,
0,
NormalRibKind), NormalRibKind),
|this| { |this| {
this.resolve_type_parameters(&generics.ty_params); this.resolve_type_parameters(&generics.ty_params);
@ -3636,8 +3632,8 @@ impl<'a> Resolver<'a> {
ast::Required(ref ty_m) => { ast::Required(ref ty_m) => {
this.with_type_parameter_rib this.with_type_parameter_rib
(HasTypeParameters(&ty_m.generics, (HasTypeParameters(&ty_m.generics,
FnSpace,
item.id, item.id,
generics.ty_params.len(),
MethodRibKind(item.id, Required)), MethodRibKind(item.id, Required)),
|this| { |this| {
@ -3656,8 +3652,7 @@ impl<'a> Resolver<'a> {
ast::Provided(ref m) => { ast::Provided(ref m) => {
this.resolve_method(MethodRibKind(item.id, this.resolve_method(MethodRibKind(item.id,
Provided(m.id)), Provided(m.id)),
&**m, &**m)
generics.ty_params.len())
} }
} }
} }
@ -3687,7 +3682,7 @@ impl<'a> Resolver<'a> {
ForeignItemFn(_, ref generics) => { ForeignItemFn(_, ref generics) => {
this.with_type_parameter_rib( this.with_type_parameter_rib(
HasTypeParameters( HasTypeParameters(
generics, foreign_item.id, 0, generics, FnSpace, foreign_item.id,
ItemRibKind), ItemRibKind),
|this| visit::walk_foreign_item(this, |this| visit::walk_foreign_item(this,
&**foreign_item, &**foreign_item,
@ -3708,8 +3703,8 @@ impl<'a> Resolver<'a> {
Some(fn_decl), Some(fn_decl),
HasTypeParameters HasTypeParameters
(generics, (generics,
FnSpace,
item.id, item.id,
0,
ItemRibKind), ItemRibKind),
block); block);
} }
@ -3730,7 +3725,7 @@ impl<'a> Resolver<'a> {
type_parameters: TypeParameters, type_parameters: TypeParameters,
f: |&mut Resolver|) { f: |&mut Resolver|) {
match type_parameters { match type_parameters {
HasTypeParameters(generics, node_id, initial_index, HasTypeParameters(generics, space, node_id,
rib_kind) => { rib_kind) => {
let function_type_rib = Rib::new(rib_kind); let function_type_rib = Rib::new(rib_kind);
@ -3739,9 +3734,9 @@ impl<'a> Resolver<'a> {
let ident = type_parameter.ident; let ident = type_parameter.ident;
debug!("with_type_parameter_rib: {} {}", node_id, debug!("with_type_parameter_rib: {} {}", node_id,
type_parameter.id); type_parameter.id);
let def_like = DlDef(DefTyParam let def_like = DlDef(DefTyParam(space,
(local_def(type_parameter.id), local_def(type_parameter.id),
index + initial_index)); index));
// Associate this type parameter with // Associate this type parameter with
// the item that bound it // the item that bound it
self.record_def(type_parameter.id, self.record_def(type_parameter.id,
@ -3897,8 +3892,8 @@ impl<'a> Resolver<'a> {
fields: &[StructField]) { fields: &[StructField]) {
// If applicable, create a rib for the type parameters. // If applicable, create a rib for the type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics, self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
id, id,
0,
ItemRibKind), ItemRibKind),
|this| { |this| {
// Resolve the type parameters. // Resolve the type parameters.
@ -3948,13 +3943,11 @@ impl<'a> Resolver<'a> {
// to be NormalRibKind? // to be NormalRibKind?
fn resolve_method(&mut self, fn resolve_method(&mut self,
rib_kind: RibKind, rib_kind: RibKind,
method: &Method, method: &Method) {
outer_type_parameter_count: uint) {
let method_generics = &method.generics; let method_generics = &method.generics;
let type_parameters = let type_parameters = HasTypeParameters(method_generics,
HasTypeParameters(method_generics, FnSpace,
method.id, method.id,
outer_type_parameter_count,
rib_kind); rib_kind);
self.resolve_function(rib_kind, Some(method.decl), type_parameters, method.body); self.resolve_function(rib_kind, Some(method.decl), type_parameters, method.body);
@ -3998,10 +3991,9 @@ impl<'a> Resolver<'a> {
self_type: &Ty, self_type: &Ty,
methods: &[Gc<Method>]) { methods: &[Gc<Method>]) {
// If applicable, create a rib for the type parameters. // If applicable, create a rib for the type parameters.
let outer_type_parameter_count = generics.ty_params.len();
self.with_type_parameter_rib(HasTypeParameters(generics, self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
id, id,
0,
NormalRibKind), NormalRibKind),
|this| { |this| {
// Resolve the type parameters. // Resolve the type parameters.
@ -4016,8 +4008,7 @@ impl<'a> Resolver<'a> {
for method in methods.iter() { for method in methods.iter() {
// We also need a new scope for the method-specific type parameters. // We also need a new scope for the method-specific type parameters.
this.resolve_method(MethodRibKind(id, Provided(method.id)), this.resolve_method(MethodRibKind(id, Provided(method.id)),
&**method, &**method);
outer_type_parameter_count);
} }
}); });
}); });

View file

@ -18,7 +18,7 @@
*/ */
use driver::session::Session; use driver::session::Session;
use util::nodemap::NodeMap; use middle::subst;
use syntax::ast; use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::owned_slice::OwnedSlice; use syntax::owned_slice::OwnedSlice;
@ -27,10 +27,24 @@ use syntax::parse::token;
use syntax::print::pprust::{lifetime_to_str}; use syntax::print::pprust::{lifetime_to_str};
use syntax::visit; use syntax::visit;
use syntax::visit::Visitor; use syntax::visit::Visitor;
use util::nodemap::NodeMap;
#[deriving(Clone, PartialEq, Eq, Hash, Encodable, Decodable, Show)]
pub enum DefRegion {
DefStaticRegion,
DefEarlyBoundRegion(/* space */ subst::ParamSpace,
/* index */ uint,
/* lifetime decl */ ast::NodeId),
DefLateBoundRegion(/* binder_id */ ast::NodeId,
/* depth */ uint,
/* lifetime decl */ ast::NodeId),
DefFreeRegion(/* block scope */ ast::NodeId,
/* lifetime decl */ ast::NodeId),
}
// maps the id of each lifetime reference to the lifetime decl // maps the id of each lifetime reference to the lifetime decl
// that it corresponds to // that it corresponds to
pub type NamedRegionMap = NodeMap<ast::DefRegion>; pub type NamedRegionMap = NodeMap<DefRegion>;
// Returns an instance of some type that implements std::fmt::Show // Returns an instance of some type that implements std::fmt::Show
fn lifetime_show(lt_name: &ast::Name) -> token::InternedString { fn lifetime_show(lt_name: &ast::Name) -> token::InternedString {
@ -45,7 +59,7 @@ struct LifetimeContext<'a> {
enum ScopeChain<'a> { enum ScopeChain<'a> {
/// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
/// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc. /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
EarlyScope(uint, &'a Vec<ast::Lifetime>, Scope<'a>), EarlyScope(subst::ParamSpace, &'a Vec<ast::Lifetime>, Scope<'a>),
/// LateScope(binder_id, ['a, 'b, ...], s) extends s with late-bound /// LateScope(binder_id, ['a, 'b, ...], s) extends s with late-bound
/// lifetimes introduced by the declaration binder_id. /// lifetimes introduced by the declaration binder_id.
LateScope(ast::NodeId, &'a Vec<ast::Lifetime>, Scope<'a>), LateScope(ast::NodeId, &'a Vec<ast::Lifetime>, Scope<'a>),
@ -86,7 +100,7 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
ast::ItemImpl(ref generics, _, _, _) | ast::ItemImpl(ref generics, _, _, _) |
ast::ItemTrait(ref generics, _, _, _) => { ast::ItemTrait(ref generics, _, _, _) => {
self.check_lifetime_names(&generics.lifetimes); self.check_lifetime_names(&generics.lifetimes);
EarlyScope(0, &generics.lifetimes, &root) EarlyScope(subst::TypeSpace, &generics.lifetimes, &root)
} }
}; };
debug!("entering scope {:?}", scope); debug!("entering scope {:?}", scope);
@ -152,33 +166,13 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
lifetime_ref: &ast::Lifetime, lifetime_ref: &ast::Lifetime,
scope: Scope<'a>) { scope: Scope<'a>) {
if lifetime_ref.name == special_idents::statik.name { if lifetime_ref.name == special_idents::statik.name {
self.insert_lifetime(lifetime_ref, ast::DefStaticRegion); self.insert_lifetime(lifetime_ref, DefStaticRegion);
return; return;
} }
self.resolve_lifetime_ref(lifetime_ref, scope); self.resolve_lifetime_ref(lifetime_ref, scope);
} }
} }
impl<'a> ScopeChain<'a> {
fn count_early_params(&self) -> uint {
/*!
* Counts the number of early-bound parameters that are in
* scope. Used when checking methods: the early-bound
* lifetime parameters declared on the method are assigned
* indices that come after the indices from the type. Given
* something like `impl<'a> Foo { ... fn bar<'b>(...) }`
* then `'a` gets index 0 and `'b` gets index 1.
*/
match *self {
RootScope => 0,
EarlyScope(base, lifetimes, _) => base + lifetimes.len(),
LateScope(_, _, s) => s.count_early_params(),
BlockScope(_, _) => 0,
}
}
}
impl<'a> LifetimeContext<'a> { impl<'a> LifetimeContext<'a> {
/// Visits self by adding a scope and handling recursive walk over the contents with `walk`. /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
fn visit_fn_decl(&mut self, fn visit_fn_decl(&mut self,
@ -212,14 +206,11 @@ impl<'a> LifetimeContext<'a> {
self.check_lifetime_names(&generics.lifetimes); self.check_lifetime_names(&generics.lifetimes);
let early_count = scope.count_early_params();
let referenced_idents = free_lifetimes(&generics.ty_params); let referenced_idents = free_lifetimes(&generics.ty_params);
debug!("pushing fn scope id={} due to fn item/method\ debug!("pushing fn scope id={} due to fn item/method\
referenced_idents={:?} \ referenced_idents={:?}",
early_count={}",
n, n,
referenced_idents.iter().map(lifetime_show).collect::<Vec<token::InternedString>>(), referenced_idents.iter().map(lifetime_show).collect::<Vec<token::InternedString>>());
early_count);
if referenced_idents.is_empty() { if referenced_idents.is_empty() {
let scope1 = LateScope(n, &generics.lifetimes, scope); let scope1 = LateScope(n, &generics.lifetimes, scope);
walk(self, &scope1) walk(self, &scope1)
@ -227,7 +218,7 @@ impl<'a> LifetimeContext<'a> {
let (early, late) = generics.lifetimes.clone().partition( let (early, late) = generics.lifetimes.clone().partition(
|l| referenced_idents.iter().any(|&i| i == l.name)); |l| referenced_idents.iter().any(|&i| i == l.name));
let scope1 = EarlyScope(early_count, &early, scope); let scope1 = EarlyScope(subst::FnSpace, &early, scope);
let scope2 = LateScope(n, &late, &scope1); let scope2 = LateScope(n, &late, &scope1);
walk(self, &scope2); walk(self, &scope2);
@ -256,11 +247,10 @@ impl<'a> LifetimeContext<'a> {
break; break;
} }
EarlyScope(base, lifetimes, s) => { EarlyScope(space, lifetimes, s) => {
match search_lifetimes(lifetimes, lifetime_ref) { match search_lifetimes(lifetimes, lifetime_ref) {
Some((offset, decl_id)) => { Some((index, decl_id)) => {
let index = base + offset; let def = DefEarlyBoundRegion(space, index, decl_id);
let def = ast::DefEarlyBoundRegion(index, decl_id);
self.insert_lifetime(lifetime_ref, def); self.insert_lifetime(lifetime_ref, def);
return; return;
} }
@ -274,7 +264,7 @@ impl<'a> LifetimeContext<'a> {
LateScope(binder_id, lifetimes, s) => { LateScope(binder_id, lifetimes, s) => {
match search_lifetimes(lifetimes, lifetime_ref) { match search_lifetimes(lifetimes, lifetime_ref) {
Some((_index, decl_id)) => { Some((_index, decl_id)) => {
let def = ast::DefLateBoundRegion(binder_id, depth, decl_id); let def = DefLateBoundRegion(binder_id, depth, decl_id);
self.insert_lifetime(lifetime_ref, def); self.insert_lifetime(lifetime_ref, def);
return; return;
} }
@ -325,7 +315,7 @@ impl<'a> LifetimeContext<'a> {
match search_result { match search_result {
Some((_depth, decl_id)) => { Some((_depth, decl_id)) => {
let def = ast::DefFreeRegion(scope_id, decl_id); let def = DefFreeRegion(scope_id, decl_id);
self.insert_lifetime(lifetime_ref, def); self.insert_lifetime(lifetime_ref, def);
} }
@ -374,7 +364,7 @@ impl<'a> LifetimeContext<'a> {
fn insert_lifetime(&mut self, fn insert_lifetime(&mut self,
lifetime_ref: &ast::Lifetime, lifetime_ref: &ast::Lifetime,
def: ast::DefRegion) { def: DefRegion) {
if lifetime_ref.id == ast::DUMMY_NODE_ID { if lifetime_ref.id == ast::DUMMY_NODE_ID {
self.sess.span_bug(lifetime_ref.span, self.sess.span_bug(lifetime_ref.span,
"lifetime reference not renumbered, \ "lifetime reference not renumbered, \

View file

@ -231,7 +231,7 @@ impl <'l> DxrVisitor<'l> {
def::DefTyParamBinder(_) | def::DefTyParamBinder(_) |
def::DefLabel(_) | def::DefLabel(_) |
def::DefStaticMethod(_, _, _) | def::DefStaticMethod(_, _, _) |
def::DefTyParam(_, _) | def::DefTyParam(..) |
def::DefUse(_) | def::DefUse(_) |
def::DefMethod(_, _) | def::DefMethod(_, _) |
def::DefPrimTy(_) => { def::DefPrimTy(_) => {

View file

@ -15,10 +15,80 @@ use middle::ty_fold;
use middle::ty_fold::{TypeFoldable, TypeFolder}; use middle::ty_fold::{TypeFoldable, TypeFolder};
use util::ppaux::Repr; use util::ppaux::Repr;
use std::iter::Chain;
use std::mem;
use std::raw;
use std::slice::{Items, MutItems};
use std::vec::Vec; use std::vec::Vec;
use syntax::codemap::Span; use syntax::codemap::{Span, DUMMY_SP};
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// HomogeneousTuple3 trait
//
// This could be moved into standard library at some point.
trait HomogeneousTuple3<T> {
fn len(&self) -> uint;
fn as_slice<'a>(&'a self) -> &'a [T];
fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T];
fn iter<'a>(&'a self) -> Items<'a, T>;
fn mut_iter<'a>(&'a mut self) -> MutItems<'a, T>;
fn get<'a>(&'a self, index: uint) -> Option<&'a T>;
fn get_mut<'a>(&'a mut self, index: uint) -> Option<&'a mut T>;
}
impl<T> HomogeneousTuple3<T> for (T, T, T) {
fn len(&self) -> uint {
3
}
fn as_slice<'a>(&'a self) -> &'a [T] {
unsafe {
let ptr: *T = mem::transmute(self);
let slice = raw::Slice { data: ptr, len: 3 };
mem::transmute(slice)
}
}
fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
unsafe {
let ptr: *T = mem::transmute(self);
let slice = raw::Slice { data: ptr, len: 3 };
mem::transmute(slice)
}
}
fn iter<'a>(&'a self) -> Items<'a, T> {
let slice: &'a [T] = self.as_slice();
slice.iter()
}
fn mut_iter<'a>(&'a mut self) -> MutItems<'a, T> {
self.as_mut_slice().mut_iter()
}
fn get<'a>(&'a self, index: uint) -> Option<&'a T> {
self.as_slice().get(index)
}
fn get_mut<'a>(&'a mut self, index: uint) -> Option<&'a mut T> {
Some(&mut self.as_mut_slice()[index]) // wrong: fallible
}
}
///////////////////////////////////////////////////////////////////////////
/**
* A substitution mapping type/region parameters to new values. We
* identify each in-scope parameter by an *index* and a *parameter
* space* (which indices where the parameter is defined; see
* `ParamSpace`).
*/
#[deriving(Clone, PartialEq, Eq, Hash)]
pub struct Substs {
pub types: VecPerParamSpace<ty::t>,
pub regions: RegionSubsts,
}
/** /**
* Represents the values to use when substituting lifetime parameters. * Represents the values to use when substituting lifetime parameters.
@ -27,46 +97,49 @@ use syntax::codemap::Span;
#[deriving(Clone, PartialEq, Eq, Hash)] #[deriving(Clone, PartialEq, Eq, Hash)]
pub enum RegionSubsts { pub enum RegionSubsts {
ErasedRegions, ErasedRegions,
NonerasedRegions(Vec<ty::Region>) NonerasedRegions(VecPerParamSpace<ty::Region>)
}
/**
* The type `Substs` represents the kinds of things that can be substituted to
* convert a polytype into a monotype. Note however that substituting bound
* regions other than `self` is done through a different mechanism:
*
* - `tps` represents the type parameters in scope. They are indexed
* according to the order in which they were declared.
*
* - `self_r` indicates the region parameter `self` that is present on nominal
* types (enums, structs) declared as having a region parameter. `self_r`
* should always be none for types that are not region-parameterized and
* Some(_) for types that are. The only bound region parameter that should
* appear within a region-parameterized type is `self`.
*
* - `self_ty` is the type to which `self` should be remapped, if any. The
* `self` type is rather funny in that it can only appear on traits and is
* always substituted away to the implementing type for a trait. */
#[deriving(Clone, PartialEq, Eq, Hash)]
pub struct Substs {
pub self_ty: Option<ty::t>,
pub tps: Vec<ty::t>,
pub regions: RegionSubsts,
} }
impl Substs { impl Substs {
pub fn new(t: VecPerParamSpace<ty::t>,
r: VecPerParamSpace<ty::Region>)
-> Substs
{
Substs { types: t, regions: NonerasedRegions(r) }
}
pub fn new_type(t: Vec<ty::t>,
r: Vec<ty::Region>)
-> Substs
{
Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()),
VecPerParamSpace::new(r, Vec::new(), Vec::new()))
}
pub fn new_trait(t: Vec<ty::t>,
r: Vec<ty::Region>,
s: ty::t)
-> Substs
{
Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new()),
VecPerParamSpace::new(r, Vec::new(), Vec::new()))
}
pub fn erased(t: VecPerParamSpace<ty::t>) -> Substs
{
Substs { types: t, regions: ErasedRegions }
}
pub fn empty() -> Substs { pub fn empty() -> Substs {
Substs { Substs {
self_ty: None, types: VecPerParamSpace::empty(),
tps: Vec::new(), regions: NonerasedRegions(VecPerParamSpace::empty()),
regions: NonerasedRegions(Vec::new())
} }
} }
pub fn trans_empty() -> Substs { pub fn trans_empty() -> Substs {
Substs { Substs {
self_ty: None, types: VecPerParamSpace::empty(),
tps: Vec::new(),
regions: ErasedRegions regions: ErasedRegions
} }
} }
@ -74,16 +147,251 @@ impl Substs {
pub fn is_noop(&self) -> bool { pub fn is_noop(&self) -> bool {
let regions_is_noop = match self.regions { let regions_is_noop = match self.regions {
ErasedRegions => false, // may be used to canonicalize ErasedRegions => false, // may be used to canonicalize
NonerasedRegions(ref regions) => regions.is_empty() NonerasedRegions(ref regions) => regions.is_empty(),
}; };
self.tps.len() == 0u && regions_is_noop && self.types.is_empty()
regions_is_noop &&
self.self_ty.is_none()
} }
pub fn self_ty(&self) -> ty::t { pub fn self_ty(&self) -> Option<ty::t> {
self.self_ty.unwrap() self.types.get_self().map(|&t| t)
}
pub fn with_self_ty(&self, self_ty: ty::t) -> Substs {
assert!(self.self_ty().is_none());
let mut s = (*self).clone();
s.types.push(SelfSpace, self_ty);
s
}
pub fn regions<'a>(&'a self) -> &'a VecPerParamSpace<ty::Region> {
/*!
* Since ErasedRegions are only to be used in trans, most of
* the compiler can use this method to easily access the set
* of region substitutions.
*/
match self.regions {
ErasedRegions => fail!("Erased regions only expected in trans"),
NonerasedRegions(ref r) => r
}
}
pub fn mut_regions<'a>(&'a mut self) -> &'a mut VecPerParamSpace<ty::Region> {
/*!
* Since ErasedRegions are only to be used in trans, most of
* the compiler can use this method to easily access the set
* of region substitutions.
*/
match self.regions {
ErasedRegions => fail!("Erased regions only expected in trans"),
NonerasedRegions(ref mut r) => r
}
}
pub fn with_method_from(self, substs: &Substs) -> Substs {
self.with_method((*substs.types.get_vec(FnSpace)).clone(),
(*substs.regions().get_vec(FnSpace)).clone())
}
pub fn with_method(self,
m_types: Vec<ty::t>,
m_regions: Vec<ty::Region>)
-> Substs
{
let Substs { types, regions } = self;
let types = types.with_vec(FnSpace, m_types);
let regions = regions.map(m_regions,
|r, m_regions| r.with_vec(FnSpace, m_regions));
Substs { types: types, regions: regions }
}
}
impl RegionSubsts {
fn map<A>(self,
a: A,
op: |VecPerParamSpace<ty::Region>, A| -> VecPerParamSpace<ty::Region>)
-> RegionSubsts {
match self {
ErasedRegions => ErasedRegions,
NonerasedRegions(r) => NonerasedRegions(op(r, a))
}
}
}
///////////////////////////////////////////////////////////////////////////
// ParamSpace
#[deriving(PartialOrd, Ord, PartialEq, Eq,
Clone, Hash, Encodable, Decodable, Show)]
pub enum ParamSpace {
TypeSpace, // Type parameters attached to a type definition, trait, or impl
SelfSpace, // Self parameter on a trait
FnSpace, // Type parameters attached to a method or fn
}
impl ParamSpace {
pub fn all() -> [ParamSpace, ..3] {
[TypeSpace, SelfSpace, FnSpace]
}
pub fn to_uint(self) -> uint {
match self {
TypeSpace => 0,
SelfSpace => 1,
FnSpace => 2,
}
}
pub fn from_uint(u: uint) -> ParamSpace {
match u {
0 => TypeSpace,
1 => SelfSpace,
2 => FnSpace,
_ => fail!("Invalid ParamSpace: {}", u)
}
}
}
/**
* Vector of things sorted by param space. Used to keep
* the set of things declared on the type, self, or method
* distinct.
*/
#[deriving(PartialEq, Eq, Clone, Hash, Encodable, Decodable)]
pub struct VecPerParamSpace<T> {
vecs: (Vec<T>, Vec<T>, Vec<T>)
}
impl<T> VecPerParamSpace<T> {
pub fn empty() -> VecPerParamSpace<T> {
VecPerParamSpace {
vecs: (Vec::new(), Vec::new(), Vec::new())
}
}
pub fn params_from_type(types: Vec<T>) -> VecPerParamSpace<T> {
VecPerParamSpace::empty().with_vec(TypeSpace, types)
}
pub fn new(t: Vec<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
VecPerParamSpace {
vecs: (t, s, f)
}
}
pub fn sort(t: Vec<T>, space: |&T| -> ParamSpace) -> VecPerParamSpace<T> {
let mut result = VecPerParamSpace::empty();
for t in t.move_iter() {
result.push(space(&t), t);
}
result
}
pub fn push(&mut self, space: ParamSpace, value: T) {
self.get_mut_vec(space).push(value);
}
pub fn get_self<'a>(&'a self) -> Option<&'a T> {
let v = self.get_vec(SelfSpace);
assert!(v.len() <= 1);
if v.len() == 0 { None } else { Some(v.get(0)) }
}
pub fn len(&self, space: ParamSpace) -> uint {
self.get_vec(space).len()
}
pub fn get_vec<'a>(&'a self, space: ParamSpace) -> &'a Vec<T> {
self.vecs.get(space as uint).unwrap()
}
pub fn get_mut_vec<'a>(&'a mut self, space: ParamSpace) -> &'a mut Vec<T> {
self.vecs.get_mut(space as uint).unwrap()
}
pub fn opt_get<'a>(&'a self,
space: ParamSpace,
index: uint)
-> Option<&'a T> {
let v = self.get_vec(space);
if index < v.len() { Some(v.get(index)) } else { None }
}
pub fn get<'a>(&'a self, space: ParamSpace, index: uint) -> &'a T {
self.get_vec(space).get(index)
}
pub fn get_mut<'a>(&'a mut self,
space: ParamSpace,
index: uint) -> &'a mut T {
self.get_mut_vec(space).get_mut(index)
}
pub fn iter<'a>(&'a self) -> Chain<Items<'a,T>,
Chain<Items<'a,T>,
Items<'a,T>>> {
let (ref r, ref s, ref f) = self.vecs;
r.iter().chain(s.iter().chain(f.iter()))
}
pub fn all_vecs(&self, pred: |&Vec<T>| -> bool) -> bool {
self.vecs.iter().all(pred)
}
pub fn all(&self, pred: |&T| -> bool) -> bool {
self.iter().all(pred)
}
pub fn any(&self, pred: |&T| -> bool) -> bool {
self.iter().any(pred)
}
pub fn is_empty(&self) -> bool {
self.all_vecs(|v| v.is_empty())
}
pub fn map<U>(&self, pred: |&T| -> U) -> VecPerParamSpace<U> {
VecPerParamSpace::new(self.vecs.ref0().iter().map(|p| pred(p)).collect(),
self.vecs.ref1().iter().map(|p| pred(p)).collect(),
self.vecs.ref2().iter().map(|p| pred(p)).collect())
}
pub fn map_rev<U>(&self, pred: |&T| -> U) -> VecPerParamSpace<U> {
/*!
* Executes the map but in reverse order. For hacky reasons, we rely
* on this in table.
*
* FIXME(#5527) -- order of eval becomes irrelevant with newer
* trait reform, which features an idempotent algorithm that
* can be run to a fixed point
*/
let mut fns: Vec<U> = self.vecs.ref2().iter().rev().map(|p| pred(p)).collect();
// NB: Calling foo.rev().map().rev() causes the calls to map
// to occur in the wrong order. This was somewhat surprising
// to me, though it makes total sense.
fns.reverse();
let mut selfs: Vec<U> = self.vecs.ref1().iter().rev().map(|p| pred(p)).collect();
selfs.reverse();
let mut tys: Vec<U> = self.vecs.ref0().iter().rev().map(|p| pred(p)).collect();
tys.reverse();
VecPerParamSpace::new(tys, selfs, fns)
}
pub fn split(self) -> (Vec<T>, Vec<T>, Vec<T>) {
self.vecs
}
pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
-> VecPerParamSpace<T>
{
assert!(self.get_vec(space).is_empty());
*self.get_mut_vec(space) = vec;
self
} }
} }
@ -149,10 +457,10 @@ impl<'a> TypeFolder for SubstFolder<'a> {
// the specialized routine // the specialized routine
// `middle::typeck::check::regionmanip::replace_late_regions_in_fn_sig()`. // `middle::typeck::check::regionmanip::replace_late_regions_in_fn_sig()`.
match r { match r {
ty::ReEarlyBound(_, i, _) => { ty::ReEarlyBound(_, space, i, _) => {
match self.substs.regions { match self.substs.regions {
ErasedRegions => ty::ReStatic, ErasedRegions => ty::ReStatic,
NonerasedRegions(ref regions) => *regions.get(i), NonerasedRegions(ref regions) => *regions.get(space, i),
} }
} }
_ => r _ => r
@ -173,52 +481,11 @@ impl<'a> TypeFolder for SubstFolder<'a> {
let t1 = match ty::get(t).sty { let t1 = match ty::get(t).sty {
ty::ty_param(p) => { ty::ty_param(p) => {
// FIXME -- This...really shouldn't happen. We should check(self, t, self.substs.types.opt_get(p.space, p.idx))
// never be substituting without knowing what's in
// scope and knowing that the indices will line up!
if p.idx < self.substs.tps.len() {
*self.substs.tps.get(p.idx)
} else {
let root_msg = match self.root_ty {
Some(root) => format!(" in the substitution of `{}`",
root.repr(self.tcx)),
None => "".to_string()
};
let m = format!("can't use type parameters from outer \
function{}; try using a local type \
parameter instead",
root_msg);
match self.span {
Some(span) => {
self.tcx.sess.span_err(span, m.as_slice())
} }
None => self.tcx.sess.err(m.as_slice()) _ => {
ty_fold::super_fold_ty(self, t)
} }
ty::mk_err()
}
}
ty::ty_self(_) => {
match self.substs.self_ty {
Some(ty) => ty,
None => {
let root_msg = match self.root_ty {
Some(root) => format!(" in the substitution of `{}`",
root.repr(self.tcx)),
None => "".to_string()
};
let m = format!("missing `Self` type param{}",
root_msg);
match self.span {
Some(span) => {
self.tcx.sess.span_err(span, m.as_slice())
}
None => self.tcx.sess.err(m.as_slice())
}
ty::mk_err()
}
}
}
_ => ty_fold::super_fold_ty(self, t)
}; };
assert_eq!(depth + 1, self.ty_stack_depth); assert_eq!(depth + 1, self.ty_stack_depth);
@ -227,6 +494,24 @@ impl<'a> TypeFolder for SubstFolder<'a> {
self.root_ty = None; self.root_ty = None;
} }
t1 return t1;
fn check(this: &SubstFolder,
source_ty: ty::t,
opt_ty: Option<&ty::t>)
-> ty::t {
match opt_ty {
Some(t) => *t,
None => {
let span = this.span.unwrap_or(DUMMY_SP);
this.tcx().sess.span_bug(
span,
format!("Type parameter {} out of range \
when substituting (root type={})",
source_ty.repr(this.tcx()),
this.root_ty.repr(this.tcx())).as_slice());
}
}
}
} }
} }

View file

@ -457,11 +457,11 @@ pub fn get_res_dtor(ccx: &CrateContext,
did did
}; };
if !substs.tps.is_empty() || !substs.self_ty.is_none() { if !substs.types.is_empty() {
assert_eq!(did.krate, ast::LOCAL_CRATE); assert_eq!(did.krate, ast::LOCAL_CRATE);
let vtables = typeck::check::vtable::trans_resolve_method(ccx.tcx(), did.node, substs); let vtables = typeck::check::vtable::trans_resolve_method(ccx.tcx(), did.node, substs);
let (val, _) = monomorphize::monomorphic_fn(ccx, did, substs, vtables, None, None); let (val, _) = monomorphize::monomorphic_fn(ccx, did, substs, vtables, None);
val val
} else if did.krate == ast::LOCAL_CRATE { } else if did.krate == ast::LOCAL_CRATE {

View file

@ -23,7 +23,7 @@ use lib::llvm::llvm;
use metadata::csearch; use metadata::csearch;
use middle::def; use middle::def;
use middle::subst; use middle::subst;
use middle::subst::Subst; use middle::subst::{Subst, VecPerParamSpace};
use middle::trans::base; use middle::trans::base;
use middle::trans::base::*; use middle::trans::base::*;
use middle::trans::build::*; use middle::trans::build::*;
@ -198,12 +198,10 @@ fn trans_fn_ref_with_vtables_to_callee<'a>(bcx: &'a Block<'a>,
fn resolve_default_method_vtables(bcx: &Block, fn resolve_default_method_vtables(bcx: &Block,
impl_id: ast::DefId, impl_id: ast::DefId,
method: &ty::Method,
substs: &subst::Substs, substs: &subst::Substs,
impl_vtables: typeck::vtable_res) impl_vtables: typeck::vtable_res)
-> (typeck::vtable_res, typeck::vtable_param_res) -> typeck::vtable_res
{ {
// Get the vtables that the impl implements the trait at // Get the vtables that the impl implements the trait at
let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id); let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id);
@ -211,22 +209,19 @@ fn resolve_default_method_vtables(bcx: &Block,
// trait_vtables under. // trait_vtables under.
let param_substs = param_substs { let param_substs = param_substs {
substs: (*substs).clone(), substs: (*substs).clone(),
vtables: impl_vtables.clone(), vtables: impl_vtables.clone()
self_vtables: None
}; };
let mut param_vtables = resolve_vtables_under_param_substs( let mut param_vtables = resolve_vtables_under_param_substs(
bcx.tcx(), &param_substs, impl_res.trait_vtables.as_slice()); bcx.tcx(), &param_substs, &impl_res);
// Now we pull any vtables for parameters on the actual method. // Now we pull any vtables for parameters on the actual method.
let num_method_vtables = method.generics.type_param_defs().len(); param_vtables
let num_impl_type_parameters = impl_vtables.len() - num_method_vtables; .get_mut_vec(subst::FnSpace)
param_vtables.push_all(impl_vtables.tailn(num_impl_type_parameters)); .push_all(
impl_vtables.get_vec(subst::FnSpace).as_slice());
let self_vtables = resolve_param_vtables_under_param_substs( param_vtables
bcx.tcx(), &param_substs, impl_res.self_vtables.as_slice());
(param_vtables, self_vtables)
} }
@ -236,7 +231,8 @@ pub fn trans_fn_ref_with_vtables(
node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A
substs: subst::Substs, // values for fn's ty params substs: subst::Substs, // values for fn's ty params
vtables: typeck::vtable_res) // vtables for the call vtables: typeck::vtable_res) // vtables for the call
-> ValueRef { -> ValueRef
{
/*! /*!
* Translates a reference to a fn/method item, monomorphizing and * Translates a reference to a fn/method item, monomorphizing and
* inlining as it goes. * inlining as it goes.
@ -264,7 +260,7 @@ pub fn trans_fn_ref_with_vtables(
substs.repr(tcx), substs.repr(tcx),
vtables.repr(tcx)); vtables.repr(tcx));
assert!(substs.tps.iter().all(|t| !ty::type_needs_infer(*t))); assert!(substs.types.all(|t| !ty::type_needs_infer(*t)));
// Polytype of the function item (may have type params) // Polytype of the function item (may have type params)
let fn_tpt = ty::lookup_item_type(tcx, def_id); let fn_tpt = ty::lookup_item_type(tcx, def_id);
@ -280,9 +276,9 @@ pub fn trans_fn_ref_with_vtables(
// We need to do a bunch of special handling for default methods. // We need to do a bunch of special handling for default methods.
// We need to modify the def_id and our substs in order to monomorphize // We need to modify the def_id and our substs in order to monomorphize
// the function. // the function.
let (is_default, def_id, substs, self_vtables, vtables) = let (is_default, def_id, substs, vtables) =
match ty::provided_source(tcx, def_id) { match ty::provided_source(tcx, def_id) {
None => (false, def_id, substs, None, vtables), None => (false, def_id, substs, vtables),
Some(source_id) => { Some(source_id) => {
// There are two relevant substitutions when compiling // There are two relevant substitutions when compiling
// default methods. First, there is the substitution for // default methods. First, there is the substitution for
@ -305,7 +301,7 @@ pub fn trans_fn_ref_with_vtables(
// Compute the first substitution // Compute the first substitution
let first_subst = make_substs_for_receiver_types( let first_subst = make_substs_for_receiver_types(
tcx, impl_id, &*trait_ref, &*method); tcx, &*trait_ref, &*method);
// And compose them // And compose them
let new_substs = first_subst.subst(tcx, &substs); let new_substs = first_subst.subst(tcx, &substs);
@ -318,16 +314,14 @@ pub fn trans_fn_ref_with_vtables(
first_subst.repr(tcx), new_substs.repr(tcx), first_subst.repr(tcx), new_substs.repr(tcx),
vtables.repr(tcx)); vtables.repr(tcx));
let (param_vtables, self_vtables) = let param_vtables =
resolve_default_method_vtables(bcx, impl_id, resolve_default_method_vtables(bcx, impl_id, &substs, vtables);
&*method, &substs, vtables);
debug!("trans_fn_with_vtables - default method: \ debug!("trans_fn_with_vtables - default method: \
self_vtable = {}, param_vtables = {}", param_vtables = {}",
self_vtables.repr(tcx), param_vtables.repr(tcx)); param_vtables.repr(tcx));
(true, source_id, (true, source_id, new_substs, param_vtables)
new_substs, Some(self_vtables), param_vtables)
} }
}; };
@ -345,7 +339,7 @@ pub fn trans_fn_ref_with_vtables(
// intrinsic, or is a default method. In particular, if we see an // intrinsic, or is a default method. In particular, if we see an
// intrinsic that is inlined from a different crate, we want to reemit the // intrinsic that is inlined from a different crate, we want to reemit the
// intrinsic instead of trying to call it in the other crate. // intrinsic instead of trying to call it in the other crate.
let must_monomorphise = if substs.tps.len() > 0 || is_default { let must_monomorphise = if !substs.types.is_empty() || is_default {
true true
} else if def_id.krate == ast::LOCAL_CRATE { } else if def_id.krate == ast::LOCAL_CRATE {
let map_node = session::expect( let map_node = session::expect(
@ -375,8 +369,7 @@ pub fn trans_fn_ref_with_vtables(
let (val, must_cast) = let (val, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, &substs, monomorphize::monomorphic_fn(ccx, def_id, &substs,
vtables, self_vtables, vtables, opt_ref_id);
opt_ref_id);
let mut val = val; let mut val = val;
if must_cast && node != ExprId(0) { if must_cast && node != ExprId(0) {
// Monotype of the REFERENCE to the function (type params // Monotype of the REFERENCE to the function (type params
@ -498,7 +491,7 @@ pub fn trans_lang_call<'a>(
did, did,
0, 0,
subst::Substs::empty(), subst::Substs::empty(),
Vec::new()) VecPerParamSpace::empty())
}, },
ArgVals(args), ArgVals(args),
dest) dest)

View file

@ -181,25 +181,18 @@ pub type ExternMap = HashMap<String, ValueRef>;
pub struct param_substs { pub struct param_substs {
pub substs: subst::Substs, pub substs: subst::Substs,
pub vtables: typeck::vtable_res, pub vtables: typeck::vtable_res,
pub self_vtables: Option<typeck::vtable_param_res>
} }
impl param_substs { impl param_substs {
pub fn empty() -> param_substs { pub fn empty() -> param_substs {
param_substs { param_substs {
substs: subst::Substs::trans_empty(), substs: subst::Substs::trans_empty(),
vtables: Vec::new(), vtables: subst::VecPerParamSpace::empty(),
self_vtables: None
} }
} }
pub fn validate(&self) { pub fn validate(&self) {
for t in self.substs.tps.iter() { assert!(self.substs.types.all(|t| !ty::type_needs_infer(*t)));
assert!(!ty::type_needs_infer(*t));
}
for t in self.substs.self_ty.iter() {
assert!(!ty::type_needs_infer(*t));
}
} }
} }
@ -738,7 +731,7 @@ pub fn node_id_substs(bcx: &Block,
} }
}; };
if !substs.tps.iter().all(|t| !ty::type_needs_infer(*t)) { if substs.types.any(|t| ty::type_needs_infer(*t)) {
bcx.sess().bug( bcx.sess().bug(
format!("type parameters for node {:?} include inference types: \ format!("type parameters for node {:?} include inference types: \
{}", {}",
@ -752,14 +745,14 @@ pub fn node_id_substs(bcx: &Block,
pub fn node_vtables(bcx: &Block, id: typeck::MethodCall) pub fn node_vtables(bcx: &Block, id: typeck::MethodCall)
-> typeck::vtable_res { -> typeck::vtable_res {
bcx.tcx().vtable_map.borrow().find(&id).map(|vts| { bcx.tcx().vtable_map.borrow().find(&id).map(|vts| {
resolve_vtables_in_fn_ctxt(bcx.fcx, vts.as_slice()) resolve_vtables_in_fn_ctxt(bcx.fcx, vts)
}).unwrap_or_else(|| Vec::new()) }).unwrap_or_else(|| subst::VecPerParamSpace::empty())
} }
// Apply the typaram substitutions in the FunctionContext to some // Apply the typaram substitutions in the FunctionContext to some
// vtables. This should eliminate any vtable_params. // vtables. This should eliminate any vtable_params.
pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext,
vts: &[typeck::vtable_param_res]) vts: &typeck::vtable_res)
-> typeck::vtable_res { -> typeck::vtable_res {
resolve_vtables_under_param_substs(fcx.ccx.tcx(), resolve_vtables_under_param_substs(fcx.ccx.tcx(),
fcx.param_substs, fcx.param_substs,
@ -768,20 +761,21 @@ pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext,
pub fn resolve_vtables_under_param_substs(tcx: &ty::ctxt, pub fn resolve_vtables_under_param_substs(tcx: &ty::ctxt,
param_substs: &param_substs, param_substs: &param_substs,
vts: &[typeck::vtable_param_res]) vts: &typeck::vtable_res)
-> typeck::vtable_res { -> typeck::vtable_res
vts.iter().map(|ds| { {
vts.map(|ds| {
resolve_param_vtables_under_param_substs(tcx, resolve_param_vtables_under_param_substs(tcx,
param_substs, param_substs,
ds.as_slice()) ds)
}).collect() })
} }
pub fn resolve_param_vtables_under_param_substs( pub fn resolve_param_vtables_under_param_substs(tcx: &ty::ctxt,
tcx: &ty::ctxt,
param_substs: &param_substs, param_substs: &param_substs,
ds: &[typeck::vtable_origin]) ds: &typeck::vtable_param_res)
-> typeck::vtable_param_res { -> typeck::vtable_param_res
{
ds.iter().map(|d| { ds.iter().map(|d| {
resolve_vtable_under_param_substs(tcx, resolve_vtable_under_param_substs(tcx,
param_substs, param_substs,
@ -794,17 +788,20 @@ pub fn resolve_param_vtables_under_param_substs(
pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt, pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt,
param_substs: &param_substs, param_substs: &param_substs,
vt: &typeck::vtable_origin) vt: &typeck::vtable_origin)
-> typeck::vtable_origin { -> typeck::vtable_origin
{
match *vt { match *vt {
typeck::vtable_static(trait_id, ref vtable_substs, ref sub) => { typeck::vtable_static(trait_id, ref vtable_substs, ref sub) => {
let vtable_substs = vtable_substs.substp(tcx, param_substs); let vtable_substs = vtable_substs.substp(tcx, param_substs);
typeck::vtable_static( typeck::vtable_static(
trait_id, vtable_substs, trait_id,
resolve_vtables_under_param_substs(tcx, param_substs, sub.as_slice())) vtable_substs,
resolve_vtables_under_param_substs(tcx, param_substs, sub))
} }
typeck::vtable_param(n_param, n_bound) => { typeck::vtable_param(n_param, n_bound) => {
find_vtable(tcx, param_substs, n_param, n_bound) find_vtable(tcx, param_substs, n_param, n_bound)
} }
typeck::vtable_error => typeck::vtable_error
} }
} }
@ -816,12 +813,8 @@ pub fn find_vtable(tcx: &ty::ctxt,
debug!("find_vtable(n_param={:?}, n_bound={}, ps={})", debug!("find_vtable(n_param={:?}, n_bound={}, ps={})",
n_param, n_bound, ps.repr(tcx)); n_param, n_bound, ps.repr(tcx));
let param_bounds = match n_param { let param_bounds = ps.vtables.get(n_param.space,
typeck::param_self => ps.self_vtables.as_ref().expect("self vtables missing"), n_param.index);
typeck::param_numbered(n) => {
ps.vtables.get(n)
}
};
param_bounds.get(n_bound).clone() param_bounds.get(n_bound).clone()
} }

View file

@ -520,10 +520,11 @@ impl TypeMap {
// Maybe check that there is no self type here // Maybe check that there is no self type here
if substs.tps.len() > 0 { let tps = substs.types.get_vec(subst::TypeSpace);
if tps.len() > 0 {
output.push_char('<'); output.push_char('<');
for &type_parameter in substs.tps.iter() { for &type_parameter in tps.iter() {
let param_type_id = type_map.get_unique_type_id_of_type(cx, type_parameter); let param_type_id = type_map.get_unique_type_id_of_type(cx, type_parameter);
let param_type_id = type_map.get_unique_type_id_as_string(param_type_id); let param_type_id = type_map.get_unique_type_id_as_string(param_type_id);
output.push_str(param_type_id.as_slice()); output.push_str(param_type_id.as_slice());
@ -1209,7 +1210,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
file_metadata: DIFile, file_metadata: DIFile,
name_to_append_suffix_to: &mut String) name_to_append_suffix_to: &mut String)
-> DIArray { -> DIArray {
let self_type = param_substs.substs.self_ty; let self_type = param_substs.substs.self_ty();
// Only true for static default methods: // Only true for static default methods:
let has_self_type = self_type.is_some(); let has_self_type = self_type.is_some();
@ -1263,7 +1264,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
} }
// Handle other generic parameters // Handle other generic parameters
let actual_types = &param_substs.substs.tps; let actual_types = param_substs.substs.types.get_vec(subst::FnSpace);
for (index, &ast::TyParam{ ident: ident, .. }) in generics.ty_params.iter().enumerate() { for (index, &ast::TyParam{ ident: ident, .. }) in generics.ty_params.iter().enumerate() {
let actual_type = *actual_types.get(index); let actual_type = *actual_types.get(index);
// Add actual type name to <...> clause of function name // Add actual type name to <...> clause of function name
@ -2733,13 +2734,11 @@ fn trait_metadata(cx: &CrateContext,
let ident_string = token::get_name(last.name()); let ident_string = token::get_name(last.name());
let mut name = ppaux::trait_store_to_str(cx.tcx(), trait_store); let mut name = ppaux::trait_store_to_str(cx.tcx(), trait_store);
name.push_str(ident_string.get()); name.push_str(ident_string.get());
// Add type and region parameters // Add type and region parameters
let name = ppaux::parameterized(cx.tcx(), let trait_def = ty::lookup_trait_def(cx.tcx(), def_id);
name.as_slice(), let name = ppaux::parameterized(cx.tcx(), name.as_slice(),
&substs.regions, substs, &trait_def.generics);
substs.tps.as_slice(),
def_id,
true);
let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id); let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id);

View file

@ -125,11 +125,11 @@ pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
if is_provided { return local_def(mth.id); } if is_provided { return local_def(mth.id); }
let impl_tpt = ty::lookup_item_type(ccx.tcx(), impl_did); let impl_tpt = ty::lookup_item_type(ccx.tcx(), impl_did);
let num_type_params = let unparameterized =
impl_tpt.generics.type_param_defs().len() + impl_tpt.generics.types.is_empty() &&
mth.generics.ty_params.len(); mth.generics.ty_params.is_empty();
if num_type_params == 0 { if unparameterized {
let llfn = get_item_val(ccx, mth.id); let llfn = get_item_val(ccx, mth.id);
trans_fn(ccx, &*mth.decl, &*mth.body, llfn, trans_fn(ccx, &*mth.decl, &*mth.body, llfn,
&param_substs::empty(), mth.id, []); &param_substs::empty(), mth.id, []);

View file

@ -14,6 +14,7 @@ use arena::TypedArena;
use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg}; use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg};
use lib::llvm::{ValueRef, Pointer, Array, Struct}; use lib::llvm::{ValueRef, Pointer, Array, Struct};
use lib; use lib;
use middle::subst::FnSpace;
use middle::trans::base::*; use middle::trans::base::*;
use middle::trans::build::*; use middle::trans::build::*;
use middle::trans::common::*; use middle::trans::common::*;
@ -295,7 +296,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
RetVoid(bcx); RetVoid(bcx);
} }
"size_of" => { "size_of" => {
let tp_ty = *substs.substs.tps.get(0); let tp_ty = *substs.substs.types.get(FnSpace, 0);
let lltp_ty = type_of::type_of(ccx, tp_ty); let lltp_ty = type_of::type_of(ccx, tp_ty);
Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty) as uint)); Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty) as uint));
} }
@ -305,7 +306,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
// if the value is non-immediate. Note that, with // if the value is non-immediate. Note that, with
// intrinsics, there are no argument cleanups to // intrinsics, there are no argument cleanups to
// concern ourselves with, so we can use an rvalue datum. // concern ourselves with, so we can use an rvalue datum.
let tp_ty = *substs.substs.tps.get(0); let tp_ty = *substs.substs.types.get(FnSpace, 0);
let mode = appropriate_rvalue_mode(ccx, tp_ty); let mode = appropriate_rvalue_mode(ccx, tp_ty);
let src = Datum {val: get_param(decl, first_real_arg + 1u), let src = Datum {val: get_param(decl, first_real_arg + 1u),
ty: tp_ty, ty: tp_ty,
@ -314,17 +315,17 @@ pub fn trans_intrinsic(ccx: &CrateContext,
RetVoid(bcx); RetVoid(bcx);
} }
"min_align_of" => { "min_align_of" => {
let tp_ty = *substs.substs.tps.get(0); let tp_ty = *substs.substs.types.get(FnSpace, 0);
let lltp_ty = type_of::type_of(ccx, tp_ty); let lltp_ty = type_of::type_of(ccx, tp_ty);
Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty) as uint)); Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty) as uint));
} }
"pref_align_of"=> { "pref_align_of"=> {
let tp_ty = *substs.substs.tps.get(0); let tp_ty = *substs.substs.types.get(FnSpace, 0);
let lltp_ty = type_of::type_of(ccx, tp_ty); let lltp_ty = type_of::type_of(ccx, tp_ty);
Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty) as uint)); Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty) as uint));
} }
"get_tydesc" => { "get_tydesc" => {
let tp_ty = *substs.substs.tps.get(0); let tp_ty = *substs.substs.types.get(FnSpace, 0);
let static_ti = get_tydesc(ccx, tp_ty); let static_ti = get_tydesc(ccx, tp_ty);
glue::lazily_emit_visit_glue(ccx, &*static_ti); glue::lazily_emit_visit_glue(ccx, &*static_ti);
@ -339,7 +340,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
"type_id" => { "type_id" => {
let hash = ty::hash_crate_independent( let hash = ty::hash_crate_independent(
ccx.tcx(), ccx.tcx(),
*substs.substs.tps.get(0), *substs.substs.types.get(FnSpace, 0),
&ccx.link_meta.crate_hash); &ccx.link_meta.crate_hash);
// NB: This needs to be kept in lockstep with the TypeId struct in // NB: This needs to be kept in lockstep with the TypeId struct in
// libstd/unstable/intrinsics.rs // libstd/unstable/intrinsics.rs
@ -354,7 +355,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
} }
} }
"init" => { "init" => {
let tp_ty = *substs.substs.tps.get(0); let tp_ty = *substs.substs.types.get(FnSpace, 0);
let lltp_ty = type_of::type_of(ccx, tp_ty); let lltp_ty = type_of::type_of(ccx, tp_ty);
match bcx.fcx.llretptr.get() { match bcx.fcx.llretptr.get() {
Some(ptr) => { Store(bcx, C_null(lltp_ty), ptr); RetVoid(bcx); } Some(ptr) => { Store(bcx, C_null(lltp_ty), ptr); RetVoid(bcx); }
@ -364,7 +365,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
} }
"uninit" => { "uninit" => {
// Do nothing, this is effectively a no-op // Do nothing, this is effectively a no-op
let retty = *substs.substs.tps.get(0); let retty = *substs.substs.types.get(FnSpace, 0);
if type_is_immediate(ccx, retty) && !return_type_is_void(ccx, retty) { if type_is_immediate(ccx, retty) && !return_type_is_void(ccx, retty) {
unsafe { unsafe {
Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref())); Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref()));
@ -377,8 +378,8 @@ pub fn trans_intrinsic(ccx: &CrateContext,
RetVoid(bcx); RetVoid(bcx);
} }
"transmute" => { "transmute" => {
let (in_type, out_type) = (*substs.substs.tps.get(0), let (in_type, out_type) = (*substs.substs.types.get(FnSpace, 0),
*substs.substs.tps.get(1)); *substs.substs.types.get(FnSpace, 1));
let llintype = type_of::type_of(ccx, in_type); let llintype = type_of::type_of(ccx, in_type);
let llouttype = type_of::type_of(ccx, out_type); let llouttype = type_of::type_of(ccx, out_type);
@ -447,11 +448,11 @@ pub fn trans_intrinsic(ccx: &CrateContext,
} }
} }
"needs_drop" => { "needs_drop" => {
let tp_ty = *substs.substs.tps.get(0); let tp_ty = *substs.substs.types.get(FnSpace, 0);
Ret(bcx, C_bool(ccx, ty::type_needs_drop(ccx.tcx(), tp_ty))); Ret(bcx, C_bool(ccx, ty::type_needs_drop(ccx.tcx(), tp_ty)));
} }
"owns_managed" => { "owns_managed" => {
let tp_ty = *substs.substs.tps.get(0); let tp_ty = *substs.substs.types.get(FnSpace, 0);
Ret(bcx, C_bool(ccx, ty::type_contents(ccx.tcx(), tp_ty).owns_managed())); Ret(bcx, C_bool(ccx, ty::type_contents(ccx.tcx(), tp_ty).owns_managed()));
} }
"visit_tydesc" => { "visit_tydesc" => {
@ -468,19 +469,26 @@ pub fn trans_intrinsic(ccx: &CrateContext,
Ret(bcx, lladdr); Ret(bcx, lladdr);
} }
"copy_nonoverlapping_memory" => { "copy_nonoverlapping_memory" => {
copy_intrinsic(bcx, false, false, *substs.substs.tps.get(0)) copy_intrinsic(bcx, false, false, *substs.substs.types.get(FnSpace, 0))
} }
"copy_memory" => { "copy_memory" => {
copy_intrinsic(bcx, true, false, *substs.substs.tps.get(0)) copy_intrinsic(bcx, true, false, *substs.substs.types.get(FnSpace, 0))
} }
"set_memory" => { "set_memory" => {
memset_intrinsic(bcx, false, *substs.substs.tps.get(0)) memset_intrinsic(bcx, false, *substs.substs.types.get(FnSpace, 0))
} }
"volatile_copy_nonoverlapping_memory" => "volatile_copy_nonoverlapping_memory" => {
copy_intrinsic(bcx, false, true, *substs.substs.tps.get(0)), copy_intrinsic(bcx, false, true, *substs.substs.types.get(FnSpace, 0))
"volatile_copy_memory" => copy_intrinsic(bcx, true, true, *substs.substs.tps.get(0)), }
"volatile_set_memory" => memset_intrinsic(bcx, true, *substs.substs.tps.get(0)),
"volatile_copy_memory" => {
copy_intrinsic(bcx, true, true, *substs.substs.types.get(FnSpace, 0))
}
"volatile_set_memory" => {
memset_intrinsic(bcx, true, *substs.substs.types.get(FnSpace, 0))
}
"ctlz8" => count_zeros_intrinsic(bcx, "llvm.ctlz.i8"), "ctlz8" => count_zeros_intrinsic(bcx, "llvm.ctlz.i8"),
"ctlz16" => count_zeros_intrinsic(bcx, "llvm.ctlz.i16"), "ctlz16" => count_zeros_intrinsic(bcx, "llvm.ctlz.i16"),

View file

@ -155,22 +155,6 @@ pub fn trans_static_method_callee(bcx: &Block,
ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id); ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id);
// When we translate a static fn defined in a trait like:
//
// trait<T1...Tn> Trait {
// fn foo<M1...Mn>(...) {...}
// }
//
// this winds up being translated as something like:
//
// fn foo<T1...Tn,self: Trait<T1...Tn>,M1...Mn>(...) {...}
//
// So when we see a call to this function foo, we have to figure
// out which impl the `Trait<T1...Tn>` bound on the type `self` was
// bound to.
let bound_index = ty::lookup_trait_def(bcx.tcx(), trait_id).
generics.type_param_defs().len();
let mname = if method_id.krate == ast::LOCAL_CRATE { let mname = if method_id.krate == ast::LOCAL_CRATE {
match bcx.tcx().map.get(method_id.node) { match bcx.tcx().map.get(method_id.node) {
ast_map::NodeTraitMethod(method) => { ast_map::NodeTraitMethod(method) => {
@ -189,18 +173,19 @@ pub fn trans_static_method_callee(bcx: &Block,
name={}", method_id, expr_id, token::get_name(mname)); name={}", method_id, expr_id, token::get_name(mname));
let vtable_key = MethodCall::expr(expr_id); let vtable_key = MethodCall::expr(expr_id);
let vtbls = resolve_vtables_in_fn_ctxt(bcx.fcx, ccx.tcx.vtable_map.borrow() let vtbls = resolve_vtables_in_fn_ctxt(
.get(&vtable_key).as_slice()); bcx.fcx,
ccx.tcx.vtable_map.borrow().get(&vtable_key));
match vtbls.move_iter().nth(bound_index).unwrap().move_iter().nth(0).unwrap() { match *vtbls.get_self().unwrap().get(0) {
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => { typeck::vtable_static(impl_did, ref rcvr_substs, ref rcvr_origins) => {
assert!(rcvr_substs.tps.iter().all(|t| !ty::type_needs_infer(*t))); assert!(rcvr_substs.types.all(|t| !ty::type_needs_infer(*t)));
let mth_id = method_with_name(ccx, impl_did, mname); let mth_id = method_with_name(ccx, impl_did, mname);
let (callee_substs, callee_origins) = let (callee_substs, callee_origins) =
combine_impl_and_methods_tps( combine_impl_and_methods_tps(
bcx, mth_id, ExprId(expr_id), bcx, ExprId(expr_id),
rcvr_substs, rcvr_origins); (*rcvr_substs).clone(), (*rcvr_origins).clone());
let llfn = trans_fn_ref_with_vtables(bcx, mth_id, ExprId(expr_id), let llfn = trans_fn_ref_with_vtables(bcx, mth_id, ExprId(expr_id),
callee_substs, callee_substs,
@ -252,8 +237,7 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
// those from the impl and those from the method: // those from the impl and those from the method:
let (callee_substs, callee_origins) = let (callee_substs, callee_origins) =
combine_impl_and_methods_tps( combine_impl_and_methods_tps(
bcx, mth_id, MethodCall(method_call), bcx, MethodCall(method_call), rcvr_substs, rcvr_origins);
rcvr_substs, rcvr_origins);
// translate the function // translate the function
let llfn = trans_fn_ref_with_vtables(bcx, let llfn = trans_fn_ref_with_vtables(bcx,
@ -265,13 +249,17 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
Callee { bcx: bcx, data: Fn(llfn) } Callee { bcx: bcx, data: Fn(llfn) }
} }
typeck::vtable_param(..) => { typeck::vtable_param(..) => {
fail!("vtable_param left in monomorphized function's vtable substs"); bcx.tcx().sess.bug(
"vtable_param left in monomorphized function's vtable substs");
}
typeck::vtable_error => {
bcx.tcx().sess.bug(
"vtable_error left in monomorphized function's vtable substs");
} }
} }
} }
fn combine_impl_and_methods_tps(bcx: &Block, fn combine_impl_and_methods_tps(bcx: &Block,
mth_did: ast::DefId,
node: ExprOrMethodCall, node: ExprOrMethodCall,
rcvr_substs: subst::Substs, rcvr_substs: subst::Substs,
rcvr_origins: typeck::vtable_res) rcvr_origins: typeck::vtable_res)
@ -295,38 +283,33 @@ fn combine_impl_and_methods_tps(bcx: &Block,
*/ */
let ccx = bcx.ccx(); let ccx = bcx.ccx();
let method = ty::method(ccx.tcx(), mth_did);
let n_m_tps = method.generics.type_param_defs().len();
let node_substs = node_id_substs(bcx, node);
debug!("rcvr_substs={:?}", rcvr_substs.repr(ccx.tcx()));
debug!("node_substs={:?}", node_substs.repr(ccx.tcx()));
let rcvr_self_ty = rcvr_substs.self_ty;
let mut tps = rcvr_substs.tps;
{
let start = node_substs.tps.len() - n_m_tps;
tps.extend(node_substs.tps.move_iter().skip(start));
}
debug!("n_m_tps={:?}", n_m_tps);
debug!("tps={}", tps.repr(ccx.tcx()));
// Now, do the same work for the vtables. The vtables might not
// exist, in which case we need to make them.
let vtable_key = match node { let vtable_key = match node {
ExprId(id) => MethodCall::expr(id), ExprId(id) => MethodCall::expr(id),
MethodCall(method_call) => method_call MethodCall(method_call) => method_call
}; };
let mut vtables = rcvr_origins; let node_substs = node_id_substs(bcx, node);
let vt = node_vtables(bcx, vtable_key); let node_vtables = node_vtables(bcx, vtable_key);
let start = vt.len() - n_m_tps;
vtables.extend(vt.move_iter().skip(start));
debug!("rcvr_substs={:?}", rcvr_substs.repr(ccx.tcx()));
debug!("node_substs={:?}", node_substs.repr(ccx.tcx()));
// Break apart the type parameters from the node and type
// parameters from the receiver.
let (_, _, node_method) = node_substs.types.split();
let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.clone().split();
assert!(rcvr_method.is_empty());
let ty_substs = subst::Substs { let ty_substs = subst::Substs {
tps: tps,
regions: subst::ErasedRegions, regions: subst::ErasedRegions,
self_ty: rcvr_self_ty types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method)
}; };
// Now do the same work for the vtables.
let (rcvr_type, rcvr_self, rcvr_method) = rcvr_origins.split();
let (_, _, node_method) = node_vtables.split();
assert!(rcvr_method.is_empty());
let vtables = subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method);
(ty_substs, vtables) (ty_substs, vtables)
} }
@ -426,7 +409,12 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>,
fn get_vtable(bcx: &Block, fn get_vtable(bcx: &Block,
self_ty: ty::t, self_ty: ty::t,
origins: typeck::vtable_param_res) origins: typeck::vtable_param_res)
-> ValueRef { -> ValueRef
{
debug!("get_vtable(self_ty={}, origins={})",
self_ty.repr(bcx.tcx()),
origins.repr(bcx.tcx()));
let ccx = bcx.ccx(); let ccx = bcx.ccx();
let _icx = push_ctxt("meth::get_vtable"); let _icx = push_ctxt("meth::get_vtable");
@ -503,8 +491,9 @@ fn emit_vtable_methods(bcx: &Block,
debug!("(making impl vtable) emitting method {} at subst {}", debug!("(making impl vtable) emitting method {} at subst {}",
m.repr(tcx), m.repr(tcx),
substs.repr(tcx)); substs.repr(tcx));
if m.generics.has_type_params() || if m.generics.has_type_params(subst::FnSpace) ||
ty::type_has_self(ty::mk_bare_fn(tcx, m.fty.clone())) { ty::type_has_self(ty::mk_bare_fn(tcx, m.fty.clone()))
{
debug!("(making impl vtable) method has self or type params: {}", debug!("(making impl vtable) method has self or type params: {}",
token::get_ident(ident)); token::get_ident(ident));
C_null(Type::nil(ccx).ptr_to()) C_null(Type::nil(ccx).ptr_to())
@ -551,7 +540,7 @@ pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>,
let vtable_map = ccx.tcx.vtable_map.borrow(); let vtable_map = ccx.tcx.vtable_map.borrow();
resolve_param_vtables_under_param_substs(ccx.tcx(), resolve_param_vtables_under_param_substs(ccx.tcx(),
bcx.fcx.param_substs, bcx.fcx.param_substs,
vtable_map.get(&MethodCall::expr(id)).get(0).as_slice()) vtable_map.get(&MethodCall::expr(id)).get_self().unwrap())
}; };
let vtable = get_vtable(bcx, v_ty, origins); let vtable = get_vtable(bcx, v_ty, origins);
let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]); let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]);

View file

@ -33,32 +33,27 @@ pub fn monomorphic_fn(ccx: &CrateContext,
fn_id: ast::DefId, fn_id: ast::DefId,
real_substs: &subst::Substs, real_substs: &subst::Substs,
vtables: typeck::vtable_res, vtables: typeck::vtable_res,
self_vtables: Option<typeck::vtable_param_res>,
ref_id: Option<ast::NodeId>) ref_id: Option<ast::NodeId>)
-> (ValueRef, bool) { -> (ValueRef, bool) {
debug!("monomorphic_fn(\ debug!("monomorphic_fn(\
fn_id={}, \ fn_id={}, \
real_substs={}, \ real_substs={}, \
vtables={}, \ vtables={}, \
self_vtable={}, \
ref_id={:?})", ref_id={:?})",
fn_id.repr(ccx.tcx()), fn_id.repr(ccx.tcx()),
real_substs.repr(ccx.tcx()), real_substs.repr(ccx.tcx()),
vtables.repr(ccx.tcx()), vtables.repr(ccx.tcx()),
self_vtables.repr(ccx.tcx()),
ref_id); ref_id);
assert!(real_substs.tps.iter().all(|t| { assert!(real_substs.types.all(|t| {
!ty::type_needs_infer(*t) && !ty::type_has_params(*t) !ty::type_needs_infer(*t) && !ty::type_has_params(*t)
})); }));
let _icx = push_ctxt("monomorphic_fn"); let _icx = push_ctxt("monomorphic_fn");
let substs_iter = real_substs.self_ty.iter().chain(real_substs.tps.iter());
let param_ids: Vec<ty::t> = substs_iter.map(|t| *t).collect();
let hash_id = MonoId { let hash_id = MonoId {
def: fn_id, def: fn_id,
params: param_ids params: real_substs.types.clone()
}; };
match ccx.monomorphized.borrow().find(&hash_id) { match ccx.monomorphized.borrow().find(&hash_id) {
@ -73,7 +68,6 @@ pub fn monomorphic_fn(ccx: &CrateContext,
let psubsts = param_substs { let psubsts = param_substs {
substs: (*real_substs).clone(), substs: (*real_substs).clone(),
vtables: vtables, vtables: vtables,
self_vtables: self_vtables
}; };
debug!("monomorphic_fn(\ debug!("monomorphic_fn(\
@ -87,10 +81,6 @@ pub fn monomorphic_fn(ccx: &CrateContext,
let tpt = ty::lookup_item_type(ccx.tcx(), fn_id); let tpt = ty::lookup_item_type(ccx.tcx(), fn_id);
let llitem_ty = tpt.ty; let llitem_ty = tpt.ty;
// We need to do special handling of the substitutions if we are
// calling a static provided method. This is sort of unfortunate.
let mut is_static_provided = None;
let map_node = session::expect( let map_node = session::expect(
ccx.sess(), ccx.sess(),
ccx.tcx.map.find(fn_id.node), ccx.tcx.map.find(fn_id.node),
@ -108,55 +98,11 @@ pub fn monomorphic_fn(ccx: &CrateContext,
return (get_item_val(ccx, fn_id.node), true); return (get_item_val(ccx, fn_id.node), true);
} }
} }
ast_map::NodeTraitMethod(method) => {
match *method {
ast::Provided(m) => {
// If this is a static provided method, indicate that
// and stash the number of params on the method.
if m.explicit_self.node == ast::SelfStatic {
is_static_provided = Some(m.generics.ty_params.len());
}
}
_ => {}
}
}
_ => {} _ => {}
} }
debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx())); debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx()));
let mono_ty = match is_static_provided { let mono_ty = llitem_ty.subst(ccx.tcx(), real_substs);
None => llitem_ty.subst(ccx.tcx(), real_substs),
Some(num_method_ty_params) => {
// Static default methods are a little unfortunate, in
// that the "internal" and "external" type of them differ.
// Internally, the method body can refer to Self, but the
// externally visible type of the method has a type param
// inserted in between the trait type params and the
// method type params. The substs that we are given are
// the proper substs *internally* to the method body, so
// we have to use those when compiling it.
//
// In order to get the proper substitution to use on the
// type of the method, we pull apart the substitution and
// stick a substitution for the self type in.
// This is a bit unfortunate.
let idx = real_substs.tps.len() - num_method_ty_params;
let mut tps = Vec::new();
tps.push_all(real_substs.tps.slice(0, idx));
tps.push(real_substs.self_ty.unwrap());
tps.push_all(real_substs.tps.tailn(idx));
let substs = subst::Substs { regions: subst::ErasedRegions,
self_ty: None,
tps: tps };
debug!("static default: changed substitution to {}",
substs.repr(ccx.tcx()));
llitem_ty.subst(ccx.tcx(), &substs)
}
};
ccx.stats.n_monos.set(ccx.stats.n_monos.get() + 1); ccx.stats.n_monos.set(ccx.stats.n_monos.get() + 1);
@ -306,7 +252,7 @@ pub struct MonoParamId {
#[deriving(PartialEq, Eq, Hash)] #[deriving(PartialEq, Eq, Hash)]
pub struct MonoId { pub struct MonoId {
pub def: ast::DefId, pub def: ast::DefId,
pub params: Vec<ty::t> pub params: subst::VecPerParamSpace<ty::t>
} }
pub fn make_vtable_id(_ccx: &CrateContext, pub fn make_vtable_id(_ccx: &CrateContext,
@ -316,7 +262,7 @@ pub fn make_vtable_id(_ccx: &CrateContext,
&typeck::vtable_static(impl_id, ref substs, _) => { &typeck::vtable_static(impl_id, ref substs, _) => {
MonoId { MonoId {
def: impl_id, def: impl_id,
params: substs.tps.iter().map(|subst| *subst).collect() params: substs.types.clone()
} }
} }

View file

@ -366,7 +366,6 @@ impl<'a, 'b> Reflector<'a, 'b> {
let extra = vec!(self.c_uint(p.idx)); let extra = vec!(self.c_uint(p.idx));
self.visit("param", extra.as_slice()) self.visit("param", extra.as_slice())
} }
ty::ty_self(..) => self.leaf("self")
} }
} }

View file

@ -15,7 +15,6 @@ use middle::trans::adt;
use middle::trans::common::*; use middle::trans::common::*;
use middle::trans::foreign; use middle::trans::foreign;
use middle::ty; use middle::ty;
use util::ppaux;
use util::ppaux::Repr; use util::ppaux::Repr;
use middle::trans::type_::Type; use middle::trans::type_::Type;
@ -152,7 +151,7 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
} }
} }
ty::ty_self(_) | ty::ty_infer(..) | ty::ty_param(..) | ty::ty_infer(..) | ty::ty_param(..) |
ty::ty_err(..) | ty::ty_vec(_, None) | ty::ty_str => { ty::ty_err(..) | ty::ty_vec(_, None) | ty::ty_str => {
cx.sess().bug(format!("fictitious type {:?} in sizing_type_of()", cx.sess().bug(format!("fictitious type {:?} in sizing_type_of()",
ty::get(t).sty).as_slice()) ty::get(t).sty).as_slice())
@ -205,7 +204,8 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
// avoids creating more than one copy of the enum when one // avoids creating more than one copy of the enum when one
// of the enum's variants refers to the enum itself. // of the enum's variants refers to the enum itself.
let repr = adt::represent_type(cx, t); let repr = adt::represent_type(cx, t);
let name = llvm_type_name(cx, an_enum, did, substs.tps.as_slice()); let tps = substs.types.get_vec(subst::TypeSpace);
let name = llvm_type_name(cx, an_enum, did, tps);
adt::incomplete_type_of(cx, &*repr, name.as_slice()) adt::incomplete_type_of(cx, &*repr, name.as_slice())
} }
ty::ty_box(typ) => { ty::ty_box(typ) => {
@ -260,17 +260,14 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
// in *after* placing it into the type cache. This prevents // in *after* placing it into the type cache. This prevents
// infinite recursion with recursive struct types. // infinite recursion with recursive struct types.
let repr = adt::represent_type(cx, t); let repr = adt::represent_type(cx, t);
let name = llvm_type_name(cx, let tps = substs.types.get_vec(subst::TypeSpace);
a_struct, let name = llvm_type_name(cx, a_struct, did, tps);
did,
substs.tps.as_slice());
adt::incomplete_type_of(cx, &*repr, name.as_slice()) adt::incomplete_type_of(cx, &*repr, name.as_slice())
} }
} }
ty::ty_vec(_, None) => cx.sess().bug("type_of with unsized ty_vec"), ty::ty_vec(_, None) => cx.sess().bug("type_of with unsized ty_vec"),
ty::ty_str => cx.sess().bug("type_of with unsized (bare) ty_str"), ty::ty_str => cx.sess().bug("type_of with unsized (bare) ty_str"),
ty::ty_self(..) => cx.sess().unimpl("type_of with ty_self"),
ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"), ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
ty::ty_param(..) => cx.sess().bug("type_of with ty_param"), ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
ty::ty_err(..) => cx.sess().bug("type_of with ty_err") ty::ty_err(..) => cx.sess().bug("type_of with ty_err")
@ -301,19 +298,17 @@ pub enum named_ty { a_struct, an_enum }
pub fn llvm_type_name(cx: &CrateContext, pub fn llvm_type_name(cx: &CrateContext,
what: named_ty, what: named_ty,
did: ast::DefId, did: ast::DefId,
tps: &[ty::t]) tps: &Vec<ty::t>)
-> String { -> String
{
let name = match what { let name = match what {
a_struct => { "struct" } a_struct => { "struct" }
an_enum => { "enum" } an_enum => { "enum" }
}; };
let tstr = ppaux::parameterized(cx.tcx(),
ty::item_path_str(cx.tcx(), let base = ty::item_path_str(cx.tcx(), did);
did).as_slice(), let strings: Vec<String> = tps.iter().map(|t| t.repr(cx.tcx())).collect();
&subst::ErasedRegions, let tstr = format!("{}<{}>", base, strings);
tps,
did,
false);
if did.krate == 0 { if did.krate == 0 {
format!("{}.{}", name, tstr) format!("{}.{}", name, tstr)
} else { } else {

View file

@ -24,7 +24,7 @@ use middle::freevars;
use middle::resolve; use middle::resolve;
use middle::resolve_lifetime; use middle::resolve_lifetime;
use middle::subst; use middle::subst;
use middle::subst::{Subst, Substs}; use middle::subst::{Subst, Substs, VecPerParamSpace};
use middle::ty; use middle::ty;
use middle::typeck; use middle::typeck;
use middle::typeck::MethodCall; use middle::typeck::MethodCall;
@ -58,7 +58,6 @@ use syntax::codemap::Span;
use syntax::parse::token; use syntax::parse::token;
use syntax::parse::token::InternedString; use syntax::parse::token::InternedString;
use syntax::{ast, ast_map}; use syntax::{ast, ast_map};
use syntax::owned_slice::OwnedSlice;
use syntax::util::small_vector::SmallVector; use syntax::util::small_vector::SmallVector;
use std::collections::enum_set::{EnumSet, CLike}; use std::collections::enum_set::{EnumSet, CLike};
@ -190,9 +189,8 @@ pub enum ast_ty_to_ty_cache_entry {
#[deriving(Clone, PartialEq, Decodable, Encodable)] #[deriving(Clone, PartialEq, Decodable, Encodable)]
pub struct ItemVariances { pub struct ItemVariances {
pub self_param: Option<Variance>, pub types: VecPerParamSpace<Variance>,
pub type_params: OwnedSlice<Variance>, pub regions: VecPerParamSpace<Variance>,
pub region_params: OwnedSlice<Variance>
} }
#[deriving(Clone, PartialEq, Decodable, Encodable, Show)] #[deriving(Clone, PartialEq, Decodable, Encodable, Show)]
@ -455,7 +453,8 @@ pub struct FnSig {
} }
#[deriving(Clone, PartialEq, Eq, Hash)] #[deriving(Clone, PartialEq, Eq, Hash)]
pub struct param_ty { pub struct ParamTy {
pub space: subst::ParamSpace,
pub idx: uint, pub idx: uint,
pub def_id: DefId pub def_id: DefId
} }
@ -466,7 +465,10 @@ pub enum Region {
// Region bound in a type or fn declaration which will be // Region bound in a type or fn declaration which will be
// substituted 'early' -- that is, at the same time when type // substituted 'early' -- that is, at the same time when type
// parameters are substituted. // parameters are substituted.
ReEarlyBound(/* param id */ ast::NodeId, /*index*/ uint, ast::Name), ReEarlyBound(/* param id */ ast::NodeId,
subst::ParamSpace,
/*index*/ uint,
ast::Name),
// Region bound in a function scope, which will be substituted when the // Region bound in a function scope, which will be substituted when the
// function is called. The first argument must be the `binder_id` of // function is called. The first argument must be the `binder_id` of
@ -713,10 +715,7 @@ pub enum sty {
ty_struct(DefId, Substs), ty_struct(DefId, Substs),
ty_tup(Vec<t>), ty_tup(Vec<t>),
ty_param(param_ty), // type parameter ty_param(ParamTy), // type parameter
ty_self(DefId), /* special, implicit `self` type parameter;
* def_id is the id of the trait */
ty_infer(InferTy), // something used only during inference/typeck ty_infer(InferTy), // something used only during inference/typeck
ty_err, // Also only used during inference/typeck, to represent ty_err, // Also only used during inference/typeck, to represent
// the type of an erroneous expression (helps cut down // the type of an erroneous expression (helps cut down
@ -734,7 +733,7 @@ pub struct TyTrait {
#[deriving(PartialEq, Eq, Hash)] #[deriving(PartialEq, Eq, Hash)]
pub struct TraitRef { pub struct TraitRef {
pub def_id: DefId, pub def_id: DefId,
pub substs: Substs pub substs: Substs,
} }
#[deriving(Clone, PartialEq)] #[deriving(Clone, PartialEq)]
@ -964,6 +963,8 @@ impl fmt::Show for IntVarValue {
pub struct TypeParameterDef { pub struct TypeParameterDef {
pub ident: ast::Ident, pub ident: ast::Ident,
pub def_id: ast::DefId, pub def_id: ast::DefId,
pub space: subst::ParamSpace,
pub index: uint,
pub bounds: Rc<ParamBounds>, pub bounds: Rc<ParamBounds>,
pub default: Option<ty::t> pub default: Option<ty::t>
} }
@ -972,29 +973,26 @@ pub struct TypeParameterDef {
pub struct RegionParameterDef { pub struct RegionParameterDef {
pub name: ast::Name, pub name: ast::Name,
pub def_id: ast::DefId, pub def_id: ast::DefId,
pub space: subst::ParamSpace,
pub index: uint,
} }
/// Information about the type/lifetime parameters associated with an item. /// Information about the type/lifetime parameters associated with an
/// Analogous to ast::Generics. /// item or method. Analogous to ast::Generics.
#[deriving(Clone)] #[deriving(Clone)]
pub struct Generics { pub struct Generics {
/// List of type parameters declared on the item. pub types: VecPerParamSpace<TypeParameterDef>,
pub type_param_defs: Rc<Vec<TypeParameterDef>>, pub regions: VecPerParamSpace<RegionParameterDef>,
/// List of region parameters declared on the item.
/// For a fn or method, only includes *early-bound* lifetimes.
pub region_param_defs: Rc<Vec<RegionParameterDef>>,
} }
impl Generics { impl Generics {
pub fn has_type_params(&self) -> bool { pub fn empty() -> Generics {
!self.type_param_defs.is_empty() Generics { types: VecPerParamSpace::empty(),
regions: VecPerParamSpace::empty() }
} }
pub fn type_param_defs<'a>(&'a self) -> &'a [TypeParameterDef] {
self.type_param_defs.as_slice() pub fn has_type_params(&self, space: subst::ParamSpace) -> bool {
} !self.types.get_vec(space).is_empty()
pub fn region_param_defs<'a>(&'a self) -> &'a [RegionParameterDef] {
self.region_param_defs.as_slice()
} }
} }
@ -1018,11 +1016,8 @@ pub struct ParameterEnvironment {
/// parameters in the same way, this only has an affect on regions. /// parameters in the same way, this only has an affect on regions.
pub free_substs: Substs, pub free_substs: Substs,
/// Bound on the Self parameter /// Bounds on the various type parameters
pub self_param_bound: Option<Rc<TraitRef>>, pub bounds: VecPerParamSpace<ParamBounds>,
/// Bounds on each numbered type parameter
pub type_param_bounds: Vec<ParamBounds>,
} }
/// A polytype. /// A polytype.
@ -1162,7 +1157,10 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
} }
fn sflags(substs: &Substs) -> uint { fn sflags(substs: &Substs) -> uint {
let mut f = 0u; let mut f = 0u;
for tt in substs.tps.iter() { f |= get(*tt).flags; } let mut i = substs.types.iter();
for tt in i {
f |= get(*tt).flags;
}
match substs.regions { match substs.regions {
subst::ErasedRegions => {} subst::ErasedRegions => {}
subst::NonerasedRegions(ref regions) => { subst::NonerasedRegions(ref regions) => {
@ -1185,9 +1183,14 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
// so we're doing it this way. // so we're doing it this way.
&ty_bot => flags |= has_ty_bot as uint, &ty_bot => flags |= has_ty_bot as uint,
&ty_err => flags |= has_ty_err as uint, &ty_err => flags |= has_ty_err as uint,
&ty_param(_) => flags |= has_params as uint, &ty_param(ref p) => {
if p.space == subst::SelfSpace {
flags |= has_self as uint;
} else {
flags |= has_params as uint;
}
}
&ty_infer(_) => flags |= needs_infer as uint, &ty_infer(_) => flags |= needs_infer as uint,
&ty_self(_) => flags |= has_self as uint,
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) => { &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
flags |= sflags(substs); flags |= sflags(substs);
} }
@ -1455,10 +1458,16 @@ pub fn mk_float_var(cx: &ctxt, v: FloatVid) -> t { mk_infer(cx, FloatVar(v)) }
pub fn mk_infer(cx: &ctxt, it: InferTy) -> t { mk_t(cx, ty_infer(it)) } pub fn mk_infer(cx: &ctxt, it: InferTy) -> t { mk_t(cx, ty_infer(it)) }
pub fn mk_self(cx: &ctxt, did: ast::DefId) -> t { mk_t(cx, ty_self(did)) } pub fn mk_param(cx: &ctxt, space: subst::ParamSpace, n: uint, k: DefId) -> t {
mk_t(cx, ty_param(ParamTy { space: space, idx: n, def_id: k }))
}
pub fn mk_param(cx: &ctxt, n: uint, k: DefId) -> t { pub fn mk_self_type(cx: &ctxt, did: ast::DefId) -> t {
mk_t(cx, ty_param(param_ty { idx: n, def_id: k })) mk_param(cx, subst::SelfSpace, 0, did)
}
pub fn mk_param_from_def(cx: &ctxt, def: &TypeParameterDef) -> t {
mk_param(cx, def.space, def.index, def.def_id)
} }
pub fn walk_ty(ty: t, f: |t|) { pub fn walk_ty(ty: t, f: |t|) {
@ -1471,15 +1480,17 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) {
} }
match get(ty).sty { match get(ty).sty {
ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_str | ty_self(_) | ty_str | ty_infer(_) | ty_param(_) | ty_err => {
ty_infer(_) | ty_param(_) | ty_err => {} }
ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f), ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f),
ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => { ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => {
maybe_walk_ty(tm.ty, f); maybe_walk_ty(tm.ty, f);
} }
ty_enum(_, ref substs) | ty_struct(_, ref substs) | ty_enum(_, ref substs) | ty_struct(_, ref substs) |
ty_trait(box TyTrait { ref substs, .. }) => { ty_trait(box TyTrait { ref substs, .. }) => {
for subty in (*substs).tps.iter() { maybe_walk_ty(*subty, |x| f(x)); } for subty in (*substs).types.iter() {
maybe_walk_ty(*subty, |x| f(x));
}
} }
ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } } ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } }
ty_bare_fn(ref ft) => { ty_bare_fn(ref ft) => {
@ -1533,8 +1544,7 @@ pub fn type_needs_subst(ty: t) -> bool {
} }
pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool { pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool {
tref.substs.self_ty.iter().any(|&t| type_is_error(t)) || tref.substs.types.any(|&t| type_is_error(t))
tref.substs.tps.iter().any(|&t| type_is_error(t))
} }
pub fn type_is_ty_var(ty: t) -> bool { pub fn type_is_ty_var(ty: t) -> bool {
@ -1548,7 +1558,7 @@ pub fn type_is_bool(ty: t) -> bool { get(ty).sty == ty_bool }
pub fn type_is_self(ty: t) -> bool { pub fn type_is_self(ty: t) -> bool {
match get(ty).sty { match get(ty).sty {
ty_self(..) => true, ty_param(ref p) => p.space == subst::SelfSpace,
_ => false _ => false
} }
} }
@ -2103,16 +2113,6 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
tp_def.bounds.trait_bounds.as_slice()) tp_def.bounds.trait_bounds.as_slice())
} }
ty_self(def_id) => {
// FIXME(#4678)---self should just be a ty param
// Self may be bounded if the associated trait has builtin kinds
// for supertraits. If so we can use those bounds.
let trait_def = lookup_trait_def(cx, def_id);
let traits = [trait_def.trait_ref.clone()];
kind_bounds_to_contents(cx, trait_def.bounds, traits)
}
ty_infer(_) => { ty_infer(_) => {
// This occurs during coherence, but shouldn't occur at other // This occurs during coherence, but shouldn't occur at other
// times. // times.
@ -2292,7 +2292,6 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
ty_infer(_) | ty_infer(_) |
ty_err | ty_err |
ty_param(_) | ty_param(_) |
ty_self(_) |
ty_vec(_, None) => { ty_vec(_, None) => {
false false
} }
@ -2688,6 +2687,14 @@ pub fn ty_region(tcx: &ctxt,
} }
} }
pub fn free_region_from_def(free_id: ast::NodeId, def: &RegionParameterDef)
-> ty::Region
{
ty::ReFree(ty::FreeRegion { scope_id: free_id,
bound_region: ty::BrNamed(def.def_id,
def.name) })
}
// Returns the type of a pattern as a monotype. Like @expr_ty, this function // Returns the type of a pattern as a monotype. Like @expr_ty, this function
// doesn't provide type parameter substitutions. // doesn't provide type parameter substitutions.
pub fn pat_ty(cx: &ctxt, pat: &ast::Pat) -> t { pub fn pat_ty(cx: &ctxt, pat: &ast::Pat) -> t {
@ -2937,27 +2944,16 @@ impl AutoRef {
} }
pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin) pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin)
-> Rc<Vec<TypeParameterDef>> { -> VecPerParamSpace<TypeParameterDef> {
match origin { match origin {
typeck::MethodStatic(did) => { typeck::MethodStatic(did) => {
// n.b.: When we encode impl methods, the bounds ty::lookup_item_type(tcx, did).generics.types.clone()
// that we encode include both the impl bounds
// and then the method bounds themselves...
ty::lookup_item_type(tcx, did).generics.type_param_defs
} }
typeck::MethodParam(typeck::MethodParam { typeck::MethodParam(typeck::MethodParam{trait_id: trt_id,
trait_id: trt_id,
method_num: n_mth, ..}) | method_num: n_mth, ..}) |
typeck::MethodObject(typeck::MethodObject { typeck::MethodObject(typeck::MethodObject{trait_id: trt_id,
trait_id: trt_id,
method_num: n_mth, ..}) => { method_num: n_mth, ..}) => {
// ...trait methods bounds, in contrast, include only the ty::trait_method(tcx, trt_id, n_mth).generics.types.clone()
// method bounds, so we must preprend the tps from the
// trait itself. This ought to be harmonized.
let trait_type_param_defs =
Vec::from_slice(lookup_trait_def(tcx, trt_id).generics.type_param_defs());
Rc::new(trait_type_param_defs.append(
ty::trait_method(tcx, trt_id, n_mth).generics.type_param_defs()))
} }
} }
} }
@ -3176,7 +3172,7 @@ pub fn method_idx(id: ast::Ident, meths: &[Rc<Method>]) -> Option<uint> {
/// Returns a vector containing the indices of all type parameters that appear /// Returns a vector containing the indices of all type parameters that appear
/// in `ty`. The vector may contain duplicates. Probably should be converted /// in `ty`. The vector may contain duplicates. Probably should be converted
/// to a bitset or some other representation. /// to a bitset or some other representation.
pub fn param_tys_in_type(ty: t) -> Vec<param_ty> { pub fn param_tys_in_type(ty: t) -> Vec<ParamTy> {
let mut rslt = Vec::new(); let mut rslt = Vec::new();
walk_ty(ty, |ty| { walk_ty(ty, |ty| {
match get(ty).sty { match get(ty).sty {
@ -3214,8 +3210,13 @@ pub fn ty_sort_str(cx: &ctxt, t: t) -> String {
ty_infer(TyVar(_)) => "inferred type".to_string(), ty_infer(TyVar(_)) => "inferred type".to_string(),
ty_infer(IntVar(_)) => "integral variable".to_string(), ty_infer(IntVar(_)) => "integral variable".to_string(),
ty_infer(FloatVar(_)) => "floating-point variable".to_string(), ty_infer(FloatVar(_)) => "floating-point variable".to_string(),
ty_param(_) => "type parameter".to_string(), ty_param(ref p) => {
ty_self(_) => "self".to_string(), if p.space == subst::SelfSpace {
"Self".to_string()
} else {
"type parameter".to_string()
}
}
ty_err => "type error".to_string(), ty_err => "type error".to_string(),
} }
} }
@ -3821,7 +3822,7 @@ pub fn lookup_item_type(cx: &ctxt,
pub fn lookup_impl_vtables(cx: &ctxt, pub fn lookup_impl_vtables(cx: &ctxt,
did: ast::DefId) did: ast::DefId)
-> typeck::impl_res { -> typeck::vtable_res {
lookup_locally_or_in_crate_store( lookup_locally_or_in_crate_store(
"impl_vtables", did, &mut *cx.impl_vtables.borrow_mut(), "impl_vtables", did, &mut *cx.impl_vtables.borrow_mut(),
|| csearch::get_impl_vtables(cx, did) ) || csearch::get_impl_vtables(cx, did) )
@ -4103,8 +4104,7 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t {
substs: &subst::Substs) substs: &subst::Substs)
-> subst::Substs { -> subst::Substs {
subst::Substs { regions: subst::ErasedRegions, subst::Substs { regions: subst::ErasedRegions,
self_ty: substs.self_ty.fold_with(self), types: substs.types.fold_with(self) }
tps: substs.tps.fold_with(self) }
} }
fn fold_sig(&mut self, fn fold_sig(&mut self,
@ -4252,11 +4252,7 @@ pub fn visitor_object_ty(tcx: &ctxt,
Ok(id) => id, Ok(id) => id,
Err(s) => { return Err(s); } Err(s) => { return Err(s); }
}; };
let substs = Substs { let substs = Substs::empty();
regions: subst::NonerasedRegions(Vec::new()),
self_ty: None,
tps: Vec::new()
};
let trait_ref = Rc::new(TraitRef { def_id: trait_lang_item, substs: substs }); let trait_ref = Rc::new(TraitRef { def_id: trait_lang_item, substs: substs });
Ok((trait_ref.clone(), Ok((trait_ref.clone(),
mk_trait(tcx, mk_trait(tcx,
@ -4582,10 +4578,6 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
hash!(p.idx); hash!(p.idx);
did(&mut state, p.def_id); did(&mut state, p.def_id);
} }
ty_self(d) => {
byte!(21);
did(&mut state, d);
}
ty_infer(_) => unreachable!(), ty_infer(_) => unreachable!(),
ty_err => byte!(23), ty_err => byte!(23),
} }
@ -4607,11 +4599,7 @@ impl Variance {
pub fn construct_parameter_environment( pub fn construct_parameter_environment(
tcx: &ctxt, tcx: &ctxt,
self_bound: Option<Rc<TraitRef>>, generics: &ty::Generics,
item_type_params: &[TypeParameterDef],
method_type_params: &[TypeParameterDef],
item_region_params: &[RegionParameterDef],
method_region_params: &[RegionParameterDef],
free_id: ast::NodeId) free_id: ast::NodeId)
-> ParameterEnvironment -> ParameterEnvironment
{ {
@ -4621,75 +4609,76 @@ pub fn construct_parameter_environment(
// Construct the free substs. // Construct the free substs.
// //
// map Self => Self // map T => T
let self_ty = self_bound.as_ref().map(|t| ty::mk_self(tcx, t.def_id)); let mut types = VecPerParamSpace::empty();
for &space in subst::ParamSpace::all().iter() {
// map A => A push_types_from_defs(tcx, &mut types, space,
let num_item_type_params = item_type_params.len(); generics.types.get_vec(space));
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 // map bound 'a => free 'a
let region_params = { let mut regions = VecPerParamSpace::empty();
fn push_region_params(mut accum: Vec<ty::Region>, for &space in subst::ParamSpace::all().iter() {
free_id: ast::NodeId, push_region_params(&mut regions, space, free_id,
region_params: &[RegionParameterDef]) generics.regions.get_vec(space));
-> Vec<ty::Region> {
for r in region_params.iter() {
accum.push(
ty::ReFree(ty::FreeRegion {
scope_id: free_id,
bound_region: ty::BrNamed(r.def_id, r.name)}));
} }
accum
}
let t = push_region_params(vec!(), free_id, item_region_params);
push_region_params(t, free_id, method_region_params)
};
let free_substs = Substs { let free_substs = Substs {
self_ty: self_ty, types: types,
tps: type_params, regions: subst::NonerasedRegions(regions)
regions: subst::NonerasedRegions(region_params)
}; };
// //
// Compute the bounds on Self and the type parameters. // Compute the bounds on Self and the type parameters.
// //
let self_bound_substd = self_bound.map(|b| b.subst(tcx, &free_substs)); let mut bounds = VecPerParamSpace::empty();
let type_param_bounds_substd = Vec::from_fn(num_type_params, |i| { for &space in subst::ParamSpace::all().iter() {
if i < num_item_type_params { push_bounds_from_defs(tcx, &mut bounds, space, &free_substs,
(*item_type_params[i].bounds).subst(tcx, &free_substs) generics.types.get_vec(space));
} else {
let j = i - num_item_type_params;
(*method_type_params[j].bounds).subst(tcx, &free_substs)
} }
});
debug!("construct_parameter_environment: free_id={} \ debug!("construct_parameter_environment: free_id={} \
free_subst={} \ free_subst={} \
self_param_bound={} \ bounds={}",
type_param_bound={}",
free_id, free_id,
free_substs.repr(tcx), free_substs.repr(tcx),
self_bound_substd.repr(tcx), bounds.repr(tcx));
type_param_bounds_substd.repr(tcx));
ty::ParameterEnvironment { return ty::ParameterEnvironment {
free_substs: free_substs, free_substs: free_substs,
self_param_bound: self_bound_substd, bounds: bounds
type_param_bounds: type_param_bounds_substd, };
fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
space: subst::ParamSpace,
free_id: ast::NodeId,
region_params: &Vec<RegionParameterDef>)
{
for r in region_params.iter() {
regions.push(space, ty::free_region_from_def(free_id, r));
}
}
fn push_types_from_defs(tcx: &ty::ctxt,
types: &mut subst::VecPerParamSpace<ty::t>,
space: subst::ParamSpace,
defs: &Vec<TypeParameterDef>) {
for (i, def) in defs.iter().enumerate() {
let ty = ty::mk_param(tcx, space, i, def.def_id);
types.push(space, ty);
}
}
fn push_bounds_from_defs(tcx: &ty::ctxt,
bounds: &mut subst::VecPerParamSpace<ParamBounds>,
space: subst::ParamSpace,
free_substs: &subst::Substs,
defs: &Vec<TypeParameterDef>) {
for def in defs.iter() {
let b = (*def.bounds).subst(tcx, free_substs);
bounds.push(space, b);
}
} }
} }

View file

@ -11,6 +11,7 @@
// Generalized type folding mechanism. // Generalized type folding mechanism.
use middle::subst; use middle::subst;
use middle::subst::VecPerParamSpace;
use middle::ty; use middle::ty;
use middle::typeck; use middle::typeck;
use std::rc::Rc; use std::rc::Rc;
@ -127,6 +128,12 @@ impl<T:TypeFoldable> TypeFoldable for OwnedSlice<T> {
} }
} }
impl<T:TypeFoldable> TypeFoldable for VecPerParamSpace<T> {
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> VecPerParamSpace<T> {
self.map(|t| t.fold_with(folder))
}
}
impl TypeFoldable for ty::TraitStore { impl TypeFoldable for ty::TraitStore {
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::TraitStore { fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::TraitStore {
folder.fold_trait_store(*self) folder.fold_trait_store(*self)
@ -212,16 +219,10 @@ impl TypeFoldable for typeck::vtable_origin {
typeck::vtable_param(n, b) => { typeck::vtable_param(n, b) => {
typeck::vtable_param(n, b) typeck::vtable_param(n, b)
} }
typeck::vtable_error => {
typeck::vtable_error
} }
} }
}
impl TypeFoldable for typeck::impl_res {
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> typeck::impl_res {
typeck::impl_res {
trait_vtables: self.trait_vtables.fold_with(folder),
self_vtables: self.self_vtables.fold_with(folder),
}
} }
} }
@ -245,6 +246,8 @@ impl TypeFoldable for ty::TypeParameterDef {
ty::TypeParameterDef { ty::TypeParameterDef {
ident: self.ident, ident: self.ident,
def_id: self.def_id, def_id: self.def_id,
space: self.space,
index: self.index,
bounds: self.bounds.fold_with(folder), bounds: self.bounds.fold_with(folder),
default: self.default.fold_with(folder), default: self.default.fold_with(folder),
} }
@ -260,8 +263,8 @@ impl TypeFoldable for ty::RegionParameterDef {
impl TypeFoldable for ty::Generics { impl TypeFoldable for ty::Generics {
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::Generics { fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::Generics {
ty::Generics { ty::Generics {
type_param_defs: self.type_param_defs.fold_with(folder), types: self.types.fold_with(folder),
region_param_defs: self.region_param_defs.fold_with(folder) regions: self.regions.fold_with(folder),
} }
} }
} }
@ -291,8 +294,7 @@ pub fn super_fold_substs<T:TypeFolder>(this: &mut T,
}; };
subst::Substs { regions: regions, subst::Substs { regions: regions,
self_ty: substs.self_ty.fold_with(this), types: substs.types.fold_with(this) }
tps: substs.tps.fold_with(this) }
} }
pub fn super_fold_sig<T:TypeFolder>(this: &mut T, pub fn super_fold_sig<T:TypeFolder>(this: &mut T,
@ -390,7 +392,7 @@ pub fn super_fold_sty<T:TypeFolder>(this: &mut T,
ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_str | ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_str |
ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
ty::ty_err | ty::ty_infer(_) | ty::ty_err | ty::ty_infer(_) |
ty::ty_param(..) | ty::ty_self(_) => { ty::ty_param(..) => {
(*sty).clone() (*sty).clone()
} }
} }

View file

@ -52,6 +52,7 @@
use middle::const_eval; use middle::const_eval;
use middle::def; use middle::def;
use middle::lang_items::FnMutTraitLangItem; use middle::lang_items::FnMutTraitLangItem;
use rl = middle::resolve_lifetime;
use middle::subst::{Subst, Substs}; use middle::subst::{Subst, Substs};
use middle::subst; use middle::subst;
use middle::ty::ty_param_substs_and_ty; use middle::ty::ty_param_substs_and_ty;
@ -85,20 +86,20 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
tcx.sess.span_bug(lifetime.span, "unresolved lifetime"); tcx.sess.span_bug(lifetime.span, "unresolved lifetime");
} }
Some(&ast::DefStaticRegion) => { Some(&rl::DefStaticRegion) => {
ty::ReStatic ty::ReStatic
} }
Some(&ast::DefLateBoundRegion(binder_id, _, id)) => { Some(&rl::DefLateBoundRegion(binder_id, _, id)) => {
ty::ReLateBound(binder_id, ty::BrNamed(ast_util::local_def(id), ty::ReLateBound(binder_id, ty::BrNamed(ast_util::local_def(id),
lifetime.name)) lifetime.name))
} }
Some(&ast::DefEarlyBoundRegion(index, id)) => { Some(&rl::DefEarlyBoundRegion(space, index, id)) => {
ty::ReEarlyBound(id, index, lifetime.name) ty::ReEarlyBound(id, space, index, lifetime.name)
} }
Some(&ast::DefFreeRegion(scope_id, id)) => { Some(&rl::DefFreeRegion(scope_id, id)) => {
ty::ReFree(ty::FreeRegion { ty::ReFree(ty::FreeRegion {
scope_id: scope_id, scope_id: scope_id,
bound_region: ty::BrNamed(ast_util::local_def(id), bound_region: ty::BrNamed(ast_util::local_def(id),
@ -163,10 +164,21 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope>(
let tcx = this.tcx(); let tcx = this.tcx();
// ast_path_substs() is only called to convert paths that are
// known to refer to traits, types, or structs. In these cases,
// all type parameters defined for the item being referenced will
// be in the TypeSpace or SelfSpace.
//
// Note: in the case of traits, the self parameter is also
// defined, but we don't currently create a `type_param_def` for
// `Self` because it is implicit.
assert!(decl_generics.regions.all(|d| d.space == subst::TypeSpace));
assert!(decl_generics.types.all(|d| d.space != subst::FnSpace));
// If the type is parameterized by the this region, then replace this // If the type is parameterized by the this region, then replace this
// region with the current anon region binding (in other words, // region with the current anon region binding (in other words,
// whatever & would get replaced with). // whatever & would get replaced with).
let expected_num_region_params = decl_generics.region_param_defs().len(); let expected_num_region_params = decl_generics.regions.len(subst::TypeSpace);
let supplied_num_region_params = path.segments.last().unwrap().lifetimes.len(); let supplied_num_region_params = path.segments.last().unwrap().lifetimes.len();
let regions = if expected_num_region_params == supplied_num_region_params { let regions = if expected_num_region_params == supplied_num_region_params {
path.segments.last().unwrap().lifetimes.iter().map( path.segments.last().unwrap().lifetimes.iter().map(
@ -192,9 +204,10 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope>(
}; };
// Convert the type parameters supplied by the user. // Convert the type parameters supplied by the user.
let ty_param_defs = decl_generics.types.get_vec(subst::TypeSpace);
let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).count(); let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).count();
let formal_ty_param_count = decl_generics.type_param_defs().len(); let formal_ty_param_count = ty_param_defs.len();
let required_ty_param_count = decl_generics.type_param_defs().iter() let required_ty_param_count = ty_param_defs.iter()
.take_while(|x| x.default.is_none()) .take_while(|x| x.default.is_none())
.count(); .count();
if supplied_ty_param_count < required_ty_param_count { if supplied_ty_param_count < required_ty_param_count {
@ -233,39 +246,31 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope>(
.map(|a_t| ast_ty_to_ty(this, rscope, &**a_t)) .map(|a_t| ast_ty_to_ty(this, rscope, &**a_t))
.collect(); .collect();
let mut substs = subst::Substs { let mut substs = subst::Substs::new_type(tps, regions);
regions: subst::NonerasedRegions(regions),
self_ty: self_ty,
tps: tps
};
for param in decl_generics.type_param_defs() match self_ty {
.slice_from(supplied_ty_param_count).iter() { None => {
let ty = param.default.unwrap().subst_spanned(tcx, &substs, Some(path.span)); // If no self-type is provided, it's still possible that
substs.tps.push(ty); // one was declared, because this could be an object type.
}
Some(ty) => {
// If a self-type is provided, one should have been
// "declared" (in other words, this should be a
// trait-ref).
assert!(decl_generics.types.get_self().is_some());
substs.types.push(subst::SelfSpace, ty);
}
}
for param in ty_param_defs.slice_from(supplied_ty_param_count).iter() {
let default = param.default.unwrap();
let default = default.subst_spanned(tcx, &substs, Some(path.span));
substs.types.push(subst::TypeSpace, default);
} }
substs substs
} }
pub fn ast_path_to_substs_and_ty<AC:AstConv,
RS:RegionScope>(
this: &AC,
rscope: &RS,
did: ast::DefId,
path: &ast::Path)
-> ty_param_substs_and_ty {
let tcx = this.tcx();
let ty::ty_param_bounds_and_ty {
generics: generics,
ty: decl_ty
} = this.get_item_ty(did);
let substs = ast_path_substs(this, rscope, &generics, None, path);
let ty = decl_ty.subst(tcx, &substs);
ty_param_substs_and_ty { substs: substs, ty: ty }
}
pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope>( pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
@ -286,12 +291,14 @@ pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope>(
path: &ast::Path) path: &ast::Path)
-> ty_param_substs_and_ty -> ty_param_substs_and_ty
{ {
// Look up the polytype of the item and then substitute the provided types let tcx = this.tcx();
// for any type/region parameters. let ty::ty_param_bounds_and_ty {
let ty::ty_param_substs_and_ty { generics: generics,
substs: substs, ty: decl_ty
ty: ty } = this.get_item_ty(did);
} = ast_path_to_substs_and_ty(this, rscope, did, path);
let substs = ast_path_substs(this, rscope, &generics, None, path);
let ty = decl_ty.subst(tcx, &substs);
ty_param_substs_and_ty { substs: substs, ty: ty } ty_param_substs_and_ty { substs: substs, ty: ty }
} }
@ -521,8 +528,10 @@ pub fn trait_ref_for_unboxed_function<AC:AstConv,
RS:RegionScope>( RS:RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
unboxed_function: &ast::UnboxedFnTy) unboxed_function: &ast::UnboxedFnTy,
-> ty::TraitRef { self_ty: Option<ty::t>)
-> ty::TraitRef
{
let fn_mut_trait_did = this.tcx() let fn_mut_trait_did = this.tcx()
.lang_items .lang_items
.require(FnMutTraitLangItem) .require(FnMutTraitLangItem)
@ -538,11 +547,14 @@ pub fn trait_ref_for_unboxed_function<AC:AstConv,
let output_type = ast_ty_to_ty(this, let output_type = ast_ty_to_ty(this,
rscope, rscope,
&*unboxed_function.decl.output); &*unboxed_function.decl.output);
let substs = subst::Substs { let mut substs = subst::Substs::new_type(vec!(input_tuple, output_type),
self_ty: None, Vec::new());
tps: vec!(input_tuple, output_type),
regions: subst::NonerasedRegions(Vec::new()), match self_ty {
}; Some(s) => substs.types.push(subst::SelfSpace, s),
None => ()
}
ty::TraitRef { ty::TraitRef {
def_id: fn_mut_trait_did, def_id: fn_mut_trait_did,
substs: substs, substs: substs,
@ -590,7 +602,8 @@ fn mk_pointer<AC:AstConv,
substs substs
} = trait_ref_for_unboxed_function(this, } = trait_ref_for_unboxed_function(this,
rscope, rscope,
&**unboxed_function); &**unboxed_function,
None);
return ty::mk_trait(this.tcx(), return ty::mk_trait(this.tcx(),
def_id, def_id,
substs, substs,
@ -801,9 +814,9 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
def::DefTy(did) | def::DefStruct(did) => { def::DefTy(did) | def::DefStruct(did) => {
ast_path_to_ty(this, rscope, did, path).ty ast_path_to_ty(this, rscope, did, path).ty
} }
def::DefTyParam(id, n) => { def::DefTyParam(space, id, n) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS); check_path_args(tcx, path, NO_TPS | NO_REGIONS);
ty::mk_param(tcx, n, id) ty::mk_param(tcx, space, n, id)
} }
def::DefSelfTy(id) => { def::DefSelfTy(id) => {
// n.b.: resolve guarantees that the this type only appears in a // n.b.: resolve guarantees that the this type only appears in a
@ -811,7 +824,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
// substs // substs
check_path_args(tcx, path, NO_TPS | NO_REGIONS); check_path_args(tcx, path, NO_TPS | NO_REGIONS);
let did = ast_util::local_def(id); let did = ast_util::local_def(id);
ty::mk_self(tcx, did) ty::mk_self_type(tcx, did)
} }
def::DefMod(id) => { def::DefMod(id) => {
tcx.sess.span_fatal(ast_ty.span, tcx.sess.span_fatal(ast_ty.span,
@ -891,7 +904,9 @@ pub fn ty_of_method<AC:AstConv>(
fn_style: ast::FnStyle, fn_style: ast::FnStyle,
untransformed_self_ty: ty::t, untransformed_self_ty: ty::t,
explicit_self: ast::ExplicitSelf, explicit_self: ast::ExplicitSelf,
decl: &ast::FnDecl) -> ty::BareFnTy { decl: &ast::FnDecl)
-> ty::BareFnTy
{
ty_of_method_or_bare_fn(this, id, fn_style, abi::Rust, Some(SelfInfo { ty_of_method_or_bare_fn(this, id, fn_style, abi::Rust, Some(SelfInfo {
untransformed_self_ty: untransformed_self_ty, untransformed_self_ty: untransformed_self_ty,
explicit_self: explicit_self explicit_self: explicit_self

View file

@ -127,7 +127,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: &ast::Pat, path: &ast::Path,
// Check to see whether this is an enum or a struct. // Check to see whether this is an enum or a struct.
match *structure_of(pcx.fcx, pat.span, expected) { match *structure_of(pcx.fcx, pat.span, expected) {
ty::ty_enum(_, ref expected_substs) => { ty::ty_enum(expected_def_id, ref expected_substs) => {
// Lookup the enum and variant def ids: // Lookup the enum and variant def ids:
let v_def = lookup_def(pcx.fcx, pat.span, pat.id); let v_def = lookup_def(pcx.fcx, pat.span, pat.id);
match v_def.variant_def_ids() { match v_def.variant_def_ids() {
@ -150,18 +150,15 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: &ast::Pat, path: &ast::Path,
arg_types = { arg_types = {
let vinfo = let vinfo =
ty::enum_variant_with_id(tcx, enm, var); ty::enum_variant_with_id(tcx, enm, var);
let var_tpt = ty::lookup_item_type(tcx, var); if enm == expected_def_id {
vinfo.args.iter().map(|t| { vinfo.args.iter()
if var_tpt.generics.type_param_defs().len() == .map(|t| t.subst(tcx, expected_substs))
expected_substs.tps.len() .collect()
{ } else {
t.subst(tcx, expected_substs) vinfo.args.iter()
.map(|_| ty::mk_err())
.collect()
} }
else {
*t // In this case, an error was already signaled
// anyway
}
}).collect()
}; };
kind_name = "variant"; kind_name = "variant";
@ -569,11 +566,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
fields.as_slice(), fields.as_slice(),
etc, etc,
supplied_def_id, supplied_def_id,
&subst::Substs { &subst::Substs::empty());
self_ty: None,
tps: Vec::new(),
regions: subst::ErasedRegions,
});
} }
_ => () // Error, but we're already in an error case _ => () // Error, but we're already in an error case
} }

View file

@ -91,7 +91,7 @@ use middle::typeck::infer;
use middle::typeck::MethodCallee; use middle::typeck::MethodCallee;
use middle::typeck::{MethodOrigin, MethodParam}; use middle::typeck::{MethodOrigin, MethodParam};
use middle::typeck::{MethodStatic, MethodObject}; use middle::typeck::{MethodStatic, MethodObject};
use middle::typeck::{param_numbered, param_self, param_index}; use middle::typeck::{param_index};
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use util::common::indenter; use util::common::indenter;
use util::ppaux; use util::ppaux;
@ -235,7 +235,8 @@ fn construct_transformed_self_ty_for_object(
trait_def_id: ast::DefId, trait_def_id: ast::DefId,
rcvr_substs: &subst::Substs, rcvr_substs: &subst::Substs,
method_ty: &ty::Method) method_ty: &ty::Method)
-> ty::t { -> ty::t
{
/*! /*!
* This is a bit tricky. We have a match against a trait method * This is a bit tricky. We have a match against a trait method
* being invoked on an object, and we want to generate the * being invoked on an object, and we want to generate the
@ -257,9 +258,13 @@ fn construct_transformed_self_ty_for_object(
* match below. * match below.
*/ */
let substs = subst::Substs {regions: rcvr_substs.regions.clone(), let mut obj_substs = rcvr_substs.clone();
self_ty: None,
tps: rcvr_substs.tps.clone()}; // The subst we get in has Err as the "Self" type. For an object
// type, we don't put any type into the Self paramspace, so let's
// make a copy of rcvr_substs that has the Self paramspace empty.
obj_substs.types.get_mut_vec(subst::SelfSpace).pop().unwrap();
match method_ty.explicit_self { match method_ty.explicit_self {
ast::SelfStatic => { ast::SelfStatic => {
tcx.sess.span_bug(span, "static method for object type receiver"); tcx.sess.span_bug(span, "static method for object type receiver");
@ -271,13 +276,13 @@ fn construct_transformed_self_ty_for_object(
let transformed_self_ty = *method_ty.fty.sig.inputs.get(0); let transformed_self_ty = *method_ty.fty.sig.inputs.get(0);
match ty::get(transformed_self_ty).sty { match ty::get(transformed_self_ty).sty {
ty::ty_rptr(r, mt) => { // must be SelfRegion ty::ty_rptr(r, mt) => { // must be SelfRegion
let r = r.subst(tcx, &substs); // handle Early-Bound lifetime let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime
ty::mk_trait(tcx, trait_def_id, substs, ty::mk_trait(tcx, trait_def_id, obj_substs,
RegionTraitStore(r, mt.mutbl), RegionTraitStore(r, mt.mutbl),
ty::empty_builtin_bounds()) ty::empty_builtin_bounds())
} }
ty::ty_uniq(_) => { // must be SelfUniq ty::ty_uniq(_) => { // must be SelfUniq
ty::mk_trait(tcx, trait_def_id, substs, ty::mk_trait(tcx, trait_def_id, obj_substs,
UniqTraitStore, UniqTraitStore,
ty::empty_builtin_bounds()) ty::empty_builtin_bounds())
} }
@ -456,11 +461,6 @@ impl<'a> LookupContext<'a> {
ty_param(p) => { ty_param(p) => {
self.push_inherent_candidates_from_param(self_ty, restrict_to, p); self.push_inherent_candidates_from_param(self_ty, restrict_to, p);
} }
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, restrict_to);
}
_ => { /* No bound methods in these types */ } _ => { /* No bound methods in these types */ }
} }
@ -516,10 +516,7 @@ impl<'a> LookupContext<'a> {
// //
// `confirm_candidate()` also relies upon this substitution // `confirm_candidate()` also relies upon this substitution
// for Self. (fix) // for Self. (fix)
let rcvr_substs = subst::Substs { let rcvr_substs = substs.with_self_ty(ty::mk_err());
self_ty: Some(ty::mk_err()),
..(*substs).clone()
};
let trait_ref = Rc::new(TraitRef { let trait_ref = Rc::new(TraitRef {
def_id: did, def_id: did,
substs: rcvr_substs.clone() substs: rcvr_substs.clone()
@ -552,35 +549,27 @@ impl<'a> LookupContext<'a> {
fn push_inherent_candidates_from_param(&mut self, fn push_inherent_candidates_from_param(&mut self,
rcvr_ty: ty::t, rcvr_ty: ty::t,
restrict_to: Option<DefId>, restrict_to: Option<DefId>,
param_ty: param_ty) { param_ty: ParamTy) {
debug!("push_inherent_candidates_from_param(param_ty={:?})", debug!("push_inherent_candidates_from_param(param_ty={:?})",
param_ty); param_ty);
let i = param_ty.idx;
match self.fcx.inh.param_env.type_param_bounds.as_slice().get(i) {
Some(b) => self.push_inherent_candidates_from_bounds(
rcvr_ty, b.trait_bounds.as_slice(), restrict_to,
param_numbered(param_ty.idx)),
None => {}
}
}
fn push_inherent_candidates_from_self(&mut self,
rcvr_ty: ty::t,
restrict_to: Option<DefId>) {
debug!("push_inherent_candidates_from_self()");
self.push_inherent_candidates_from_bounds( self.push_inherent_candidates_from_bounds(
rcvr_ty, rcvr_ty,
[self.fcx.inh.param_env.self_param_bound.clone().unwrap()], param_ty.space,
param_ty.idx,
restrict_to, restrict_to,
param_self) param_index { space: param_ty.space, index: param_ty.idx });
} }
fn push_inherent_candidates_from_bounds(&mut self, fn push_inherent_candidates_from_bounds(&mut self,
self_ty: ty::t, self_ty: ty::t,
bounds: &[Rc<TraitRef>], space: subst::ParamSpace,
index: uint,
restrict_to: Option<DefId>, restrict_to: Option<DefId>,
param: param_index) { param: param_index) {
let bounds =
self.fcx.inh.param_env.bounds.get(space, index).trait_bounds
.as_slice();
self.push_inherent_candidates_from_bounds_inner(bounds, self.push_inherent_candidates_from_bounds_inner(bounds,
|trait_ref, m, method_num, bound_num| { |trait_ref, m, method_num, bound_num| {
match restrict_to { match restrict_to {
@ -937,7 +926,7 @@ impl<'a> LookupContext<'a> {
ty_bare_fn(..) | ty_box(..) | ty_uniq(..) | ty_rptr(..) | ty_bare_fn(..) | ty_box(..) | ty_uniq(..) | ty_rptr(..) |
ty_infer(IntVar(_)) | ty_infer(IntVar(_)) |
ty_infer(FloatVar(_)) | ty_infer(FloatVar(_)) |
ty_self(_) | ty_param(..) | ty_nil | ty_bot | ty_bool | ty_param(..) | ty_nil | ty_bot | ty_bool |
ty_char | ty_int(..) | ty_uint(..) | ty_char | ty_int(..) | ty_uint(..) |
ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) | ty_tup(..) | ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) | ty_tup(..) |
ty_str | ty_vec(..) | ty_trait(..) | ty_closure(..) => { ty_str | ty_vec(..) | ty_trait(..) | ty_closure(..) => {
@ -1093,7 +1082,8 @@ impl<'a> LookupContext<'a> {
} }
fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate) fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
-> MethodCallee { -> MethodCallee
{
// This method performs two sets of substitutions, one after the other: // This method performs two sets of substitutions, one after the other:
// 1. Substitute values for any type/lifetime parameters from the impl and // 1. Substitute values for any type/lifetime parameters from the impl and
// method declaration into the method type. This is the function type // method declaration into the method type. This is the function type
@ -1117,8 +1107,8 @@ impl<'a> LookupContext<'a> {
// If they were not explicitly supplied, just construct fresh // If they were not explicitly supplied, just construct fresh
// variables. // variables.
let num_supplied_tps = self.supplied_tps.len(); let num_supplied_tps = self.supplied_tps.len();
let num_method_tps = candidate.method_ty.generics.type_param_defs().len(); let num_method_tps = candidate.method_ty.generics.types.len(subst::FnSpace);
let m_substs = { let m_types = {
if num_supplied_tps == 0u { if num_supplied_tps == 0u {
self.fcx.infcx().next_ty_vars(num_method_tps) self.fcx.infcx().next_ty_vars(num_method_tps)
} else if num_method_tps == 0u { } else if num_method_tps == 0u {
@ -1129,37 +1119,23 @@ impl<'a> LookupContext<'a> {
} else if num_supplied_tps != num_method_tps { } else if num_supplied_tps != num_method_tps {
tcx.sess.span_err( tcx.sess.span_err(
self.span, self.span,
"incorrect number of type \ "incorrect number of type parameters given for this method");
parameters given for this method");
self.fcx.infcx().next_ty_vars(num_method_tps) self.fcx.infcx().next_ty_vars(num_method_tps)
} else { } else {
Vec::from_slice(self.supplied_tps) Vec::from_slice(self.supplied_tps)
} }
}; };
// Determine values for the early-bound lifetime parameters. // Create subst for early-bound lifetime parameters, combining
// parameters from the type and those from the method.
//
// FIXME -- permit users to manually specify lifetimes // FIXME -- permit users to manually specify lifetimes
let mut all_regions: Vec<Region> = match candidate.rcvr_substs.regions {
subst::NonerasedRegions(ref v) => {
v.iter().map(|r| r.clone()).collect()
}
subst::ErasedRegions => tcx.sess.span_bug(self.span, "ErasedRegions")
};
let m_regions = let m_regions =
self.fcx.infcx().region_vars_for_defs( self.fcx.infcx().region_vars_for_defs(
self.span, self.span,
candidate.method_ty.generics.region_param_defs.as_slice()); candidate.method_ty.generics.regions.get_vec(subst::FnSpace));
for &r in m_regions.iter() {
all_regions.push(r);
}
// Construct the full set of type parameters for the method, let all_substs = candidate.rcvr_substs.clone().with_method(m_types, m_regions);
// which is equal to the class tps + the method tps.
let all_substs = subst::Substs {
tps: candidate.rcvr_substs.tps.clone().append(m_substs.as_slice()),
regions: subst::NonerasedRegions(all_regions),
self_ty: candidate.rcvr_substs.self_ty,
};
let ref bare_fn_ty = candidate.method_ty.fty; let ref bare_fn_ty = candidate.method_ty.fty;
@ -1285,7 +1261,8 @@ impl<'a> LookupContext<'a> {
check_for_self_ty(sig.output); check_for_self_ty(sig.output);
} }
if candidate.method_ty.generics.has_type_params() { // reason (b) above if candidate.method_ty.generics.has_type_params(subst::FnSpace) {
// reason (b) above
self.tcx().sess.span_err( self.tcx().sess.span_err(
self.span, self.span,
"cannot call a generic method through an object"); "cannot call a generic method through an object");

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,7 @@
use middle::ty; use middle::ty;
use middle::ty::{AutoAddEnv, AutoDerefRef, AutoObject, param_ty}; use middle::ty::{AutoAddEnv, AutoDerefRef, AutoObject, ParamTy};
use middle::ty_fold::TypeFolder; use middle::ty_fold::TypeFolder;
use middle::typeck::astconv::AstConv; use middle::typeck::astconv::AstConv;
use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{FnCtxt, impl_self_ty};
@ -20,11 +20,11 @@ use middle::typeck::infer::fixup_err_to_str;
use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
use middle::typeck::infer; use middle::typeck::infer;
use middle::typeck::{vtable_origin, vtable_res, vtable_param_res}; use middle::typeck::{vtable_origin, vtable_res, vtable_param_res};
use middle::typeck::{vtable_static, vtable_param, impl_res}; use middle::typeck::{vtable_static, vtable_param, vtable_error};
use middle::typeck::{param_numbered, param_self, param_index}; use middle::typeck::{param_index};
use middle::typeck::MethodCall; use middle::typeck::MethodCall;
use middle::subst; use middle::subst;
use middle::subst::Subst; use middle::subst::{Subst, VecPerParamSpace};
use util::common::indenter; use util::common::indenter;
use util::ppaux; use util::ppaux;
use util::ppaux::Repr; use util::ppaux::Repr;
@ -76,38 +76,32 @@ impl<'a> VtableContext<'a> {
fn lookup_vtables(vcx: &VtableContext, fn lookup_vtables(vcx: &VtableContext,
span: Span, span: Span,
type_param_defs: &[ty::TypeParameterDef], type_param_defs: &VecPerParamSpace<ty::TypeParameterDef>,
substs: &subst::Substs, substs: &subst::Substs,
is_early: bool) -> vtable_res { is_early: bool)
debug!("lookup_vtables(span={:?}, \ -> VecPerParamSpace<vtable_param_res>
{
debug!("lookup_vtables(\
type_param_defs={}, \ type_param_defs={}, \
substs={}", substs={}",
span,
type_param_defs.repr(vcx.tcx()), type_param_defs.repr(vcx.tcx()),
substs.repr(vcx.tcx())); substs.repr(vcx.tcx()));
// We do this backwards for reasons discussed above. // We do this backwards for reasons discussed above.
assert_eq!(substs.tps.len(), type_param_defs.len()); let result = type_param_defs.map_rev(|def| {
let mut result: Vec<vtable_param_res> = let ty = *substs.types.get(def.space, def.index);
substs.tps.iter()
.rev()
.zip(type_param_defs.iter().rev())
.map(|(ty, def)|
lookup_vtables_for_param(vcx, span, Some(substs), lookup_vtables_for_param(vcx, span, Some(substs),
&*def.bounds, *ty, is_early)) &*def.bounds, ty, is_early)
.collect(); });
result.reverse();
assert_eq!(substs.tps.len(), result.len());
debug!("lookup_vtables result(\ debug!("lookup_vtables result(\
span={:?}, \
type_param_defs={}, \ type_param_defs={}, \
substs={}, \ substs={}, \
result={})", result={})",
span,
type_param_defs.repr(vcx.tcx()), type_param_defs.repr(vcx.tcx()),
substs.repr(vcx.tcx()), substs.repr(vcx.tcx()),
result.repr(vcx.tcx())); result.repr(vcx.tcx()));
result result
} }
@ -117,9 +111,15 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
substs: Option<&subst::Substs>, substs: Option<&subst::Substs>,
type_param_bounds: &ty::ParamBounds, type_param_bounds: &ty::ParamBounds,
ty: ty::t, ty: ty::t,
is_early: bool) -> vtable_param_res { is_early: bool)
-> vtable_param_res {
let tcx = vcx.tcx(); let tcx = vcx.tcx();
debug!("lookup_vtables_for_param(ty={}, type_param_bounds={}, is_early={})",
ty.repr(vcx.tcx()),
type_param_bounds.repr(vcx.tcx()),
is_early);
// ty is the value supplied for the type parameter A... // ty is the value supplied for the type parameter A...
let mut param_result = Vec::new(); let mut param_result = Vec::new();
@ -130,6 +130,10 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
// ...and here trait_ref is each bound that was declared on A, // ...and here trait_ref is each bound that was declared on A,
// expressed in terms of the type parameters. // expressed in terms of the type parameters.
debug!("matching ty={} trait_ref={}",
ty.repr(vcx.tcx()),
trait_ref.repr(vcx.tcx()));
ty::populate_implementations_for_trait_if_necessary(tcx, ty::populate_implementations_for_trait_if_necessary(tcx,
trait_ref.def_id); trait_ref.def_id);
@ -157,11 +161,9 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
}); });
debug!("lookup_vtables_for_param result(\ debug!("lookup_vtables_for_param result(\
span={:?}, \
type_param_bounds={}, \ type_param_bounds={}, \
ty={}, \ ty={}, \
result={})", result={})",
span,
type_param_bounds.repr(vcx.tcx()), type_param_bounds.repr(vcx.tcx()),
ty.repr(vcx.tcx()), ty.repr(vcx.tcx()),
param_result.repr(vcx.tcx())); param_result.repr(vcx.tcx()));
@ -216,10 +218,11 @@ fn lookup_vtable(vcx: &VtableContext,
ty: ty::t, ty: ty::t,
trait_ref: Rc<ty::TraitRef>, trait_ref: Rc<ty::TraitRef>,
is_early: bool) is_early: bool)
-> Option<vtable_origin> { -> Option<vtable_origin>
{
debug!("lookup_vtable(ty={}, trait_ref={})", debug!("lookup_vtable(ty={}, trait_ref={})",
vcx.infcx.ty_to_str(ty), ty.repr(vcx.tcx()),
vcx.infcx.trait_ref_to_str(&*trait_ref)); trait_ref.repr(vcx.tcx()));
let _i = indenter(); let _i = indenter();
let ty = match fixup_ty(vcx, span, ty, is_early) { let ty = match fixup_ty(vcx, span, ty, is_early) {
@ -230,32 +233,24 @@ fn lookup_vtable(vcx: &VtableContext,
// The type has unconstrained type variables in it, so we can't // The type has unconstrained type variables in it, so we can't
// do early resolution on it. Return some completely bogus vtable // do early resolution on it. Return some completely bogus vtable
// information: we aren't storing it anyways. // information: we aren't storing it anyways.
return Some(vtable_param(param_self, 0)); return Some(vtable_error);
} }
}; };
if ty::type_is_error(ty) {
return Some(vtable_error);
}
// If the type is self or a param, we look at the trait/supertrait // 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. // bounds to see if they include the trait we are looking for.
let vtable_opt = match ty::get(ty).sty { let vtable_opt = match ty::get(ty).sty {
ty::ty_param(param_ty {idx: n, ..}) => { ty::ty_param(ParamTy {space, idx: n, ..}) => {
let env_bounds = &vcx.param_env.type_param_bounds; let env_bounds = &vcx.param_env.bounds;
if env_bounds.len() > n { let type_param_bounds = &env_bounds.get(space, n).trait_bounds;
let type_param_bounds: &[Rc<ty::TraitRef>] =
env_bounds.get(n).trait_bounds.as_slice();
lookup_vtable_from_bounds(vcx, span, lookup_vtable_from_bounds(vcx, span,
type_param_bounds, type_param_bounds.as_slice(),
param_numbered(n), param_index { space: space,
trait_ref.clone()) index: n },
} else {
None
}
}
ty::ty_self(_) => {
let self_param_bound = vcx.param_env.self_param_bound.clone().unwrap();
lookup_vtable_from_bounds(vcx, span,
[self_param_bound],
param_self,
trait_ref.clone()) trait_ref.clone())
} }
@ -373,8 +368,8 @@ fn search_for_vtable(vcx: &VtableContext,
// Now, in the previous example, for_ty is bound to // Now, in the previous example, for_ty is bound to
// the type self_ty, and substs is bound to [T]. // the type self_ty, and substs is bound to [T].
debug!("The self ty is {} and its substs are {}", debug!("The self ty is {} and its substs are {}",
vcx.infcx.ty_to_str(for_ty), for_ty.repr(tcx),
vcx.infcx.tys_to_str(substs.tps.as_slice())); substs.types.repr(tcx));
// Next, we unify trait_ref -- the type that we want to cast // Next, we unify trait_ref -- the type that we want to cast
// to -- with of_trait_ref -- the trait that im implements. At // to -- with of_trait_ref -- the trait that im implements. At
@ -386,12 +381,13 @@ fn search_for_vtable(vcx: &VtableContext,
// some value of U) with some_trait<T>. This would fail if T // some value of U) with some_trait<T>. This would fail if T
// and U weren't compatible. // and U weren't compatible.
debug!("(checking vtable) {}2 relating trait \ let of_trait_ref = of_trait_ref.subst(tcx, &substs);
ty {} to of_trait_ref {}", "#",
debug!("(checking vtable) num 2 relating trait \
ty {} to of_trait_ref {}",
vcx.infcx.trait_ref_to_str(&*trait_ref), vcx.infcx.trait_ref_to_str(&*trait_ref),
vcx.infcx.trait_ref_to_str(&*of_trait_ref)); vcx.infcx.trait_ref_to_str(&*of_trait_ref));
let of_trait_ref = of_trait_ref.subst(tcx, &substs);
relate_trait_refs(vcx, span, of_trait_ref, trait_ref.clone()); relate_trait_refs(vcx, span, of_trait_ref, trait_ref.clone());
@ -404,11 +400,12 @@ fn search_for_vtable(vcx: &VtableContext,
// process of looking up bounds might constrain some of them. // process of looking up bounds might constrain some of them.
let im_generics = let im_generics =
ty::lookup_item_type(tcx, impl_did).generics; ty::lookup_item_type(tcx, impl_did).generics;
let subres = lookup_vtables(vcx, span, let subres = lookup_vtables(vcx,
im_generics.type_param_defs(), &substs, span,
&im_generics.types,
&substs,
is_early); is_early);
// substs might contain type variables, so we call // substs might contain type variables, so we call
// fixup_substs to resolve them. // fixup_substs to resolve them.
let substs_f = match fixup_substs(vcx, span, let substs_f = match fixup_substs(vcx, span,
@ -419,15 +416,15 @@ fn search_for_vtable(vcx: &VtableContext,
None => { None => {
assert!(is_early); assert!(is_early);
// Bail out with a bogus answer // Bail out with a bogus answer
return Some(vtable_param(param_self, 0)); return Some(vtable_error);
} }
}; };
debug!("The fixed-up substs are {} - \ debug!("The fixed-up substs are {} - \
they will be unified with the bounds for \ they will be unified with the bounds for \
the target ty, {}", the target ty, {}",
vcx.infcx.tys_to_str(substs_f.tps.as_slice()), substs_f.types.repr(tcx),
vcx.infcx.trait_ref_to_str(&*trait_ref)); trait_ref.repr(tcx));
// Next, we unify the fixed-up substitutions for the impl self // Next, we unify the fixed-up substitutions for the impl self
// ty with the substitutions from the trait type that we're // ty with the substitutions from the trait type that we're
@ -515,7 +512,7 @@ fn connect_trait_tps(vcx: &VtableContext,
} }
fn insert_vtables(fcx: &FnCtxt, vtable_key: MethodCall, vtables: vtable_res) { fn insert_vtables(fcx: &FnCtxt, vtable_key: MethodCall, vtables: vtable_res) {
debug!("insert_vtables(vtable_key={}, vtables={:?})", debug!("insert_vtables(vtable_key={}, vtables={})",
vtable_key, vtables.repr(fcx.tcx())); vtable_key, vtables.repr(fcx.tcx()));
fcx.inh.vtable_map.borrow_mut().insert(vtable_key, vtables); fcx.inh.vtable_map.borrow_mut().insert(vtable_key, vtables);
} }
@ -560,12 +557,20 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
}; };
let vcx = fcx.vtable_context(); let vcx = fcx.vtable_context();
// Take the type parameters from the object
// type, but set the Self type (which is
// unknown, for the object type) to be the type
// we are casting from.
let mut target_types = target_substs.types.clone();
assert!(target_types.get_self().is_none());
target_types.push(subst::SelfSpace, typ);
let target_trait_ref = Rc::new(ty::TraitRef { let target_trait_ref = Rc::new(ty::TraitRef {
def_id: target_def_id, def_id: target_def_id,
substs: subst::Substs { substs: subst::Substs {
tps: target_substs.tps.clone(),
regions: target_substs.regions.clone(), regions: target_substs.regions.clone(),
self_ty: Some(typ) types: target_types
} }
}); });
@ -582,7 +587,9 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
is_early); is_early);
if !is_early { if !is_early {
insert_vtables(fcx, MethodCall::expr(ex.id), vec!(vtables)); let mut r = VecPerParamSpace::empty();
r.push(subst::SelfSpace, vtables);
insert_vtables(fcx, MethodCall::expr(ex.id), r);
} }
// Now, if this is &trait, we need to link the // Now, if this is &trait, we need to link the
@ -632,10 +639,10 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
debug!("early resolve expr: def {:?} {:?}, {:?}, {}", ex.id, did, def, debug!("early resolve expr: def {:?} {:?}, {:?}, {}", ex.id, did, def,
fcx.infcx().ty_to_str(item_ty.ty)); fcx.infcx().ty_to_str(item_ty.ty));
debug!("early_resolve_expr: looking up vtables for type params {}", debug!("early_resolve_expr: looking up vtables for type params {}",
item_ty.generics.type_param_defs().repr(fcx.tcx())); item_ty.generics.types.repr(fcx.tcx()));
let vcx = fcx.vtable_context(); let vcx = fcx.vtable_context();
let vtbls = lookup_vtables(&vcx, ex.span, let vtbls = lookup_vtables(&vcx, ex.span,
item_ty.generics.type_param_defs(), &item_ty.generics.types,
&item_substs.substs, is_early); &item_substs.substs, is_early);
if !is_early { if !is_early {
insert_vtables(fcx, MethodCall::expr(ex.id), vtbls); insert_vtables(fcx, MethodCall::expr(ex.id), vtbls);
@ -657,7 +664,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
let substs = fcx.method_ty_substs(ex.id); let substs = fcx.method_ty_substs(ex.id);
let vcx = fcx.vtable_context(); let vcx = fcx.vtable_context();
let vtbls = lookup_vtables(&vcx, ex.span, let vtbls = lookup_vtables(&vcx, ex.span,
type_param_defs.as_slice(), &type_param_defs,
&substs, is_early); &substs, is_early);
if !is_early { if !is_early {
insert_vtables(fcx, MethodCall::expr(ex.id), vtbls); insert_vtables(fcx, MethodCall::expr(ex.id), vtbls);
@ -689,8 +696,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
ty::method_call_type_param_defs(cx.tcx, method.origin); ty::method_call_type_param_defs(cx.tcx, method.origin);
let vcx = fcx.vtable_context(); let vcx = fcx.vtable_context();
let vtbls = lookup_vtables(&vcx, ex.span, let vtbls = lookup_vtables(&vcx, ex.span,
type_param_defs.deref() &type_param_defs,
.as_slice(),
&method.substs, is_early); &method.substs, is_early);
if !is_early { if !is_early {
insert_vtables(fcx, method_call, vtbls); insert_vtables(fcx, method_call, vtbls);
@ -726,64 +732,84 @@ pub fn resolve_impl(tcx: &ty::ctxt,
impl_item: &ast::Item, impl_item: &ast::Item,
impl_generics: &ty::Generics, impl_generics: &ty::Generics,
impl_trait_ref: &ty::TraitRef) { impl_trait_ref: &ty::TraitRef) {
/*!
* The situation is as follows. We have some trait like:
*
* trait Foo<A:Clone> : Bar {
* fn method() { ... }
* }
*
* and an impl like:
*
* impl<B:Clone> Foo<B> for int { ... }
*
* We want to validate that the various requirements of the trait
* are met:
*
* A:Clone, Self:Bar
*
* But of course after substituting the types from the impl:
*
* B:Clone, int:Bar
*
* We store these results away as the "impl_res" for use by the
* default methods.
*/
debug!("resolve_impl(impl_item.id={})", debug!("resolve_impl(impl_item.id={})",
impl_item.id); impl_item.id);
let param_env = ty::construct_parameter_environment( let param_env = ty::construct_parameter_environment(tcx,
tcx, impl_generics,
None,
impl_generics.type_param_defs(),
[],
impl_generics.region_param_defs(),
[],
impl_item.id); impl_item.id);
// The impl_trait_ref in our example above would be
// `Foo<B> for int`
let impl_trait_ref = impl_trait_ref.subst(tcx, &param_env.free_substs); let impl_trait_ref = impl_trait_ref.subst(tcx, &param_env.free_substs);
debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx)); debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx));
let infcx = &infer::new_infer_ctxt(tcx); let infcx = &infer::new_infer_ctxt(tcx);
let vcx = VtableContext { infcx: infcx, param_env: &param_env }; let vcx = VtableContext { infcx: infcx, param_env: &param_env };
// First, check that the impl implements any trait bounds // Resolve the vtables for the trait reference on the impl. This
// on the trait. // serves many purposes, best explained by example. Imagine we have:
//
// trait A<T:B> : C { fn x(&self) { ... } }
//
// and
//
// impl A<int> for uint { ... }
//
// In that case, the trait ref will be `A<int> for uint`. Resolving
// this will first check that the various types meet their requirements:
//
// 1. Because of T:B, int must implement the trait B
// 2. Because of the supertrait C, uint must implement the trait C.
//
// Simultaneously, the result of this resolution (`vtbls`), is precisely
// the set of vtable information needed to compile the default method
// `x()` adapted to the impl. (After all, a default method is basically
// the same as:
//
// fn default_x<T:B, Self:A>(...) { .. .})
let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id); let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id);
let vtbls = lookup_vtables(&vcx, impl_item.span, let vtbls = lookup_vtables(&vcx,
trait_def.generics.type_param_defs(), impl_item.span,
&trait_def.generics.types,
&impl_trait_ref.substs, &impl_trait_ref.substs,
false); 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::empty_builtin_bounds(),
trait_bounds: vec!(Rc::new(impl_trait_ref))
};
let t = ty::node_id_to_type(tcx, impl_item.id);
let t = t.subst(tcx, &param_env.free_substs);
debug!("=== Doing a self lookup now.");
// Right now, we don't have any place to store this.
// We will need to make one so we can use this information
// for compiling default methods that refer to supertraits.
let self_vtable_res =
lookup_vtables_for_param(&vcx, impl_item.span, None,
&param_bounds, t, false);
infcx.resolve_regions_and_report_errors(); infcx.resolve_regions_and_report_errors();
let res = impl_res { let vtbls = writeback::resolve_impl_res(infcx, impl_item.span, &vtbls);
trait_vtables: vtbls,
self_vtables: self_vtable_res
};
let res = writeback::resolve_impl_res(infcx, impl_item.span, &res);
let impl_def_id = ast_util::local_def(impl_item.id); let impl_def_id = ast_util::local_def(impl_item.id);
debug!("impl_vtables for {} are {}", debug!("impl_vtables for {} are {}",
impl_def_id.repr(tcx), impl_def_id.repr(tcx),
res.repr(tcx)); vtbls.repr(tcx));
tcx.impl_vtables.borrow_mut().insert(impl_def_id, res); tcx.impl_vtables.borrow_mut().insert(impl_def_id, vtbls);
} }
/// Resolve vtables for a method call after typeck has finished. /// Resolve vtables for a method call after typeck has finished.
@ -791,15 +817,14 @@ pub fn resolve_impl(tcx: &ty::ctxt,
pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId, pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId,
substs: &subst::Substs) -> vtable_res { substs: &subst::Substs) -> vtable_res {
let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics; let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics;
let type_param_defs = &*generics.type_param_defs;
let vcx = VtableContext { let vcx = VtableContext {
infcx: &infer::new_infer_ctxt(tcx), infcx: &infer::new_infer_ctxt(tcx),
param_env: &ty::construct_parameter_environment(tcx, None, [], [], [], [], id) param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id)
}; };
lookup_vtables(&vcx, lookup_vtables(&vcx,
tcx.map.span(id), tcx.map.span(id),
type_param_defs.as_slice(), &generics.types,
substs, substs,
false) false)
} }

View file

@ -14,7 +14,6 @@
use middle::def; use middle::def;
use middle::pat_util; use middle::pat_util;
use middle::subst;
use middle::ty; use middle::ty;
use middle::ty_fold::{TypeFolder,TypeFoldable}; use middle::ty_fold::{TypeFolder,TypeFoldable};
use middle::typeck::astconv::AstConv; use middle::typeck::astconv::AstConv;
@ -22,8 +21,8 @@ use middle::typeck::check::FnCtxt;
use middle::typeck::infer::{force_all, resolve_all, resolve_region}; use middle::typeck::infer::{force_all, resolve_all, resolve_region};
use middle::typeck::infer::resolve_type; use middle::typeck::infer::resolve_type;
use middle::typeck::infer; use middle::typeck::infer;
use middle::typeck::impl_res;
use middle::typeck::{MethodCall, MethodCallee}; use middle::typeck::{MethodCall, MethodCallee};
use middle::typeck::vtable_res;
use middle::typeck::write_substs_to_tcx; use middle::typeck::write_substs_to_tcx;
use middle::typeck::write_ty_to_tcx; use middle::typeck::write_ty_to_tcx;
use util::ppaux::Repr; use util::ppaux::Repr;
@ -66,13 +65,13 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
pub fn resolve_impl_res(infcx: &infer::InferCtxt, pub fn resolve_impl_res(infcx: &infer::InferCtxt,
span: Span, span: Span,
impl_res: &impl_res) vtable_res: &vtable_res)
-> impl_res { -> vtable_res {
let errors = Cell::new(false); // nobody cares let errors = Cell::new(false); // nobody cares
let mut resolver = Resolver::from_infcx(infcx, let mut resolver = Resolver::from_infcx(infcx,
&errors, &errors,
ResolvingImplRes(span)); ResolvingImplRes(span));
impl_res.resolve_in(&mut resolver) vtable_res.resolve_in(&mut resolver)
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -285,22 +284,12 @@ impl<'cx> WritebackCx<'cx> {
debug!("writeback::resolve_method_map_entry(call={:?}, entry={})", debug!("writeback::resolve_method_map_entry(call={:?}, entry={})",
method_call, method_call,
method.repr(self.tcx())); method.repr(self.tcx()));
let mut new_method = MethodCallee { let new_method = MethodCallee {
origin: method.origin, origin: method.origin,
ty: self.resolve(&method.ty, reason), ty: self.resolve(&method.ty, reason),
substs: self.resolve(&method.substs, reason), substs: self.resolve(&method.substs, reason),
}; };
// Wack. For some reason I don't quite know, we always
// hard-code the self-ty and regions to these
// values. Changing this causes downstream errors I
// don't feel like investigating right now (in
// particular, self_ty is set to mk_err in some cases,
// probably for invocations on objects, and this
// causes encoding failures). -nmatsakis
new_method.substs.self_ty = None;
new_method.substs.regions = subst::ErasedRegions;
self.tcx().method_map.borrow_mut().insert( self.tcx().method_map.borrow_mut().insert(
method_call, method_call,
new_method); new_method);

View file

@ -24,7 +24,7 @@ use middle::ty::{ImplContainer, lookup_item_type};
use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err}; use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err};
use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil};
use middle::ty::{ty_param, ty_param_bounds_and_ty, ty_ptr}; use middle::ty::{ty_param, ty_param_bounds_and_ty, ty_ptr};
use middle::ty::{ty_rptr, ty_self, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
use middle::ty::{ty_uint, ty_uniq, ty_bare_fn, ty_closure}; use middle::ty::{ty_uint, ty_uniq, ty_bare_fn, ty_closure};
use middle::ty::type_is_ty_var; use middle::ty::type_is_ty_var;
use middle::subst::Subst; use middle::subst::Subst;
@ -43,7 +43,7 @@ use syntax::ast;
use syntax::ast_map::NodeItem; use syntax::ast_map::NodeItem;
use syntax::ast_map; use syntax::ast_map;
use syntax::ast_util::{local_def}; use syntax::ast_util::{local_def};
use syntax::codemap::Span; use syntax::codemap::{Span, DUMMY_SP};
use syntax::parse::token; use syntax::parse::token;
use syntax::visit; use syntax::visit;
@ -81,7 +81,7 @@ fn get_base_type(inference_context: &InferCtxt,
ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) | ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
ty_infer(..) | ty_param(..) | ty_self(..) | ty_err | ty_infer(..) | ty_param(..) | ty_err |
ty_box(_) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => { ty_box(_) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => {
debug!("(getting base type) no base type; found {:?}", debug!("(getting base type) no base type; found {:?}",
get(original_type).sty); get(original_type).sty);
@ -338,7 +338,8 @@ impl<'a> CoherenceChecker<'a> {
// Creates default method IDs and performs type substitutions for an impl // Creates default method IDs and performs type substitutions for an impl
// and trait pair. Then, for each provided method in the trait, inserts a // and trait pair. Then, for each provided method in the trait, inserts a
// `ProvidedMethodInfo` instance into the `provided_method_sources` map. // `ProvidedMethodInfo` instance into the `provided_method_sources` map.
fn instantiate_default_methods(&self, impl_id: DefId, fn instantiate_default_methods(&self,
impl_id: DefId,
trait_ref: &ty::TraitRef, trait_ref: &ty::TraitRef,
all_methods: &mut Vec<DefId>) { all_methods: &mut Vec<DefId>) {
let tcx = self.crate_context.tcx; let tcx = self.crate_context.tcx;
@ -360,6 +361,7 @@ impl<'a> CoherenceChecker<'a> {
Rc::new(subst_receiver_types_in_method_ty( Rc::new(subst_receiver_types_in_method_ty(
tcx, tcx,
impl_id, impl_id,
&impl_poly_type,
trait_ref, trait_ref,
new_did, new_did,
&**trait_method, &**trait_method,
@ -368,17 +370,11 @@ impl<'a> CoherenceChecker<'a> {
debug!("new_method_ty={}", new_method_ty.repr(tcx)); debug!("new_method_ty={}", new_method_ty.repr(tcx));
all_methods.push(new_did); all_methods.push(new_did);
// construct the polytype for the method based on the method_ty // construct the polytype for the method based on the
let new_generics = ty::Generics { // method_ty. it will have all the generics from the
type_param_defs: // impl, plus its own.
Rc::new(Vec::from_slice(impl_poly_type.generics.type_param_defs()).append(
new_method_ty.generics.type_param_defs())),
region_param_defs:
Rc::new(Vec::from_slice(impl_poly_type.generics.region_param_defs()).append(
new_method_ty.generics.region_param_defs()))
};
let new_polytype = ty::ty_param_bounds_and_ty { let new_polytype = ty::ty_param_bounds_and_ty {
generics: new_generics, generics: new_method_ty.generics.clone(),
ty: ty::mk_bare_fn(tcx, new_method_ty.fty.clone()) ty: ty::mk_bare_fn(tcx, new_method_ty.fty.clone())
}; };
debug!("new_polytype={}", new_polytype.repr(tcx)); debug!("new_polytype={}", new_polytype.repr(tcx));
@ -503,21 +499,11 @@ impl<'a> CoherenceChecker<'a> {
// Converts a polytype to a monotype by replacing all parameters with // Converts a polytype to a monotype by replacing all parameters with
// type variables. Returns the monotype and the type variables created. // type variables. Returns the monotype and the type variables created.
fn universally_quantify_polytype(&self, polytype: ty_param_bounds_and_ty) fn universally_quantify_polytype(&self, polytype: ty_param_bounds_and_ty)
-> UniversalQuantificationResult { -> UniversalQuantificationResult
let region_parameters = {
polytype.generics.region_param_defs().iter() let substitutions =
.map(|d| self.inference_context.next_region_var( self.inference_context.fresh_substs_for_type(DUMMY_SP,
infer::BoundRegionInCoherence(d.name))) &polytype.generics);
.collect();
let bounds_count = polytype.generics.type_param_defs().len();
let type_parameters = self.inference_context.next_ty_vars(bounds_count);
let substitutions = subst::Substs {
regions: subst::NonerasedRegions(region_parameters),
self_ty: None,
tps: type_parameters
};
let monotype = polytype.ty.subst(self.crate_context.tcx, &substitutions); let monotype = polytype.ty.subst(self.crate_context.tcx, &substitutions);
UniversalQuantificationResult { UniversalQuantificationResult {
@ -731,69 +717,67 @@ impl<'a> CoherenceChecker<'a> {
} }
pub fn make_substs_for_receiver_types(tcx: &ty::ctxt, pub fn make_substs_for_receiver_types(tcx: &ty::ctxt,
impl_id: ast::DefId,
trait_ref: &ty::TraitRef, trait_ref: &ty::TraitRef,
method: &ty::Method) method: &ty::Method)
-> subst::Substs { -> subst::Substs
{
/*! /*!
* Substitutes the values for the receiver's type parameters * Substitutes the values for the receiver's type parameters
* that are found in method, leaving the method's type parameters * that are found in method, leaving the method's type parameters
* intact. This is in fact a mildly complex operation, * intact.
* largely because of the hokey way that we concatenate the
* receiver and method generics.
*/ */
let impl_polytype = ty::lookup_item_type(tcx, impl_id);
let num_impl_tps = impl_polytype.generics.type_param_defs().len();
let num_impl_regions = impl_polytype.generics.region_param_defs().len();
let meth_tps: Vec<ty::t> = let meth_tps: Vec<ty::t> =
method.generics.type_param_defs().iter().enumerate() method.generics.types.get_vec(subst::FnSpace)
.map(|(i, t)| ty::mk_param(tcx, i + num_impl_tps, t.def_id)) .iter()
.map(|def| ty::mk_param_from_def(tcx, def))
.collect(); .collect();
let meth_regions: Vec<ty::Region> = let meth_regions: Vec<ty::Region> =
method.generics.region_param_defs().iter().enumerate() method.generics.regions.get_vec(subst::FnSpace)
.map(|(i, l)| ty::ReEarlyBound(l.def_id.node, i + num_impl_regions, l.name)) .iter()
.map(|def| ty::ReEarlyBound(def.def_id.node, def.space,
def.index, def.name))
.collect(); .collect();
let mut combined_tps = trait_ref.substs.tps.clone(); trait_ref.substs.clone().with_method(meth_tps, meth_regions)
combined_tps.push_all_move(meth_tps);
let combined_regions = match &trait_ref.substs.regions {
&subst::ErasedRegions =>
fail!("make_substs_for_receiver_types: unexpected ErasedRegions"),
&subst::NonerasedRegions(ref rs) => {
let mut rs = rs.clone();
rs.push_all_move(meth_regions);
subst::NonerasedRegions(rs)
}
};
subst::Substs {
regions: combined_regions,
self_ty: trait_ref.substs.self_ty,
tps: combined_tps
}
} }
fn subst_receiver_types_in_method_ty(tcx: &ty::ctxt, fn subst_receiver_types_in_method_ty(tcx: &ty::ctxt,
impl_id: ast::DefId, impl_id: ast::DefId,
impl_poly_type: &ty::ty_param_bounds_and_ty,
trait_ref: &ty::TraitRef, trait_ref: &ty::TraitRef,
new_def_id: ast::DefId, new_def_id: ast::DefId,
method: &ty::Method, method: &ty::Method,
provided_source: Option<ast::DefId>) provided_source: Option<ast::DefId>)
-> ty::Method { -> ty::Method
{
let combined_substs = make_substs_for_receiver_types(tcx, trait_ref, method);
let combined_substs = make_substs_for_receiver_types( debug!("subst_receiver_types_in_method_ty: combined_substs={}",
tcx, impl_id, trait_ref, method); combined_substs.repr(tcx));
let mut method_generics = method.generics.subst(tcx, &combined_substs);
// replace the type parameters declared on the trait with those
// from the impl
for &space in [subst::TypeSpace, subst::SelfSpace].iter() {
*method_generics.types.get_mut_vec(space) =
impl_poly_type.generics.types.get_vec(space).clone();
*method_generics.regions.get_mut_vec(space) =
impl_poly_type.generics.regions.get_vec(space).clone();
}
debug!("subst_receiver_types_in_method_ty: method_generics={}",
method_generics.repr(tcx));
let method_fty = method.fty.subst(tcx, &combined_substs);
debug!("subst_receiver_types_in_method_ty: method_ty={}",
method.fty.repr(tcx));
ty::Method::new( ty::Method::new(
method.ident, method.ident,
method_generics,
// method types *can* appear in the generic bounds method_fty,
method.generics.subst(tcx, &combined_substs),
// method types *can* appear in the fty
method.fty.subst(tcx, &combined_substs),
method.explicit_self, method.explicit_self,
method.vis, method.vis,
new_def_id, new_def_id,

View file

@ -36,7 +36,7 @@ use middle::def;
use middle::lang_items::SizedTraitLangItem; use middle::lang_items::SizedTraitLangItem;
use middle::resolve_lifetime; use middle::resolve_lifetime;
use middle::subst; use middle::subst;
use middle::subst::{Subst, Substs}; use middle::subst::{Substs};
use middle::ty::{ImplContainer, MethodContainer, TraitContainer}; use middle::ty::{ImplContainer, MethodContainer, TraitContainer};
use middle::ty::{ty_param_bounds_and_ty}; use middle::ty::{ty_param_bounds_and_ty};
use middle::ty; use middle::ty;
@ -191,36 +191,35 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
} }
} }
pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { pub fn ensure_trait_methods(ccx: &CrateCtxt,
trait_id: ast::NodeId,
trait_def: &ty::TraitDef) {
let tcx = ccx.tcx; let tcx = ccx.tcx;
match tcx.map.get(trait_id) { match tcx.map.get(trait_id) {
ast_map::NodeItem(item) => { ast_map::NodeItem(item) => {
match item.node { match item.node {
ast::ItemTrait(ref generics, _, _, ref ms) => { ast::ItemTrait(_, _, _, ref ms) => {
let trait_ty_generics = ty_generics_for_type(ccx, generics);
// For each method, construct a suitable ty::Method and // For each method, construct a suitable ty::Method and
// store it into the `tcx.methods` table: // store it into the `tcx.methods` table:
for m in ms.iter() { for m in ms.iter() {
let ty_method = Rc::new(match m { let ty_method = Rc::new(match m {
&ast::Required(ref m) => { &ast::Required(ref m) => {
ty_method_of_trait_method( ty_method_of_trait_method(
ccx, trait_id, &trait_ty_generics, ccx, trait_id, &trait_def.generics,
&m.id, &m.ident, &m.explicit_self, &m.id, &m.ident, &m.explicit_self,
&m.generics, &m.fn_style, &*m.decl) &m.generics, &m.fn_style, &*m.decl)
} }
&ast::Provided(ref m) => { &ast::Provided(ref m) => {
ty_method_of_trait_method( ty_method_of_trait_method(
ccx, trait_id, &trait_ty_generics, ccx, trait_id, &trait_def.generics,
&m.id, &m.ident, &m.explicit_self, &m.id, &m.ident, &m.explicit_self,
&m.generics, &m.fn_style, &*m.decl) &m.generics, &m.fn_style, &*m.decl)
} }
}); });
if ty_method.explicit_self == ast::SelfStatic { if ty_method.explicit_self == ast::SelfStatic {
make_static_method_ty(ccx, trait_id, &*ty_method, make_static_method_ty(ccx, &*ty_method);
&trait_ty_generics);
} }
tcx.methods.borrow_mut().insert(ty_method.def_id, tcx.methods.borrow_mut().insert(ty_method.def_id,
@ -249,129 +248,12 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) {
_ => { /* Ignore things that aren't traits */ } _ => { /* Ignore things that aren't traits */ }
} }
fn make_static_method_ty(ccx: &CrateCtxt, fn make_static_method_ty(ccx: &CrateCtxt, m: &ty::Method) {
trait_id: ast::NodeId, ccx.tcx.tcache.borrow_mut().insert(
m: &ty::Method, m.def_id,
trait_ty_generics: &ty::Generics) {
// If declaration is
//
// trait 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, // First the lifetime params from trait
// 'd,'e,'f, // Then lifetime params from `foo()`
// a,b,c, // Then type params from trait
// D:Trait<'a,'b,'c,a,b,c>, // Then this sucker
// E,F,G // Then type params from `foo()`, offset by 1
// >(...) -> D' {}
//
// Note that `Self` is replaced with an explicit type
// parameter D that is sandwiched in between the trait params
// and the method params, and thus the indices of the method
// type parameters are offset by 1 (that is, the method
// parameters are mapped from d, e, f to E, F, and G). The
// choice of this ordering is somewhat arbitrary.
//
// Note also that the bound for `D` is `Trait<'a,'b,'c,a,b,c>`.
// This implies that the lifetime parameters that were inherited
// from the trait (i.e., `'a`, `'b`, and `'c`) all must be early
// bound, since they appear in a trait bound.
//
// Also, this system is rather a hack that should be replaced
// with a more uniform treatment of Self (which is partly
// underway).
// build up a subst that shifts all of the parameters over
// by one and substitute in a new type param for self
let tcx = ccx.tcx;
let dummy_defid = ast::DefId {krate: 0, node: 0};
// Represents [A',B',C']
let num_trait_bounds = trait_ty_generics.type_param_defs().len();
let non_shifted_trait_tps = Vec::from_fn(num_trait_bounds, |i| {
ty::mk_param(tcx, i, trait_ty_generics.type_param_defs()[i].def_id)
});
// Represents [D']
let self_param = ty::mk_param(tcx, num_trait_bounds,
dummy_defid);
// Represents [E',F',G']
let num_method_bounds = m.generics.type_param_defs().len();
let shifted_method_tps = Vec::from_fn(num_method_bounds, |i| {
ty::mk_param(tcx, i + num_trait_bounds + 1,
m.generics.type_param_defs()[i].def_id)
});
// Convert the regions 'a, 'b, 'c defined on the trait into
// bound regions on the fn. Note that because these appear in the
// bound for `Self` they must be early bound.
let new_early_region_param_defs = trait_ty_generics.region_param_defs.clone();
let rps_from_trait =
trait_ty_generics.region_param_defs().iter().
enumerate().
map(|(index,d)| ty::ReEarlyBound(d.def_id.node, index, d.name)).
collect();
// build up the substitution from
// 'a,'b,'c => 'a,'b,'c
// A,B,C => A',B',C'
// Self => D'
// D,E,F => E',F',G'
let substs = subst::Substs {
regions: subst::NonerasedRegions(rps_from_trait),
self_ty: Some(self_param),
tps: non_shifted_trait_tps.append(shifted_method_tps.as_slice())
};
// create the type of `foo`, applying the substitution above
let ty = ty::mk_bare_fn(tcx, m.fty.clone()).subst(tcx, &substs);
// create the type parameter definitions for `foo`, applying
// the substitution to any traits that appear in their bounds.
// add in the type parameters from the trait
let mut new_type_param_defs = Vec::new();
let substd_type_param_defs =
trait_ty_generics.type_param_defs.subst(tcx, &substs);
new_type_param_defs.push_all(substd_type_param_defs.as_slice());
// add in the "self" type parameter
let self_trait_def = get_trait_def(ccx, local_def(trait_id));
let self_trait_ref = self_trait_def.trait_ref.subst(tcx, &substs);
new_type_param_defs.push(ty::TypeParameterDef {
ident: special_idents::self_,
def_id: dummy_defid,
bounds: Rc::new(ty::ParamBounds {
builtin_bounds: ty::empty_builtin_bounds(),
trait_bounds: vec!(self_trait_ref)
}),
default: None
});
// add in the type parameters from the method
let substd_type_param_defs = m.generics.type_param_defs.subst(tcx, &substs);
new_type_param_defs.push_all(substd_type_param_defs.as_slice());
debug!("static method {} type_param_defs={} ty={}, substs={}",
m.def_id.repr(tcx),
new_type_param_defs.repr(tcx),
ty.repr(tcx),
substs.repr(tcx));
tcx.tcache.borrow_mut().insert(m.def_id,
ty_param_bounds_and_ty { ty_param_bounds_and_ty {
generics: ty::Generics { generics: m.generics.clone(),
type_param_defs: Rc::new(new_type_param_defs), ty: ty::mk_bare_fn(ccx.tcx, m.fty.clone()) });
region_param_defs: new_early_region_param_defs
},
ty: ty
});
} }
fn ty_method_of_trait_method(this: &CrateCtxt, fn ty_method_of_trait_method(this: &CrateCtxt,
@ -384,12 +266,13 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) {
m_fn_style: &ast::FnStyle, m_fn_style: &ast::FnStyle,
m_decl: &ast::FnDecl) -> ty::Method m_decl: &ast::FnDecl) -> ty::Method
{ {
let trait_self_ty = ty::mk_self(this.tcx, local_def(trait_id)); let trait_self_ty = ty::mk_self_type(this.tcx, local_def(trait_id));
let fty = astconv::ty_of_method(this, *m_id, *m_fn_style, trait_self_ty, let fty = astconv::ty_of_method(this, *m_id, *m_fn_style, trait_self_ty,
*m_explicit_self, m_decl); *m_explicit_self, m_decl);
let num_trait_type_params = trait_generics.type_param_defs().len(); let ty_generics =
let ty_generics = ty_generics_for_fn_or_method(this, m_generics, ty_generics_for_fn_or_method(this,
num_trait_type_params); m_generics,
(*trait_generics).clone());
ty::Method::new( ty::Method::new(
*m_ident, *m_ident,
ty_generics, ty_generics,
@ -404,54 +287,6 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) {
} }
} }
pub fn ensure_supertraits(ccx: &CrateCtxt,
id: ast::NodeId,
sp: codemap::Span,
ast_trait_refs: &[ast::TraitRef],
sized: ast::Sized)
-> ty::BuiltinBounds
{
let tcx = ccx.tcx;
// Called only the first time trait_def_of_item is called.
// Supertraits are ensured at the same time.
assert!(!tcx.supertraits.borrow().contains_key(&local_def(id)));
let self_ty = ty::mk_self(ccx.tcx, local_def(id));
let mut ty_trait_refs: Vec<Rc<ty::TraitRef>> = Vec::new();
let mut bounds = ty::empty_builtin_bounds();
for ast_trait_ref in ast_trait_refs.iter() {
let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, ast_trait_ref);
// 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, self_ty);
if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) {
// FIXME(#5527) Could have same trait multiple times
if ty_trait_refs.iter().any(|other_trait| other_trait.def_id == trait_ref.def_id) {
// This means a trait inherited from the same supertrait more
// than once.
tcx.sess.span_err(sp, "duplicate supertrait in trait declaration");
break;
} else {
ty_trait_refs.push(trait_ref);
}
}
}
if sized == ast::StaticSize {
match tcx.lang_items.require(SizedTraitLangItem) {
Ok(def_id) => {
ty::try_add_builtin_trait(tcx, def_id, &mut bounds);
}
Err(s) => tcx.sess.err(s.as_slice()),
};
}
tcx.supertraits.borrow_mut().insert(local_def(id), Rc::new(ty_trait_refs));
bounds
}
pub fn convert_field(ccx: &CrateCtxt, pub fn convert_field(ccx: &CrateCtxt,
struct_generics: &ty::Generics, struct_generics: &ty::Generics,
v: &ast::StructField, v: &ast::StructField,
@ -490,7 +325,6 @@ fn convert_methods(ccx: &CrateCtxt,
ms: &[Gc<ast::Method>], ms: &[Gc<ast::Method>],
untransformed_rcvr_ty: ty::t, untransformed_rcvr_ty: ty::t,
rcvr_ty_generics: &ty::Generics, rcvr_ty_generics: &ty::Generics,
rcvr_ast_generics: &ast::Generics,
rcvr_visibility: ast::Visibility) rcvr_visibility: ast::Visibility)
{ {
let tcx = ccx.tcx; let tcx = ccx.tcx;
@ -500,14 +334,11 @@ fn convert_methods(ccx: &CrateCtxt,
tcx.sess.span_err(m.span, "duplicate method in trait impl"); tcx.sess.span_err(m.span, "duplicate method in trait impl");
} }
let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs().len();
let m_ty_generics = ty_generics_for_fn_or_method(ccx, &m.generics,
num_rcvr_ty_params);
let mty = Rc::new(ty_of_method(ccx, let mty = Rc::new(ty_of_method(ccx,
container, container,
&**m, &**m,
untransformed_rcvr_ty, untransformed_rcvr_ty,
rcvr_ast_generics, rcvr_ty_generics,
rcvr_visibility)); rcvr_visibility));
let fty = ty::mk_bare_fn(tcx, mty.fty.clone()); let fty = ty::mk_bare_fn(tcx, mty.fty.clone());
debug!("method {} (id {}) has type {}", debug!("method {} (id {}) has type {}",
@ -516,17 +347,8 @@ fn convert_methods(ccx: &CrateCtxt,
fty.repr(ccx.tcx)); fty.repr(ccx.tcx));
tcx.tcache.borrow_mut().insert( tcx.tcache.borrow_mut().insert(
local_def(m.id), local_def(m.id),
// n.b.: the type of a method is parameterized by both
// the parameters on the receiver and those on the method
// itself
ty_param_bounds_and_ty { ty_param_bounds_and_ty {
generics: ty::Generics { generics: mty.generics.clone(),
type_param_defs: Rc::new(Vec::from_slice(rcvr_ty_generics.type_param_defs())
.append(m_ty_generics.type_param_defs())),
region_param_defs: Rc::new(Vec::from_slice(rcvr_ty_generics.region_param_defs())
.append(m_ty_generics.region_param_defs())),
},
ty: fty ty: fty
}); });
@ -539,8 +361,9 @@ fn convert_methods(ccx: &CrateCtxt,
container: MethodContainer, container: MethodContainer,
m: &ast::Method, m: &ast::Method,
untransformed_rcvr_ty: ty::t, untransformed_rcvr_ty: ty::t,
rcvr_generics: &ast::Generics, rcvr_ty_generics: &ty::Generics,
rcvr_visibility: ast::Visibility) -> ty::Method rcvr_visibility: ast::Visibility)
-> ty::Method
{ {
let fty = astconv::ty_of_method(ccx, m.id, m.fn_style, let fty = astconv::ty_of_method(ccx, m.id, m.fn_style,
untransformed_rcvr_ty, untransformed_rcvr_ty,
@ -552,19 +375,17 @@ fn convert_methods(ccx: &CrateCtxt,
// foo(); }`). // foo(); }`).
let method_vis = m.vis.inherit_from(rcvr_visibility); let method_vis = m.vis.inherit_from(rcvr_visibility);
let num_rcvr_type_params = rcvr_generics.ty_params.len();
let m_ty_generics = let m_ty_generics =
ty_generics_for_fn_or_method(ccx, &m.generics, num_rcvr_type_params); ty_generics_for_fn_or_method(ccx, &m.generics,
ty::Method::new( (*rcvr_ty_generics).clone());
m.ident, ty::Method::new(m.ident,
m_ty_generics, m_ty_generics,
fty, fty,
m.explicit_self.node, m.explicit_self.node,
method_vis, method_vis,
local_def(m.id), local_def(m.id),
container, container,
None None)
)
} }
} }
@ -634,32 +455,30 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
ms.as_slice(), ms.as_slice(),
selfty, selfty,
&ty_generics, &ty_generics,
generics,
parent_visibility); parent_visibility);
for trait_ref in opt_trait_ref.iter() { for trait_ref in opt_trait_ref.iter() {
instantiate_trait_ref(ccx, trait_ref, selfty); instantiate_trait_ref(ccx, trait_ref, selfty);
} }
}, },
ast::ItemTrait(ref generics, _, _, ref trait_methods) => { ast::ItemTrait(_, _, _, 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. // Run convert_methods on the provided methods.
let (_, provided_methods) = let (_, provided_methods) =
split_trait_methods(trait_methods.as_slice()); split_trait_methods(trait_methods.as_slice());
let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id)); let untransformed_rcvr_ty = ty::mk_self_type(tcx, local_def(it.id));
convert_methods(ccx, convert_methods(ccx,
TraitContainer(local_def(it.id)), TraitContainer(local_def(it.id)),
provided_methods.as_slice(), provided_methods.as_slice(),
untransformed_rcvr_ty, untransformed_rcvr_ty,
&trait_def.generics, &trait_def.generics,
generics,
it.vis); it.vis);
// We need to do this *after* converting methods, since // We need to do this *after* converting methods, since
// convert_methods produces a tcache entry that is wrong for // convert_methods produces a tcache entry that is wrong for
// static trait methods. This is somewhat unfortunate. // static trait methods. This is somewhat unfortunate.
ensure_trait_methods(ccx, it.id); ensure_trait_methods(ccx, it.id, &*trait_def);
}, },
ast::ItemStruct(struct_def, ref generics) => { ast::ItemStruct(struct_def, ref generics) => {
ensure_no_ty_param_bounds(ccx, it.span, generics, "structure"); ensure_no_ty_param_bounds(ccx, it.span, generics, "structure");
@ -770,7 +589,7 @@ pub fn convert_struct(ccx: &CrateCtxt,
}; };
tcx.superstructs.borrow_mut().insert(local_def(id), super_struct); tcx.superstructs.borrow_mut().insert(local_def(id), super_struct);
let substs = mk_item_substs(ccx, &tpt.generics, None); let substs = mk_item_substs(ccx, &tpt.generics);
let selfty = ty::mk_struct(tcx, local_def(id), substs); let selfty = ty::mk_struct(tcx, local_def(id), substs);
// If this struct is enum-like or tuple-like, create the type of its // If this struct is enum-like or tuple-like, create the type of its
@ -873,32 +692,124 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
_ => {} _ => {}
} }
match it.node { let (generics, sized, supertraits) = match it.node {
ast::ItemTrait(ref generics, sized, ref supertraits, _) => { ast::ItemTrait(ref generics, sized, ref supertraits, _) => {
let self_ty = ty::mk_self(tcx, def_id); (generics, sized, supertraits)
let ty_generics = ty_generics_for_type(ccx, generics);
let substs = mk_item_substs(ccx, &ty_generics, Some(self_ty));
let bounds = ensure_supertraits(ccx,
it.id,
it.span,
supertraits.as_slice(),
sized);
let trait_def = Rc::new(ty::TraitDef {
generics: ty_generics,
bounds: bounds,
trait_ref: Rc::new(ty::TraitRef {
def_id: def_id,
substs: substs
})
});
tcx.trait_defs.borrow_mut().insert(def_id, trait_def.clone());
trait_def
} }
ref s => { ref s => {
tcx.sess.span_bug( tcx.sess.span_bug(
it.span, it.span,
format!("trait_def_of_item invoked on {:?}", s).as_slice()); format!("trait_def_of_item invoked on {:?}", s).as_slice());
} }
};
let substs = mk_trait_substs(ccx, it.id, generics);
let ty_generics = ty_generics_for_trait(ccx,
it.id,
&substs,
generics);
let builtin_bounds =
ensure_supertraits(ccx, it.id, it.span, supertraits, sized);
let substs = mk_item_substs(ccx, &ty_generics);
let trait_def = Rc::new(ty::TraitDef {
generics: ty_generics,
bounds: builtin_bounds,
trait_ref: Rc::new(ty::TraitRef {
def_id: def_id,
substs: substs
})
});
tcx.trait_defs.borrow_mut().insert(def_id, trait_def.clone());
return trait_def;
fn mk_trait_substs(ccx: &CrateCtxt,
trait_id: ast::NodeId,
generics: &ast::Generics)
-> subst::Substs
{
// Creates a no-op substitution for the trait's type parameters.
let regions =
generics.lifetimes
.iter()
.enumerate()
.map(|(i, def)| ty::ReEarlyBound(def.id,
subst::TypeSpace,
i, def.name))
.collect();
let types =
generics.ty_params
.iter()
.enumerate()
.map(|(i, def)| ty::mk_param(ccx.tcx, subst::TypeSpace,
i, local_def(def.id)))
.collect();
let self_ty =
ty::mk_param(ccx.tcx, subst::SelfSpace, 0, local_def(trait_id));
subst::Substs::new_trait(types, regions, self_ty)
}
fn ensure_supertraits(ccx: &CrateCtxt,
id: ast::NodeId,
sp: codemap::Span,
ast_trait_refs: &Vec<ast::TraitRef>,
sized: ast::Sized)
-> ty::BuiltinBounds
{
let tcx = ccx.tcx;
// Called only the first time trait_def_of_item is called.
// Supertraits are ensured at the same time.
assert!(!tcx.supertraits.borrow().contains_key(&local_def(id)));
let self_ty = ty::mk_self_type(ccx.tcx, local_def(id));
let mut ty_trait_refs: Vec<Rc<ty::TraitRef>> = Vec::new();
let mut bounds = ty::empty_builtin_bounds();
for ast_trait_ref in ast_trait_refs.iter() {
let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, ast_trait_ref);
// 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, self_ty);
if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) {
// FIXME(#5527) Could have same trait multiple times
if ty_trait_refs.iter().any(
|other_trait| other_trait.def_id == trait_ref.def_id)
{
// This means a trait inherited from the same
// supertrait more than once.
tcx.sess.span_err(sp, "duplicate supertrait in \
trait declaration");
break;
} else {
ty_trait_refs.push(trait_ref);
}
}
}
if sized == ast::StaticSize {
match tcx.lang_items.require(SizedTraitLangItem) {
Ok(def_id) => {
ty::try_add_builtin_trait(tcx, def_id, &mut bounds);
}
Err(s) => tcx.sess.err(s.as_slice()),
};
}
tcx.supertraits.borrow_mut().insert(local_def(id),
Rc::new(ty_trait_refs));
bounds
} }
} }
@ -919,7 +830,8 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
return tpt; return tpt;
} }
ast::ItemFn(decl, fn_style, abi, ref generics, _) => { ast::ItemFn(decl, fn_style, abi, ref generics, _) => {
let ty_generics = ty_generics_for_fn_or_method(ccx, generics, 0); let ty_generics = ty_generics_for_fn_or_method(ccx, generics,
ty::Generics::empty());
let tofd = astconv::ty_of_bare_fn(ccx, let tofd = astconv::ty_of_bare_fn(ccx,
it.id, it.id,
fn_style, fn_style,
@ -957,7 +869,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
ast::ItemEnum(_, ref generics) => { ast::ItemEnum(_, ref generics) => {
// Create a new generic polytype. // Create a new generic polytype.
let ty_generics = ty_generics_for_type(ccx, generics); let ty_generics = ty_generics_for_type(ccx, generics);
let substs = mk_item_substs(ccx, &ty_generics, None); let substs = mk_item_substs(ccx, &ty_generics);
let t = ty::mk_enum(tcx, local_def(it.id), substs); let t = ty::mk_enum(tcx, local_def(it.id), substs);
let tpt = ty_param_bounds_and_ty { let tpt = ty_param_bounds_and_ty {
generics: ty_generics, generics: ty_generics,
@ -972,7 +884,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
} }
ast::ItemStruct(_, ref generics) => { ast::ItemStruct(_, ref generics) => {
let ty_generics = ty_generics_for_type(ccx, generics); let ty_generics = ty_generics_for_type(ccx, generics);
let substs = mk_item_substs(ccx, &ty_generics, None); let substs = mk_item_substs(ccx, &ty_generics);
let t = ty::mk_struct(tcx, local_def(it.id), substs); let t = ty::mk_struct(tcx, local_def(it.id), substs);
let tpt = ty_param_bounds_and_ty { let tpt = ty_param_bounds_and_ty {
generics: ty_generics, generics: ty_generics,
@ -1001,10 +913,7 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt,
} }
ast::ForeignItemStatic(t, _) => { ast::ForeignItemStatic(t, _) => {
ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty {
generics: ty::Generics { generics: ty::Generics::empty(),
type_param_defs: Rc::new(Vec::new()),
region_param_defs: Rc::new(Vec::new()),
},
ty: ast_ty_to_ty(ccx, &ExplicitRscope, &*t) ty: ast_ty_to_ty(ccx, &ExplicitRscope, &*t)
} }
} }
@ -1013,34 +922,96 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt,
fn ty_generics_for_type(ccx: &CrateCtxt, fn ty_generics_for_type(ccx: &CrateCtxt,
generics: &ast::Generics) generics: &ast::Generics)
-> ty::Generics { -> ty::Generics
ty_generics(ccx, &generics.lifetimes, &generics.ty_params, 0) {
ty_generics(ccx, subst::TypeSpace, &generics.lifetimes,
&generics.ty_params, ty::Generics::empty())
}
fn ty_generics_for_trait(ccx: &CrateCtxt,
trait_id: ast::NodeId,
substs: &subst::Substs,
generics: &ast::Generics)
-> ty::Generics
{
let mut generics = ty_generics(ccx, subst::TypeSpace, &generics.lifetimes,
&generics.ty_params, ty::Generics::empty());
// Something of a hack: use the node id for the trait, also as
// the node id for the Self type parameter.
let param_id = trait_id;
let self_trait_ref =
Rc::new(ty::TraitRef { def_id: local_def(trait_id),
substs: (*substs).clone() });
let def = ty::TypeParameterDef {
space: subst::SelfSpace,
index: 0,
ident: special_idents::type_self,
def_id: local_def(param_id),
bounds: Rc::new(ty::ParamBounds {
builtin_bounds: ty::empty_builtin_bounds(),
trait_bounds: vec!(self_trait_ref),
}),
default: None
};
ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
generics.types.push(subst::SelfSpace, def);
generics
} }
fn ty_generics_for_fn_or_method(ccx: &CrateCtxt, fn ty_generics_for_fn_or_method(ccx: &CrateCtxt,
generics: &ast::Generics, generics: &ast::Generics,
base_index: uint) base_generics: ty::Generics)
-> ty::Generics { -> ty::Generics
{
let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
ty_generics(ccx, &early_lifetimes, &generics.ty_params, base_index) ty_generics(ccx, subst::FnSpace, &early_lifetimes,
&generics.ty_params, base_generics)
} }
fn ty_generics(ccx: &CrateCtxt, fn ty_generics(ccx: &CrateCtxt,
space: subst::ParamSpace,
lifetimes: &Vec<ast::Lifetime>, lifetimes: &Vec<ast::Lifetime>,
ty_params: &OwnedSlice<ast::TyParam>, types: &OwnedSlice<ast::TyParam>,
base_index: uint) -> ty::Generics { base_generics: ty::Generics)
return ty::Generics { -> ty::Generics
region_param_defs: Rc::new(lifetimes.iter().map(|l| { {
let mut result = base_generics;
for (i, l) in lifetimes.iter().enumerate() {
result.regions.push(space,
ty::RegionParameterDef { name: l.name, ty::RegionParameterDef { name: l.name,
def_id: local_def(l.id) } space: space,
}).collect()), index: i,
type_param_defs: Rc::new(ty_params.iter().enumerate().map(|(offset, param)| { def_id: local_def(l.id) });
let existing_def_opt = { }
let ty_param_defs = ccx.tcx.ty_param_defs.borrow();
ty_param_defs.find(&param.id).map(|def| def.clone()) for (i, param) in types.iter().enumerate() {
}; let def = get_or_create_type_parameter_def(ccx, space, param, i);
existing_def_opt.unwrap_or_else(|| { debug!("def for param: {}", def.repr(ccx.tcx));
let param_ty = ty::param_ty {idx: base_index + offset, result.types.push(space, def);
}
return result;
fn get_or_create_type_parameter_def(ccx: &CrateCtxt,
space: subst::ParamSpace,
param: &ast::TyParam,
index: uint)
-> ty::TypeParameterDef
{
match ccx.tcx.ty_param_defs.borrow().find(&param.id) {
Some(d) => { return (*d).clone(); }
None => { }
}
let param_ty = ty::ParamTy {space: space,
idx: index,
def_id: local_def(param.id)}; def_id: local_def(param.id)};
let bounds = Rc::new(compute_bounds(ccx, let bounds = Rc::new(compute_bounds(ccx,
param_ty, param_ty,
@ -1055,7 +1026,8 @@ fn ty_generics(ccx: &CrateCtxt,
ty::walk_ty(ty, |t| { ty::walk_ty(ty, |t| {
match ty::get(t).sty { match ty::get(t).sty {
ty::ty_param(p) => if p.idx > cur_idx { ty::ty_param(p) => if p.idx > cur_idx {
ccx.tcx.sess.span_err(path.span, ccx.tcx.sess.span_err(
path.span,
"type parameters with a default cannot use \ "type parameters with a default cannot use \
forward declared identifiers") forward declared identifiers")
}, },
@ -1067,21 +1039,22 @@ fn ty_generics(ccx: &CrateCtxt,
}); });
let def = ty::TypeParameterDef { let def = ty::TypeParameterDef {
space: space,
index: index,
ident: param.ident, ident: param.ident,
def_id: local_def(param.id), def_id: local_def(param.id),
bounds: bounds, bounds: bounds,
default: default default: default
}; };
debug!("def for param: {}", def.repr(ccx.tcx));
ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
def def
}) }
}).collect()),
};
fn compute_bounds( fn compute_bounds(
ccx: &CrateCtxt, ccx: &CrateCtxt,
param_ty: ty::param_ty, param_ty: ty::ParamTy,
ast_bounds: &OwnedSlice<ast::TyParamBound>, ast_bounds: &OwnedSlice<ast::TyParamBound>,
sized: ast::Sized, sized: ast::Sized,
ident: ast::Ident, ident: ast::Ident,
@ -1101,7 +1074,8 @@ fn ty_generics(ccx: &CrateCtxt,
for ast_bound in ast_bounds.iter() { for ast_bound in ast_bounds.iter() {
match *ast_bound { match *ast_bound {
TraitTyParamBound(ref b) => { TraitTyParamBound(ref b) => {
let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id); let ty = ty::mk_param(ccx.tcx, param_ty.space,
param_ty.idx, param_ty.def_id);
let trait_ref = instantiate_trait_ref(ccx, b, ty); let trait_ref = instantiate_trait_ref(ccx, b, ty);
if !ty::try_add_builtin_trait( if !ty::try_add_builtin_trait(
ccx.tcx, trait_ref.def_id, ccx.tcx, trait_ref.def_id,
@ -1117,15 +1091,15 @@ fn ty_generics(ccx: &CrateCtxt,
UnboxedFnTyParamBound(ref unboxed_function) => { UnboxedFnTyParamBound(ref unboxed_function) => {
let rscope = ExplicitRscope; let rscope = ExplicitRscope;
let mut trait_ref =
astconv::trait_ref_for_unboxed_function(
ccx,
&rscope,
unboxed_function);
let self_ty = ty::mk_param(ccx.tcx, let self_ty = ty::mk_param(ccx.tcx,
param_ty.space,
param_ty.idx, param_ty.idx,
param_ty.def_id); param_ty.def_id);
trait_ref.substs.self_ty = Some(self_ty); let trait_ref =
astconv::trait_ref_for_unboxed_function(ccx,
&rscope,
unboxed_function,
Some(self_ty));
param_bounds.trait_bounds.push(Rc::new(trait_ref)); param_bounds.trait_bounds.push(Rc::new(trait_ref));
} }
@ -1196,7 +1170,8 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
} }
let ty_generics_for_fn_or_method = let ty_generics_for_fn_or_method =
ty_generics_for_fn_or_method(ccx, ast_generics, 0); ty_generics_for_fn_or_method(ccx, ast_generics,
ty::Generics::empty());
let rb = BindingRscope::new(def_id.node); let rb = BindingRscope::new(def_id.node);
let input_tys = decl.inputs let input_tys = decl.inputs
.iter() .iter()
@ -1225,19 +1200,17 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
} }
pub fn mk_item_substs(ccx: &CrateCtxt, pub fn mk_item_substs(ccx: &CrateCtxt,
ty_generics: &ty::Generics, ty_generics: &ty::Generics)
self_ty: Option<ty::t>)
-> subst::Substs -> subst::Substs
{ {
let params: Vec<ty::t> = let types =
ty_generics.type_param_defs().iter().enumerate().map( ty_generics.types.map(
|(i, t)| ty::mk_param(ccx.tcx, i, t.def_id)).collect(); |def| ty::mk_param_from_def(ccx.tcx, def));
let regions: Vec<ty::Region> = let regions =
ty_generics.region_param_defs().iter().enumerate().map( ty_generics.regions.map(
|(i, l)| ty::ReEarlyBound(l.def_id.node, i, l.name)).collect(); |def| ty::ReEarlyBound(def.def_id.node, def.space,
def.index, def.name));
subst::Substs {regions: subst::NonerasedRegions(regions), subst::Substs::new(types, regions)
self_ty: self_ty,
tps: params}
} }

View file

@ -53,7 +53,7 @@ use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
use middle::ty::{IntType, UintType}; use middle::ty::{IntType, UintType};
use middle::ty::{BuiltinBounds}; use middle::ty::{BuiltinBounds};
use middle::ty; use middle::ty;
use middle::typeck::infer::{then, ToUres}; use middle::typeck::infer::{ToUres};
use middle::typeck::infer::glb::Glb; use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub; use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::sub::Sub; use middle::typeck::infer::sub::Sub;
@ -84,80 +84,94 @@ pub trait Combine {
fn contratys(&self, a: ty::t, b: ty::t) -> cres<ty::t>; fn contratys(&self, a: ty::t, b: ty::t) -> cres<ty::t>;
fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t>; fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t>;
fn tps(&self, as_: &[ty::t], bs: &[ty::t]) -> cres<Vec<ty::t> > { fn tps(&self,
space: subst::ParamSpace,
as_: &[ty::t],
bs: &[ty::t])
-> cres<Vec<ty::t>>
{
// FIXME(#5781) -- In general, we treat variance a bit wrong
// here. For historical reasons, we treat Self as
// contravariant and other tps as invariant. Both are wrong:
// Self may or may not be contravariant, and other tps do not
// need to be invariant.
// Note: type parameters are always treated as *invariant* if as_.len() != bs.len() {
// (otherwise the type system would be unsound). In the return Err(ty::terr_ty_param_size(expected_found(self,
// future we could allow type parameters to declare a
// variance.
if as_.len() == bs.len() {
result::fold_(as_.iter().zip(bs.iter())
.map(|(a, b)| eq_tys(self, *a, *b)))
.then(|| Ok(Vec::from_slice(as_)))
} else {
Err(ty::terr_ty_param_size(expected_found(self,
as_.len(), as_.len(),
bs.len()))) bs.len())));
}
} }
fn self_tys(&self, a: Option<ty::t>, b: Option<ty::t>) match space {
-> cres<Option<ty::t>> { subst::SelfSpace => {
result::fold(as_
.iter()
.zip(bs.iter())
.map(|(a, b)| self.contratys(*a, *b)),
Vec::new(),
|mut v, a| { v.push(a); v })
}
match (a, b) { subst::TypeSpace | subst::FnSpace => {
(None, None) => { try!(result::fold_(as_
Ok(None) .iter()
} .zip(bs.iter())
(Some(a), Some(b)) => { .map(|(a, b)| eq_tys(self, *a, *b))));
// FIXME(#5781) this should be eq_tys Ok(Vec::from_slice(as_))
// eq_tys(self, a, b).then(|| Ok(Some(a)) )
self.contratys(a, b).and_then(|t| Ok(Some(t)))
}
(None, Some(_)) |
(Some(_), None) => {
// I think it should never happen that we unify two
// substs and one of them has a self_ty and one
// doesn't...? I could be wrong about this.
self.infcx().tcx.sess.bug("substitution a had a self_ty \
and substitution b didn't, or \
vice versa");
} }
} }
} }
fn substs(&self, fn substs(&self,
item_def_id: ast::DefId, item_def_id: ast::DefId,
as_: &subst::Substs, a_subst: &subst::Substs,
bs: &subst::Substs) b_subst: &subst::Substs)
-> cres<subst::Substs> -> cres<subst::Substs>
{ {
fn relate_region_params<C:Combine>(this: &C, let variances = ty::item_variances(self.infcx().tcx, item_def_id);
item_def_id: ast::DefId, let mut substs = subst::Substs::empty();
a: &subst::RegionSubsts,
b: &subst::RegionSubsts) for &space in subst::ParamSpace::all().iter() {
-> cres<subst::RegionSubsts> { let a_tps = a_subst.types.get_vec(space);
let tcx = this.infcx().tcx; let b_tps = b_subst.types.get_vec(space);
match (a, b) { let tps = if_ok!(self.tps(space,
(&subst::ErasedRegions, _) | (_, &subst::ErasedRegions) => { a_tps.as_slice(),
Ok(subst::ErasedRegions) b_tps.as_slice()));
let a_regions = a_subst.regions().get_vec(space);
let b_regions = b_subst.regions().get_vec(space);
let r_variances = variances.regions.get_vec(space);
let regions = if_ok!(relate_region_params(self,
item_def_id,
r_variances,
a_regions,
b_regions));
*substs.types.get_mut_vec(space) = tps;
*substs.mut_regions().get_mut_vec(space) = regions;
} }
(&subst::NonerasedRegions(ref a_rs), return Ok(substs);
&subst::NonerasedRegions(ref b_rs)) => {
let variances = ty::item_variances(tcx, item_def_id); fn relate_region_params<C:Combine>(this: &C,
let region_params = &variances.region_params; item_def_id: ast::DefId,
let num_region_params = region_params.len(); variances: &Vec<ty::Variance>,
a_rs: &Vec<ty::Region>,
b_rs: &Vec<ty::Region>)
-> cres<Vec<ty::Region>>
{
let tcx = this.infcx().tcx;
let num_region_params = variances.len();
debug!("relate_region_params(\ debug!("relate_region_params(\
item_def_id={}, \ item_def_id={}, \
a_rs={}, \ a_rs={}, \
b_rs={}, b_rs={},
region_params={})", variances={})",
item_def_id.repr(tcx), item_def_id.repr(tcx),
a_rs.repr(tcx), a_rs.repr(tcx),
b_rs.repr(tcx), b_rs.repr(tcx),
region_params.repr(tcx)); variances.repr(tcx));
assert_eq!(num_region_params, a_rs.len()); assert_eq!(num_region_params, a_rs.len());
assert_eq!(num_region_params, b_rs.len()); assert_eq!(num_region_params, b_rs.len());
@ -165,7 +179,7 @@ pub trait Combine {
for i in range(0, num_region_params) { for i in range(0, num_region_params) {
let a_r = *a_rs.get(i); let a_r = *a_rs.get(i);
let b_r = *b_rs.get(i); let b_r = *b_rs.get(i);
let variance = *region_params.get(i); let variance = *variances.get(i);
let r = match variance { let r = match variance {
ty::Invariant => { ty::Invariant => {
eq_regions(this, a_r, b_r) eq_regions(this, a_r, b_r)
@ -177,21 +191,9 @@ pub trait Combine {
}; };
rs.push(if_ok!(r)); rs.push(if_ok!(r));
} }
Ok(subst::NonerasedRegions(rs)) Ok(rs)
} }
} }
}
let tps = if_ok!(self.tps(as_.tps.as_slice(), bs.tps.as_slice()));
let self_ty = if_ok!(self.self_tys(as_.self_ty, bs.self_ty));
let regions = if_ok!(relate_region_params(self,
item_def_id,
&as_.regions,
&bs.regions));
Ok(subst::Substs { regions: regions,
self_ty: self_ty,
tps: tps.clone() })
}
fn bare_fn_tys(&self, a: &ty::BareFnTy, fn bare_fn_tys(&self, a: &ty::BareFnTy,
b: &ty::BareFnTy) -> cres<ty::BareFnTy> { b: &ty::BareFnTy) -> cres<ty::BareFnTy> {

View file

@ -61,6 +61,7 @@ time of error detection.
use std::collections::HashSet; use std::collections::HashSet;
use middle::def; use middle::def;
use middle::subst;
use middle::ty; use middle::ty;
use middle::ty::{Region, ReFree}; use middle::ty::{Region, ReFree};
use middle::typeck::infer; use middle::typeck::infer;
@ -1055,9 +1056,10 @@ impl<'a> Rebuilder<'a> {
ty: _ ty: _
} = ty::lookup_item_type(self.tcx, did); } = ty::lookup_item_type(self.tcx, did);
let expected = generics.region_param_defs().len(); let expected =
let lifetimes = &path.segments.last() generics.regions.len(subst::TypeSpace);
.unwrap().lifetimes; let lifetimes =
&path.segments.last().unwrap().lifetimes;
let mut insert = Vec::new(); let mut insert = Vec::new();
if lifetimes.len() == 0 { if lifetimes.len() == 0 {
let anon = self.cur_anon.get(); let anon = self.cur_anon.get();

View file

@ -21,7 +21,8 @@ pub use middle::typeck::infer::resolve::{resolve_ivar, resolve_all};
pub use middle::typeck::infer::resolve::{resolve_nested_tvar}; pub use middle::typeck::infer::resolve::{resolve_nested_tvar};
pub use middle::typeck::infer::resolve::{resolve_rvar}; pub use middle::typeck::infer::resolve::{resolve_rvar};
use std::collections::HashMap; use middle::subst;
use middle::subst::Substs;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid}; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid};
use middle::ty; use middle::ty;
use middle::ty_fold; use middle::ty_fold;
@ -37,6 +38,7 @@ use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::unify::{ValsAndBindings, Root}; use middle::typeck::infer::unify::{ValsAndBindings, Root};
use middle::typeck::infer::error_reporting::ErrorReporting; use middle::typeck::infer::error_reporting::ErrorReporting;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use syntax::ast; use syntax::ast;
use syntax::codemap; use syntax::codemap;
@ -588,6 +590,7 @@ impl<'a> InferCtxt<'a> {
let vals = &mut ty_var_bindings.vals; let vals = &mut ty_var_bindings.vals;
vals.insert(id, Root(Bounds { lb: None, ub: None }, 0u)); vals.insert(id, Root(Bounds { lb: None, ub: None }, 0u));
} }
debug!("created type variable {}", TyVid(id));
return TyVid(id); return TyVid(id);
} }
@ -623,13 +626,35 @@ impl<'a> InferCtxt<'a> {
pub fn region_vars_for_defs(&self, pub fn region_vars_for_defs(&self,
span: Span, span: Span,
defs: &[ty::RegionParameterDef]) defs: &Vec<ty::RegionParameterDef>)
-> Vec<ty::Region> { -> Vec<ty::Region> {
defs.iter() defs.iter()
.map(|d| self.next_region_var(EarlyBoundRegion(span, d.name))) .map(|d| self.next_region_var(EarlyBoundRegion(span, d.name)))
.collect() .collect()
} }
pub fn fresh_substs_for_type(&self,
span: Span,
generics: &ty::Generics)
-> subst::Substs
{
/*!
* Given a set of generics defined on a type or impl, returns
* a substitution mapping each type/region parameter to a
* fresh inference variable.
*/
assert!(generics.types.len(subst::SelfSpace) == 0);
assert!(generics.types.len(subst::FnSpace) == 0);
assert!(generics.regions.len(subst::SelfSpace) == 0);
assert!(generics.regions.len(subst::FnSpace) == 0);
let type_parameter_count = generics.types.len(subst::TypeSpace);
let region_param_defs = generics.regions.get_vec(subst::TypeSpace);
let regions = self.region_vars_for_defs(span, region_param_defs);
let type_parameters = self.next_ty_vars(type_parameter_count);
subst::Substs::new_type(type_parameters, regions)
}
pub fn fresh_bound_region(&self, binder_id: ast::NodeId) -> ty::Region { pub fn fresh_bound_region(&self, binder_id: ast::NodeId) -> ty::Region {
self.region_vars.new_bound(binder_id) self.region_vars.new_bound(binder_id)
} }

View file

@ -66,6 +66,7 @@ use driver::config;
use middle::def; use middle::def;
use middle::resolve; use middle::resolve;
use middle::subst; use middle::subst;
use middle::subst::VecPerParamSpace;
use middle::ty; use middle::ty;
use util::common::time; use util::common::time;
use util::ppaux::Repr; use util::ppaux::Repr;
@ -73,7 +74,6 @@ use util::ppaux;
use util::nodemap::{DefIdMap, FnvHashMap}; use util::nodemap::{DefIdMap, FnvHashMap};
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::print::pprust::*; use syntax::print::pprust::*;
use syntax::{ast, ast_map, abi}; use syntax::{ast, ast_map, abi};
@ -87,9 +87,9 @@ pub mod coherence;
pub mod variance; pub mod variance;
#[deriving(Clone, Encodable, Decodable, PartialEq, PartialOrd)] #[deriving(Clone, Encodable, Decodable, PartialEq, PartialOrd)]
pub enum param_index { pub struct param_index {
param_numbered(uint), pub space: subst::ParamSpace,
param_self pub index: uint
} }
#[deriving(Clone, Encodable, Decodable)] #[deriving(Clone, Encodable, Decodable)]
@ -176,8 +176,9 @@ impl MethodCall {
pub type MethodMap = RefCell<FnvHashMap<MethodCall, MethodCallee>>; pub type MethodMap = RefCell<FnvHashMap<MethodCall, MethodCallee>>;
pub type vtable_param_res = Vec<vtable_origin>; pub type vtable_param_res = Vec<vtable_origin>;
// Resolutions for bounds of all parameters, left to right, for a given path. // Resolutions for bounds of all parameters, left to right, for a given path.
pub type vtable_res = Vec<vtable_param_res>; pub type vtable_res = VecPerParamSpace<vtable_param_res>;
#[deriving(Clone)] #[deriving(Clone)]
pub enum vtable_origin { pub enum vtable_origin {
@ -197,6 +198,14 @@ pub enum vtable_origin {
and the second is the bound number (identifying baz) and the second is the bound number (identifying baz)
*/ */
vtable_param(param_index, uint), vtable_param(param_index, uint),
/*
Asked to determine the vtable for ty_err. This is the value used
for the vtables of `Self` in a virtual call like `foo.bar()`
where `foo` is of object type. The same value is also used when
type errors occur.
*/
vtable_error,
} }
impl Repr for vtable_origin { impl Repr for vtable_origin {
@ -213,6 +222,10 @@ impl Repr for vtable_origin {
vtable_param(x, y) => { vtable_param(x, y) => {
format!("vtable_param({:?}, {:?})", x, y) format!("vtable_param({:?}, {:?})", x, y)
} }
vtable_error => {
format!("vtable_error")
}
} }
} }
} }
@ -220,33 +233,7 @@ impl Repr for vtable_origin {
pub type vtable_map = RefCell<FnvHashMap<MethodCall, vtable_res>>; pub type vtable_map = RefCell<FnvHashMap<MethodCall, vtable_res>>;
// Information about the vtable resolutions for a trait impl. pub type impl_vtable_map = RefCell<DefIdMap<vtable_res>>;
// Mostly the information is important for implementing default
// methods.
#[deriving(Clone)]
pub struct impl_res {
// resolutions for any bounded params on the trait definition
pub trait_vtables: vtable_res,
// resolutions for the trait /itself/ (and for supertraits)
pub self_vtables: vtable_param_res
}
impl Repr for impl_res {
#[cfg(stage0)]
fn repr(&self, tcx: &ty::ctxt) -> String {
format!("impl_res \\{trait_vtables={}, self_vtables={}\\}",
self.trait_vtables.repr(tcx),
self.self_vtables.repr(tcx))
}
#[cfg(not(stage0))]
fn repr(&self, tcx: &ty::ctxt) -> String {
format!("impl_res {{trait_vtables={}, self_vtables={}}}",
self.trait_vtables.repr(tcx),
self.self_vtables.repr(tcx))
}
}
pub type impl_vtable_map = RefCell<DefIdMap<impl_res>>;
pub struct CrateCtxt<'a> { pub struct CrateCtxt<'a> {
// A mapping from method call sites to traits that have that method. // A mapping from method call sites to traits that have that method.
@ -268,8 +255,7 @@ pub fn write_substs_to_tcx(tcx: &ty::ctxt,
node_id, node_id,
item_substs.repr(tcx)); item_substs.repr(tcx));
assert!(item_substs.substs.tps.iter(). assert!(item_substs.substs.types.all(|t| !ty::type_needs_infer(*t)));
all(|t| !ty::type_needs_infer(*t)));
tcx.item_substs.borrow_mut().insert(node_id, item_substs); tcx.item_substs.borrow_mut().insert(node_id, item_substs);
} }
@ -290,8 +276,8 @@ pub fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId)
pub fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty { pub fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty {
generics: ty::Generics {type_param_defs: Rc::new(Vec::new()), generics: ty::Generics {types: VecPerParamSpace::empty(),
region_param_defs: Rc::new(Vec::new())}, regions: VecPerParamSpace::empty()},
ty: t ty: t
} }
} }

View file

@ -195,14 +195,15 @@ represents the "variance transform" as defined in the paper:
use std::collections::HashMap; use std::collections::HashMap;
use arena; use arena;
use arena::Arena; use arena::Arena;
use rl = middle::resolve_lifetime;
use middle::subst; use middle::subst;
use middle::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace};
use middle::ty; use middle::ty;
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use syntax::ast; use syntax::ast;
use syntax::ast_map; use syntax::ast_map;
use syntax::ast_util; use syntax::ast_util;
use syntax::owned_slice::OwnedSlice;
use syntax::visit; use syntax::visit;
use syntax::visit::Visitor; use syntax::visit::Visitor;
use util::ppaux::Repr; use util::ppaux::Repr;
@ -266,11 +267,17 @@ struct TermsContext<'a> {
inferred_infos: Vec<InferredInfo<'a>> , inferred_infos: Vec<InferredInfo<'a>> ,
} }
enum ParamKind { TypeParam, RegionParam, SelfParam } #[deriving(Show)]
enum ParamKind {
TypeParam,
RegionParam
}
struct InferredInfo<'a> { struct InferredInfo<'a> {
item_id: ast::NodeId, item_id: ast::NodeId,
kind: ParamKind, kind: ParamKind,
space: ParamSpace,
index: uint,
param_id: ast::NodeId, param_id: ast::NodeId,
term: VarianceTermPtr<'a>, term: VarianceTermPtr<'a>,
} }
@ -288,9 +295,8 @@ fn determine_parameters_to_be_inferred<'a>(tcx: &'a ty::ctxt,
// cache and share the variance struct used for items with // cache and share the variance struct used for items with
// no type/region parameters // no type/region parameters
empty_variances: Rc::new(ty::ItemVariances { empty_variances: Rc::new(ty::ItemVariances {
self_param: None, types: VecPerParamSpace::empty(),
type_params: OwnedSlice::empty(), regions: VecPerParamSpace::empty()
region_params: OwnedSlice::empty()
}) })
}; };
@ -303,12 +309,15 @@ impl<'a> TermsContext<'a> {
fn add_inferred(&mut self, fn add_inferred(&mut self,
item_id: ast::NodeId, item_id: ast::NodeId,
kind: ParamKind, kind: ParamKind,
space: ParamSpace,
index: uint, index: uint,
param_id: ast::NodeId) { param_id: ast::NodeId) {
let inf_index = InferredIndex(self.inferred_infos.len()); let inf_index = InferredIndex(self.inferred_infos.len());
let term = self.arena.alloc(|| InferredTerm(inf_index)); let term = self.arena.alloc(|| InferredTerm(inf_index));
self.inferred_infos.push(InferredInfo { item_id: item_id, self.inferred_infos.push(InferredInfo { item_id: item_id,
kind: kind, kind: kind,
space: space,
index: index,
param_id: param_id, param_id: param_id,
term: term }); term: term });
let newly_added = self.inferred_map.insert(param_id, inf_index); let newly_added = self.inferred_map.insert(param_id, inf_index);
@ -338,7 +347,7 @@ impl<'a> Visitor<()> for TermsContext<'a> {
// item are assigned continuous indices. // item are assigned continuous indices.
match item.node { match item.node {
ast::ItemTrait(..) => { ast::ItemTrait(..) => {
self.add_inferred(item.id, SelfParam, 0, item.id); self.add_inferred(item.id, TypeParam, SelfSpace, 0, item.id);
} }
_ => { } _ => { }
} }
@ -348,10 +357,10 @@ impl<'a> Visitor<()> for TermsContext<'a> {
ast::ItemStruct(_, ref generics) | ast::ItemStruct(_, ref generics) |
ast::ItemTrait(ref generics, _, _, _) => { ast::ItemTrait(ref generics, _, _, _) => {
for (i, p) in generics.lifetimes.iter().enumerate() { for (i, p) in generics.lifetimes.iter().enumerate() {
self.add_inferred(item.id, RegionParam, i, p.id); self.add_inferred(item.id, RegionParam, TypeSpace, i, p.id);
} }
for (i, p) in generics.ty_params.iter().enumerate() { for (i, p) in generics.ty_params.iter().enumerate() {
self.add_inferred(item.id, TypeParam, i, p.id); self.add_inferred(item.id, TypeParam, TypeSpace, i, p.id);
} }
// If this item has no type or lifetime parameters, // If this item has no type or lifetime parameters,
@ -399,9 +408,9 @@ struct ConstraintContext<'a> {
// are indexed by the `ParamKind` (type, lifetime, self). Note // are indexed by the `ParamKind` (type, lifetime, self). Note
// that there are no marker types for self, so the entries for // that there are no marker types for self, so the entries for
// self are always None. // self are always None.
invariant_lang_items: [Option<ast::DefId>, ..3], invariant_lang_items: [Option<ast::DefId>, ..2],
covariant_lang_items: [Option<ast::DefId>, ..3], covariant_lang_items: [Option<ast::DefId>, ..2],
contravariant_lang_items: [Option<ast::DefId>, ..3], contravariant_lang_items: [Option<ast::DefId>, ..2],
// These are pointers to common `ConstantTerm` instances // These are pointers to common `ConstantTerm` instances
covariant: VarianceTermPtr<'a>, covariant: VarianceTermPtr<'a>,
@ -422,9 +431,9 @@ struct Constraint<'a> {
fn add_constraints_from_crate<'a>(terms_cx: TermsContext<'a>, fn add_constraints_from_crate<'a>(terms_cx: TermsContext<'a>,
krate: &ast::Crate) krate: &ast::Crate)
-> ConstraintContext<'a> { -> ConstraintContext<'a> {
let mut invariant_lang_items = [None, ..3]; let mut invariant_lang_items = [None, ..2];
let mut covariant_lang_items = [None, ..3]; let mut covariant_lang_items = [None, ..2];
let mut contravariant_lang_items = [None, ..3]; let mut contravariant_lang_items = [None, ..2];
covariant_lang_items[TypeParam as uint] = covariant_lang_items[TypeParam as uint] =
terms_cx.tcx.lang_items.covariant_type(); terms_cx.tcx.lang_items.covariant_type();
@ -547,7 +556,7 @@ impl<'a> ConstraintContext<'a> {
let tcx = self.terms_cx.tcx; let tcx = self.terms_cx.tcx;
assert!(is_lifetime(&tcx.map, param_id)); assert!(is_lifetime(&tcx.map, param_id));
match tcx.named_region_map.find(&param_id) { match tcx.named_region_map.find(&param_id) {
Some(&ast::DefEarlyBoundRegion(_, lifetime_decl_id)) Some(&rl::DefEarlyBoundRegion(_, _, lifetime_decl_id))
=> lifetime_decl_id, => lifetime_decl_id,
Some(_) => fail!("should not encounter non early-bound cases"), Some(_) => fail!("should not encounter non early-bound cases"),
@ -611,6 +620,7 @@ impl<'a> ConstraintContext<'a> {
param_def_id: ast::DefId, param_def_id: ast::DefId,
item_def_id: ast::DefId, item_def_id: ast::DefId,
kind: ParamKind, kind: ParamKind,
space: ParamSpace,
index: uint) index: uint)
-> VarianceTermPtr<'a> { -> VarianceTermPtr<'a> {
/*! /*!
@ -637,9 +647,8 @@ impl<'a> ConstraintContext<'a> {
// variance already inferred, just look it up. // variance already inferred, just look it up.
let variances = ty::item_variances(self.tcx(), item_def_id); let variances = ty::item_variances(self.tcx(), item_def_id);
let variance = match kind { let variance = match kind {
SelfParam => variances.self_param.unwrap(), TypeParam => *variances.types.get(space, index),
TypeParam => *variances.type_params.get(index), RegionParam => *variances.regions.get(space, index),
RegionParam => *variances.region_params.get(index),
}; };
self.constant_term(variance) self.constant_term(variance)
} }
@ -736,17 +745,50 @@ impl<'a> ConstraintContext<'a> {
ty::ty_enum(def_id, ref substs) | ty::ty_enum(def_id, ref substs) |
ty::ty_struct(def_id, ref substs) => { ty::ty_struct(def_id, ref substs) => {
let item_type = ty::lookup_item_type(self.tcx(), def_id); let item_type = ty::lookup_item_type(self.tcx(), def_id);
self.add_constraints_from_substs(def_id, &item_type.generics, let generics = &item_type.generics;
substs, variance);
// All type parameters on enums and structs should be
// in the TypeSpace.
assert!(generics.types.get_vec(subst::SelfSpace).is_empty());
assert!(generics.types.get_vec(subst::FnSpace).is_empty());
assert!(generics.regions.get_vec(subst::SelfSpace).is_empty());
assert!(generics.regions.get_vec(subst::FnSpace).is_empty());
self.add_constraints_from_substs(
def_id,
generics.types.get_vec(subst::TypeSpace),
generics.regions.get_vec(subst::TypeSpace),
substs,
variance);
} }
ty::ty_trait(box ty::TyTrait { def_id, ref substs, .. }) => { ty::ty_trait(box ty::TyTrait { def_id, ref substs, .. }) => {
let trait_def = ty::lookup_trait_def(self.tcx(), def_id); let trait_def = ty::lookup_trait_def(self.tcx(), def_id);
self.add_constraints_from_substs(def_id, &trait_def.generics, let generics = &trait_def.generics;
substs, variance);
// Traits DO have a Self type parameter, but it is
// erased from object types.
assert!(!generics.types.get_vec(subst::SelfSpace).is_empty() &&
substs.types.get_vec(subst::SelfSpace).is_empty());
// Traits never declare region parameters in the self
// space.
assert!(generics.regions.get_vec(subst::SelfSpace).is_empty());
// Traits never declare type/region parameters in the
// fn space.
assert!(generics.types.get_vec(subst::FnSpace).is_empty());
assert!(generics.regions.get_vec(subst::FnSpace).is_empty());
self.add_constraints_from_substs(
def_id,
generics.types.get_vec(subst::TypeSpace),
generics.regions.get_vec(subst::TypeSpace),
substs,
variance);
} }
ty::ty_param(ty::param_ty { def_id: ref def_id, .. }) => { ty::ty_param(ty::ParamTy { def_id: ref def_id, .. }) => {
assert_eq!(def_id.krate, ast::LOCAL_CRATE); assert_eq!(def_id.krate, ast::LOCAL_CRATE);
match self.terms_cx.inferred_map.find(&def_id.node) { match self.terms_cx.inferred_map.find(&def_id.node) {
Some(&index) => { Some(&index) => {
@ -760,12 +802,6 @@ impl<'a> ConstraintContext<'a> {
} }
} }
ty::ty_self(ref def_id) => {
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
let index = self.inferred_index(def_id.node);
self.add_constraint(index, variance);
}
ty::ty_bare_fn(ty::BareFnTy { ref sig, .. }) | ty::ty_bare_fn(ty::BareFnTy { ref sig, .. }) |
ty::ty_closure(box ty::ClosureTy { ty::ty_closure(box ty::ClosureTy {
ref sig, ref sig,
@ -796,28 +832,28 @@ impl<'a> ConstraintContext<'a> {
/// object, etc) appearing in a context with ambient variance `variance` /// object, etc) appearing in a context with ambient variance `variance`
fn add_constraints_from_substs(&mut self, fn add_constraints_from_substs(&mut self,
def_id: ast::DefId, def_id: ast::DefId,
generics: &ty::Generics, type_param_defs: &Vec<ty::TypeParameterDef>,
region_param_defs: &Vec<ty::RegionParameterDef>,
substs: &subst::Substs, substs: &subst::Substs,
variance: VarianceTermPtr<'a>) { variance: VarianceTermPtr<'a>) {
debug!("add_constraints_from_substs(def_id={:?})", def_id); debug!("add_constraints_from_substs(def_id={:?})", def_id);
for (i, p) in generics.type_param_defs().iter().enumerate() { for p in type_param_defs.iter() {
let variance_decl = let variance_decl =
self.declared_variance(p.def_id, def_id, TypeParam, i); self.declared_variance(p.def_id, def_id, TypeParam,
p.space, p.index);
let variance_i = self.xform(variance, variance_decl); let variance_i = self.xform(variance, variance_decl);
self.add_constraints_from_ty(*substs.tps.get(i), variance_i); let substs_ty = *substs.types.get(p.space, p.index);
self.add_constraints_from_ty(substs_ty, variance_i);
} }
match substs.regions { for p in region_param_defs.iter() {
subst::ErasedRegions => {}
subst::NonerasedRegions(ref rps) => {
for (i, p) in generics.region_param_defs().iter().enumerate() {
let variance_decl = let variance_decl =
self.declared_variance(p.def_id, def_id, RegionParam, i); self.declared_variance(p.def_id, def_id,
RegionParam, p.space, p.index);
let variance_i = self.xform(variance, variance_decl); let variance_i = self.xform(variance, variance_decl);
self.add_constraints_from_region(*rps.get(i), variance_i); let substs_r = *substs.regions().get(p.space, p.index);
} self.add_constraints_from_region(substs_r, variance_i);
}
} }
} }
@ -839,7 +875,7 @@ impl<'a> ConstraintContext<'a> {
region: ty::Region, region: ty::Region,
variance: VarianceTermPtr<'a>) { variance: VarianceTermPtr<'a>) {
match region { match region {
ty::ReEarlyBound(param_id, _, _) => { ty::ReEarlyBound(param_id, _, _, _) => {
if self.is_to_be_inferred(param_id) { if self.is_to_be_inferred(param_id) {
let index = self.inferred_index(param_id); let index = self.inferred_index(param_id);
self.add_constraint(index, variance); self.add_constraint(index, variance);
@ -931,7 +967,7 @@ impl<'a> SolveContext<'a> {
let new_value = glb(variance, old_value); let new_value = glb(variance, old_value);
if old_value != new_value { if old_value != new_value {
debug!("Updating inferred {} (node {}) \ debug!("Updating inferred {} (node {}) \
from {:?} to {:?} due to {}", from {} to {} due to {}",
inferred, inferred,
self.terms_cx self.terms_cx
.inferred_infos .inferred_infos
@ -965,32 +1001,29 @@ impl<'a> SolveContext<'a> {
let num_inferred = self.terms_cx.num_inferred(); let num_inferred = self.terms_cx.num_inferred();
while index < num_inferred { while index < num_inferred {
let item_id = inferred_infos.get(index).item_id; let item_id = inferred_infos.get(index).item_id;
let mut self_param = None; let mut types = VecPerParamSpace::empty();
let mut type_params = vec!(); let mut regions = VecPerParamSpace::empty();
let mut region_params = vec!();
while index < num_inferred && while index < num_inferred &&
inferred_infos.get(index).item_id == item_id { inferred_infos.get(index).item_id == item_id {
let info = inferred_infos.get(index); let info = inferred_infos.get(index);
let variance = *solutions.get(index);
debug!("Index {} Info {} / {} / {} Variance {}",
index, info.index, info.kind, info.space, variance);
match info.kind { match info.kind {
SelfParam => {
assert!(self_param.is_none());
self_param = Some(*solutions.get(index));
}
TypeParam => { TypeParam => {
type_params.push(*solutions.get(index)); types.push(info.space, variance);
} }
RegionParam => { RegionParam => {
region_params.push(*solutions.get(index)); regions.push(info.space, variance);
} }
} }
index += 1; index += 1;
} }
let item_variances = ty::ItemVariances { let item_variances = ty::ItemVariances {
self_param: self_param, types: types,
type_params: OwnedSlice::from_vec(type_params), regions: regions
region_params: OwnedSlice::from_vec(region_params)
}; };
debug!("item_id={} item_variances={}", debug!("item_id={} item_variances={}",
item_id, item_id,

View file

@ -9,17 +9,18 @@
// except according to those terms. // except according to those terms.
use middle::def;
use middle::subst; use middle::subst;
use middle::subst::Subst; use middle::subst::{VecPerParamSpace,Subst};
use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{ReSkolemized, ReVar};
use middle::ty::{BoundRegion, BrAnon, BrNamed}; use middle::ty::{BoundRegion, BrAnon, BrNamed};
use middle::ty::{BrFresh, ctxt}; use middle::ty::{BrFresh, ctxt};
use middle::ty::{mt, t, param_ty}; use middle::ty::{mt, t, ParamTy};
use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region,
ReEmpty}; ReEmpty};
use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure}; use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_self, ty_tup}; use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup};
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
use middle::ty; use middle::ty;
use middle::typeck; use middle::typeck;
@ -188,7 +189,7 @@ pub fn region_to_str(cx: &ctxt, prefix: &str, space: bool, region: Region) -> St
// `explain_region()` or `note_and_explain_region()`. // `explain_region()` or `note_and_explain_region()`.
match region { match region {
ty::ReScope(_) => prefix.to_string(), ty::ReScope(_) => prefix.to_string(),
ty::ReEarlyBound(_, _, name) => { ty::ReEarlyBound(_, _, _, name) => {
token::get_name(name).get().to_string() token::get_name(name).get().to_string()
} }
ty::ReLateBound(_, br) => bound_region_to_str(cx, prefix, space, br), ty::ReLateBound(_, br) => bound_region_to_str(cx, prefix, space, br),
@ -375,7 +376,7 @@ pub fn ty_to_str(cx: &ctxt, typ: t) -> String {
} }
ty_infer(infer_ty) => infer_ty.to_str(), ty_infer(infer_ty) => infer_ty.to_str(),
ty_err => "[type error]".to_string(), ty_err => "[type error]".to_string(),
ty_param(param_ty {idx: id, def_id: did}) => { ty_param(ParamTy {idx: id, def_id: did, ..}) => {
let ident = match cx.ty_param_defs.borrow().find(&did.node) { let ident = match cx.ty_param_defs.borrow().find(&did.node) {
Some(def) => token::get_ident(def.ident).get().to_string(), Some(def) => token::get_ident(def.ident).get().to_string(),
// This can only happen when a type mismatch error happens and // This can only happen when a type mismatch error happens and
@ -391,22 +392,18 @@ pub fn ty_to_str(cx: &ctxt, typ: t) -> String {
format!("{}:{:?}", ident, did) format!("{}:{:?}", ident, did)
} }
} }
ty_self(..) => "Self".to_string(),
ty_enum(did, ref substs) | ty_struct(did, ref substs) => { ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
let base = ty::item_path_str(cx, did); let base = ty::item_path_str(cx, did);
parameterized(cx, let generics = ty::lookup_item_type(cx, did).generics;
base.as_slice(), parameterized(cx, base.as_slice(), substs, &generics)
&substs.regions,
substs.tps.as_slice(),
did,
false)
} }
ty_trait(box ty::TyTrait { ty_trait(box ty::TyTrait {
def_id: did, ref substs, store, ref bounds def_id: did, ref substs, store, ref bounds
}) => { }) => {
let base = ty::item_path_str(cx, did); let base = ty::item_path_str(cx, did);
let ty = parameterized(cx, base.as_slice(), &substs.regions, let trait_def = ty::lookup_trait_def(cx, did);
substs.tps.as_slice(), did, true); let ty = parameterized(cx, base.as_slice(),
substs, &trait_def.generics);
let bound_sep = if bounds.is_empty() { "" } else { ":" }; let bound_sep = if bounds.is_empty() { "" } else { ":" };
let bound_str = bounds.repr(cx); let bound_str = bounds.repr(cx);
format!("{}{}{}{}", format!("{}{}{}{}",
@ -429,39 +426,38 @@ pub fn ty_to_str(cx: &ctxt, typ: t) -> String {
pub fn parameterized(cx: &ctxt, pub fn parameterized(cx: &ctxt,
base: &str, base: &str,
regions: &subst::RegionSubsts, substs: &subst::Substs,
tps: &[ty::t], generics: &ty::Generics)
did: ast::DefId, -> String
is_trait: bool) {
-> String {
let mut strs = Vec::new(); let mut strs = Vec::new();
match *regions {
match substs.regions {
subst::ErasedRegions => { } subst::ErasedRegions => { }
subst::NonerasedRegions(ref regions) => { subst::NonerasedRegions(ref regions) => {
for &r in regions.iter() { for &r in regions.iter() {
strs.push(region_to_str(cx, "", false, r)) let s = region_to_str(cx, "", false, r);
if !s.is_empty() {
strs.push(s)
} else {
// This happens when the value of the region
// parameter is not easily serialized. This may be
// because the user omitted it in the first place,
// or because it refers to some block in the code,
// etc. I'm not sure how best to serialize this.
strs.push(format!("'_"));
}
} }
} }
} }
let generics = if is_trait { let tps = substs.types.get_vec(subst::TypeSpace);
ty::lookup_trait_def(cx, did).generics.clone() let ty_params = generics.types.get_vec(subst::TypeSpace);
} else {
ty::lookup_item_type(cx, did).generics
};
let ty_params = generics.type_param_defs();
let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some()); let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some());
let num_defaults = if has_defaults { let num_defaults = if has_defaults && !cx.sess.verbose() {
// We should have a borrowed version of substs instead of cloning.
let mut substs = subst::Substs {
tps: Vec::from_slice(tps),
regions: regions.clone(),
self_ty: None
};
ty_params.iter().zip(tps.iter()).rev().take_while(|&(def, &actual)| { ty_params.iter().zip(tps.iter()).rev().take_while(|&(def, &actual)| {
substs.tps.pop();
match def.default { match def.default {
Some(default) => default.subst(cx, &substs) == actual, Some(default) => default.subst(cx, substs) == actual,
None => false None => false
} }
}).count() }).count()
@ -473,6 +469,12 @@ pub fn parameterized(cx: &ctxt,
strs.push(ty_to_str(cx, *t)) strs.push(ty_to_str(cx, *t))
} }
if cx.sess.verbose() {
for t in substs.types.get_vec(subst::SelfSpace).iter() {
strs.push(format!("for {}", t.repr(cx)));
}
}
if strs.len() > 0u { if strs.len() > 0u {
format!("{}<{}>", base, strs.connect(",")) format!("{}<{}>", base, strs.connect(","))
} else { } else {
@ -554,6 +556,12 @@ impl<T:Repr> Repr for Vec<T> {
} }
} }
impl Repr for def::Def {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{:?}", *self)
}
}
impl Repr for ty::TypeParameterDef { impl Repr for ty::TypeParameterDef {
fn repr(&self, tcx: &ctxt) -> String { fn repr(&self, tcx: &ctxt) -> String {
format!("TypeParameterDef({:?}, {})", self.def_id, format!("TypeParameterDef({:?}, {})", self.def_id,
@ -577,10 +585,18 @@ impl Repr for ty::t {
impl Repr for subst::Substs { impl Repr for subst::Substs {
fn repr(&self, tcx: &ctxt) -> String { fn repr(&self, tcx: &ctxt) -> String {
format!("substs(regions={}, self_ty={}, tps={})", format!("Substs[types={}, regions={}]",
self.regions.repr(tcx), self.types.repr(tcx),
self.self_ty.repr(tcx), self.regions.repr(tcx))
self.tps.repr(tcx)) }
}
impl<T:Repr> Repr for subst::VecPerParamSpace<T> {
fn repr(&self, tcx: &ctxt) -> String {
format!("[{};{};{}]",
self.get_vec(subst::TypeSpace).repr(tcx),
self.get_vec(subst::SelfSpace).repr(tcx),
self.get_vec(subst::FnSpace).repr(tcx))
} }
} }
@ -630,6 +646,12 @@ impl Repr for ast::Expr {
} }
} }
impl Repr for ast::Path {
fn repr(&self, _tcx: &ctxt) -> String {
format!("path({})", pprust::path_to_str(self))
}
}
impl Repr for ast::Item { impl Repr for ast::Item {
fn repr(&self, tcx: &ctxt) -> String { fn repr(&self, tcx: &ctxt) -> String {
format!("item({})", tcx.map.node_to_str(self.id)) format!("item({})", tcx.map.node_to_str(self.id))
@ -665,9 +687,10 @@ impl Repr for ty::BoundRegion {
impl Repr for ty::Region { impl Repr for ty::Region {
fn repr(&self, tcx: &ctxt) -> String { fn repr(&self, tcx: &ctxt) -> String {
match *self { match *self {
ty::ReEarlyBound(id, index, name) => { ty::ReEarlyBound(id, space, index, name) => {
format!("ReEarlyBound({}, {}, {})", format!("ReEarlyBound({}, {}, {}, {})",
id, id,
space,
index, index,
token::get_name(name)) token::get_name(name))
} }
@ -697,9 +720,7 @@ impl Repr for ty::Region {
} }
ty::ReInfer(ReSkolemized(id, ref bound_region)) => { ty::ReInfer(ReSkolemized(id, ref bound_region)) => {
format!("re_skolemized({}, {})", format!("re_skolemized({}, {})", id, bound_region.repr(tcx))
id,
bound_region.repr(tcx))
} }
ty::ReEmpty => { ty::ReEmpty => {
@ -753,18 +774,18 @@ impl Repr for ty::ty_param_bounds_and_ty {
impl Repr for ty::Generics { impl Repr for ty::Generics {
fn repr(&self, tcx: &ctxt) -> String { fn repr(&self, tcx: &ctxt) -> String {
format!("Generics(type_param_defs: {}, region_param_defs: {})", format!("Generics(types: {}, regions: {})",
self.type_param_defs().repr(tcx), self.types.repr(tcx),
self.region_param_defs().repr(tcx)) self.regions.repr(tcx))
} }
} }
impl Repr for ty::ItemVariances { impl Repr for ty::ItemVariances {
fn repr(&self, tcx: &ctxt) -> String { fn repr(&self, tcx: &ctxt) -> String {
format!("IterVariances(self_param={}, type_params={}, region_params={})", format!("ItemVariances(types={}, \
self.self_param.repr(tcx), regions={})",
self.type_params.repr(tcx), self.types.repr(tcx),
self.region_params.repr(tcx)) self.regions.repr(tcx))
} }
} }
@ -952,23 +973,8 @@ impl UserString for ty::BuiltinBounds {
impl UserString for ty::TraitRef { impl UserString for ty::TraitRef {
fn user_string(&self, tcx: &ctxt) -> String { fn user_string(&self, tcx: &ctxt) -> String {
let base = ty::item_path_str(tcx, self.def_id); let base = ty::item_path_str(tcx, self.def_id);
if tcx.sess.verbose() && self.substs.self_ty.is_some() { let trait_def = ty::lookup_trait_def(tcx, self.def_id);
let mut all_tps = self.substs.tps.clone(); parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics)
for &t in self.substs.self_ty.iter() { all_tps.push(t); }
parameterized(tcx,
base.as_slice(),
&self.substs.regions,
all_tps.as_slice(),
self.def_id,
true)
} else {
parameterized(tcx,
base.as_slice(),
&self.substs.regions,
self.substs.tps.as_slice(),
self.def_id,
true)
}
} }
} }

View file

@ -27,6 +27,7 @@ use rustc::metadata::csearch;
use rustc::metadata::decoder; use rustc::metadata::decoder;
use rustc::middle::def; use rustc::middle::def;
use rustc::middle::subst; use rustc::middle::subst;
use rustc::middle::subst::VecPerParamSpace;
use rustc::middle::ty; use rustc::middle::ty;
use std::rc::Rc; use std::rc::Rc;
@ -53,6 +54,12 @@ impl<T: Clean<U>, U> Clean<Vec<U>> for Vec<T> {
} }
} }
impl<T: Clean<U>, U> Clean<VecPerParamSpace<U>> for VecPerParamSpace<T> {
fn clean(&self) -> VecPerParamSpace<U> {
self.map(|x| x.clean())
}
}
impl<T: Clean<U>, U> Clean<U> for Gc<T> { impl<T: Clean<U>, U> Clean<U> for Gc<T> {
fn clean(&self) -> U { fn clean(&self) -> U {
(**self).clean() (**self).clean()
@ -488,17 +495,17 @@ impl Clean<TyParamBound> for ast::TyParamBound {
} }
fn external_path(name: &str, substs: &subst::Substs) -> Path { fn external_path(name: &str, substs: &subst::Substs) -> Path {
let lifetimes = substs.regions().get_vec(subst::TypeSpace)
.iter()
.filter_map(|v| v.clean())
.collect();
let types = substs.types.get_vec(subst::TypeSpace).clean();
Path { Path {
global: false, global: false,
segments: vec![PathSegment { segments: vec![PathSegment {
name: name.to_string(), name: name.to_string(),
lifetimes: match substs.regions { lifetimes: lifetimes,
subst::ErasedRegions => Vec::new(), types: types,
subst::NonerasedRegions(ref v) => {
v.iter().filter_map(|v| v.clean()).collect()
}
},
types: substs.tps.clean(),
}], }],
} }
} }
@ -578,12 +585,8 @@ impl Clean<Vec<TyParamBound>> for ty::ParamBounds {
impl Clean<Option<Vec<TyParamBound>>> for subst::Substs { impl Clean<Option<Vec<TyParamBound>>> for subst::Substs {
fn clean(&self) -> Option<Vec<TyParamBound>> { fn clean(&self) -> Option<Vec<TyParamBound>> {
let mut v = Vec::new(); let mut v = Vec::new();
match self.regions { v.extend(self.regions().iter().map(|_| RegionBound));
subst::NonerasedRegions(..) => v.push(RegionBound), v.extend(self.types.iter().map(|t| TraitBound(t.clean())));
subst::ErasedRegions => {}
}
v.extend(self.tps.iter().map(|t| TraitBound(t.clean())));
if v.len() > 0 {Some(v)} else {None} if v.len() > 0 {Some(v)} else {None}
} }
} }
@ -617,7 +620,7 @@ impl Clean<Option<Lifetime>> for ty::Region {
ty::ReStatic => Some(Lifetime("static".to_string())), ty::ReStatic => Some(Lifetime("static".to_string())),
ty::ReLateBound(_, ty::BrNamed(_, name)) => ty::ReLateBound(_, ty::BrNamed(_, name)) =>
Some(Lifetime(token::get_name(name).get().to_string())), Some(Lifetime(token::get_name(name).get().to_string())),
ty::ReEarlyBound(_, _, name) => Some(Lifetime(name.clean())), ty::ReEarlyBound(_, _, _, name) => Some(Lifetime(name.clean())),
ty::ReLateBound(..) | ty::ReLateBound(..) |
ty::ReFree(..) | ty::ReFree(..) |
@ -638,17 +641,41 @@ pub struct Generics {
impl Clean<Generics> for ast::Generics { impl Clean<Generics> for ast::Generics {
fn clean(&self) -> Generics { fn clean(&self) -> Generics {
Generics { Generics {
lifetimes: self.lifetimes.clean().move_iter().collect(), lifetimes: self.lifetimes.clean(),
type_params: self.ty_params.clean().move_iter().collect(), type_params: self.ty_params.clean(),
} }
} }
} }
impl Clean<Generics> for ty::Generics { impl Clean<Generics> for ty::Generics {
fn clean(&self) -> Generics { fn clean(&self) -> Generics {
// In the type space, generics can come in one of multiple
// namespaces. This means that e.g. for fn items the type
// parameters will live in FnSpace, but for types the
// parameters will live in TypeSpace (trait definitions also
// define a parameter in SelfSpace). *Method* definitions are
// the one exception: they combine the TypeSpace parameters
// from the enclosing impl/trait with their own FnSpace
// parameters.
//
// In general, when we clean, we are trying to produce the
// "user-facing" generics. Hence we select the most specific
// namespace that is occupied, ignoring SelfSpace because it
// is implicit.
let space = {
if !self.types.get_vec(subst::FnSpace).is_empty() ||
!self.regions.get_vec(subst::FnSpace).is_empty()
{
subst::FnSpace
} else {
subst::TypeSpace
}
};
Generics { Generics {
lifetimes: self.region_param_defs.clean(), type_params: self.types.get_vec(space).clean(),
type_params: self.type_param_defs.clean(), lifetimes: self.regions.get_vec(space).clean(),
} }
} }
} }
@ -1259,8 +1286,13 @@ impl Clean<Type> for ty::t {
} }
ty::ty_tup(ref t) => Tuple(t.iter().map(|t| t.clean()).collect()), ty::ty_tup(ref t) => Tuple(t.iter().map(|t| t.clean()).collect()),
ty::ty_param(ref p) => Generic(p.def_id), ty::ty_param(ref p) => {
ty::ty_self(did) => Self(did), if p.space == subst::SelfSpace {
Self(p.def_id)
} else {
Generic(p.def_id)
}
}
ty::ty_infer(..) => fail!("ty_infer"), ty::ty_infer(..) => fail!("ty_infer"),
ty::ty_err => fail!("ty_err"), ty::ty_err => fail!("ty_err"),
@ -1968,7 +2000,7 @@ fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound>>,
ast::TyFloat(ast::TyF64) => return Primitive(F64), ast::TyFloat(ast::TyF64) => return Primitive(F64),
ast::TyFloat(ast::TyF128) => return Primitive(F128), ast::TyFloat(ast::TyF128) => return Primitive(F128),
}, },
def::DefTyParam(i, _) => return Generic(i), def::DefTyParam(_, i, _) => return Generic(i),
def::DefTyParamBinder(i) => return TyParamBinder(i), def::DefTyParamBinder(i) => return TyParamBinder(i),
_ => {} _ => {}
}; };

View file

@ -208,14 +208,6 @@ impl Generics {
} }
} }
#[deriving(Clone, PartialEq, Eq, Hash, Encodable, Decodable, Show)]
pub enum DefRegion {
DefStaticRegion,
DefEarlyBoundRegion(/* index */ uint, /* lifetime decl */ NodeId),
DefLateBoundRegion(/* binder_id */ NodeId, /* depth */ uint, /* lifetime decl */ NodeId),
DefFreeRegion(/* block scope */ NodeId, /* lifetime decl */ NodeId),
}
// The set of MetaItems that define the compilation environment of the crate, // The set of MetaItems that define the compilation environment of the crate,
// used to drive conditional compilation // used to drive conditional compilation
pub type CrateConfig = Vec<Gc<MetaItem>>; pub type CrateConfig = Vec<Gc<MetaItem>>;

View file

@ -45,11 +45,16 @@ impl Trait<int> for S2 {
fn foo<'a>() { fn foo<'a>() {
let _ = S::new::<int,f64>(1, 1.0); let _ = S::new::<int,f64>(1, 1.0);
//~^ ERROR the impl referenced by this path needs 1 type parameter, but 0 type parameters were supplied //~^ ERROR too many type parameters provided
let _ = S::<'a,int>::new::<f64>(1, 1.0); //~ ERROR expected 0 lifetime parameters
let _ = S::<'a,int>::new::<f64>(1, 1.0);
//~^ ERROR too many lifetime parameters provided
let _: S2 = Trait::new::<int,f64>(1, 1.0); let _: S2 = Trait::new::<int,f64>(1, 1.0);
//~^ ERROR the trait referenced by this path needs 1 type parameter, but 0 type parameters were supplied //~^ ERROR too many type parameters provided
let _: S2 = Trait::<'a,int>::new::<f64>(1, 1.0); //~ ERROR expected 0 lifetime parameters
let _: S2 = Trait::<'a,int>::new::<f64>(1, 1.0);
//~^ ERROR too many lifetime parameters provided
} }
fn main() {} fn main() {}

View file

@ -18,7 +18,5 @@ impl<A, B, C = (A, B)> Foo<A, B, C> {
fn main() { fn main() {
Foo::<int>::new(); Foo::<int>::new();
//~^ ERROR the impl referenced by this path needs at least 2 type parameters, //~^ ERROR too few type parameters provided
// but 1 was supplied
//~^^^ ERROR not enough type parameters provided: expected at least 2, found 1
} }

View file

@ -20,7 +20,5 @@ impl<T, A = Heap> Vec<T, A> {
fn main() { fn main() {
Vec::<int, Heap, bool>::new(); Vec::<int, Heap, bool>::new();
//~^ ERROR the impl referenced by this path needs at most 2 type parameters, //~^ ERROR too many type parameters provided
// but 3 were supplied
//~^^^ ERROR too many type parameters provided: expected at most 2, found 3
} }

View file

@ -12,7 +12,7 @@ fn main() {
let a = Some(box 1); let a = Some(box 1);
match a { match a {
Ok(a) => //~ ERROR: mismatched types Ok(a) => //~ ERROR: mismatched types
println!("{}",a), //~ ERROR: failed to find an implementation of trait println!("{}",a),
None => fail!() None => fail!()
} }
} }

View file

@ -15,7 +15,6 @@ pub fn main() {
// the actual arm `Result<T, E>` has two. typeck should not be // the actual arm `Result<T, E>` has two. typeck should not be
// tricked into looking up a non-existing second type parameter. // tricked into looking up a non-existing second type parameter.
let _x: uint = match Some(1u) { let _x: uint = match Some(1u) {
//~^ ERROR mismatched types: expected `uint` but found `<generic #0>`
Ok(u) => u, //~ ERROR mismatched types: expected `core::option::Option<uint>` Ok(u) => u, //~ ERROR mismatched types: expected `core::option::Option<uint>`
Err(e) => fail!(e) //~ ERROR mismatched types: expected `core::option::Option<uint>` Err(e) => fail!(e) //~ ERROR mismatched types: expected `core::option::Option<uint>`
}; };

View file

@ -15,7 +15,6 @@ fn foo(x: Whatever) {
match x { match x {
Some(field) => field.access(), Some(field) => field.access(),
//~^ ERROR: mismatched types: expected `Whatever` but found //~^ ERROR: mismatched types: expected `Whatever` but found
//~^^ ERROR: does not implement any method in scope named `access`
} }
} }

View file

@ -14,7 +14,7 @@
// Regions that just appear in normal spots are contravariant: // Regions that just appear in normal spots are contravariant:
#[rustc_variance] #[rustc_variance]
struct Test2<'a, 'b, 'c> { //~ ERROR region_params=[-, -, -] struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]]
x: &'a int, x: &'a int,
y: &'b [int], y: &'b [int],
c: &'c str c: &'c str
@ -23,7 +23,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR region_params=[-, -, -]
// Those same annotations in function arguments become covariant: // Those same annotations in function arguments become covariant:
#[rustc_variance] #[rustc_variance]
struct Test3<'a, 'b, 'c> { //~ ERROR region_params=[+, +, +] struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]]
x: extern "Rust" fn(&'a int), x: extern "Rust" fn(&'a int),
y: extern "Rust" fn(&'b [int]), y: extern "Rust" fn(&'b [int]),
c: extern "Rust" fn(&'c str), c: extern "Rust" fn(&'c str),
@ -32,7 +32,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR region_params=[+, +, +]
// Mutability induces invariance: // Mutability induces invariance:
#[rustc_variance] #[rustc_variance]
struct Test4<'a, 'b> { //~ ERROR region_params=[-, o] struct Test4<'a, 'b> { //~ ERROR regions=[[-, o];[];[]]
x: &'a mut &'b int, x: &'a mut &'b int,
} }
@ -40,7 +40,7 @@ struct Test4<'a, 'b> { //~ ERROR region_params=[-, o]
// contravariant context: // contravariant context:
#[rustc_variance] #[rustc_variance]
struct Test5<'a, 'b> { //~ ERROR region_params=[+, o] struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[]]
x: extern "Rust" fn(&'a mut &'b int), x: extern "Rust" fn(&'a mut &'b int),
} }
@ -50,21 +50,21 @@ struct Test5<'a, 'b> { //~ ERROR region_params=[+, o]
// argument list occurs in an invariant context. // argument list occurs in an invariant context.
#[rustc_variance] #[rustc_variance]
struct Test6<'a, 'b> { //~ ERROR region_params=[-, o] struct Test6<'a, 'b> { //~ ERROR regions=[[-, o];[];[]]
x: &'a mut extern "Rust" fn(&'b int), x: &'a mut extern "Rust" fn(&'b int),
} }
// No uses at all is bivariant: // No uses at all is bivariant:
#[rustc_variance] #[rustc_variance]
struct Test7<'a> { //~ ERROR region_params=[*] struct Test7<'a> { //~ ERROR regions=[[*];[];[]]
x: int x: int
} }
// Try enums too. // Try enums too.
#[rustc_variance] #[rustc_variance]
enum Test8<'a, 'b, 'c> { //~ ERROR region_params=[+, -, o] enum Test8<'a, 'b, 'c> { //~ ERROR regions=[[+, -, o];[];[]]
Test8A(extern "Rust" fn(&'a int)), Test8A(extern "Rust" fn(&'a int)),
Test8B(&'b [int]), Test8B(&'b [int]),
Test8C(&'b mut &'c str), Test8C(&'b mut &'c str),

View file

@ -13,29 +13,29 @@
// Try enums too. // Try enums too.
#[rustc_variance] #[rustc_variance]
enum Base<'a, 'b, 'c, 'd> { //~ ERROR region_params=[+, -, o, *] enum Base<'a, 'b, 'c, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]]
Test8A(extern "Rust" fn(&'a int)), Test8A(extern "Rust" fn(&'a int)),
Test8B(&'b [int]), Test8B(&'b [int]),
Test8C(&'b mut &'c str), Test8C(&'b mut &'c str),
} }
#[rustc_variance] #[rustc_variance]
struct Derived1<'w, 'x, 'y, 'z> { //~ ERROR region_params=[*, o, -, +] struct Derived1<'w, 'x, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[]]
f: Base<'z, 'y, 'x, 'w> f: Base<'z, 'y, 'x, 'w>
} }
#[rustc_variance] // Combine - and + to yield o #[rustc_variance] // Combine - and + to yield o
struct Derived2<'a, 'b, 'c> { //~ ERROR region_params=[o, o, *] struct Derived2<'a, 'b, 'c> { //~ ERROR regions=[[o, o, *];[];[]]
f: Base<'a, 'a, 'b, 'c> f: Base<'a, 'a, 'b, 'c>
} }
#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
struct Derived3<'a, 'b, 'c> { //~ ERROR region_params=[o, -, *] struct Derived3<'a, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[]]
f: Base<'a, 'b, 'a, 'c> f: Base<'a, 'b, 'a, 'c>
} }
#[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
struct Derived4<'a, 'b, 'c> { //~ ERROR region_params=[+, -, o] struct Derived4<'a, 'b, 'c> { //~ ERROR regions=[[+, -, o];[];[]]
f: Base<'a, 'b, 'c, 'a> f: Base<'a, 'b, 'c, 'a>
} }