diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 2ff656853c3bd..5a974aecabcb2 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -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_extension_impl: uint = 0x83; -pub static tag_region_param_def: uint = 0x84; -pub static tag_region_param_def_ident: uint = 0x85; -pub static tag_region_param_def_def_id: uint = 0x86; +// GAP 0x84, 0x85, 0x86 pub static tag_native_libraries: uint = 0x87; pub static tag_native_libraries_lib: uint = 0x88; @@ -217,3 +215,9 @@ pub struct LinkMeta { pub crateid: CrateId, 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; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index ee5179e9cef4a..43c895a201fa6 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -18,6 +18,7 @@ use metadata::decoder; use middle::lang_items; use middle::ty; use middle::typeck; +use middle::subst::VecPerParamSpace; use serialize::ebml; 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); ty::ty_param_bounds_and_ty { - generics: ty::Generics {type_param_defs: Rc::new(Vec::new()), - region_param_defs: Rc::new(Vec::new())}, + generics: ty::Generics {types: VecPerParamSpace::empty(), + regions: VecPerParamSpace::empty()}, 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 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 cdata = cstore.get_crate_data(def.krate); decoder::get_impl_vtables(&*cdata, def.node, tcx) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index d088d0d953d0e..68aa2bacd08e2 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -23,6 +23,7 @@ use metadata::tydecode::{parse_ty_data, parse_def_id, parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::lang_items; use middle::def; +use middle::subst; use middle::ty::{ImplContainer, TraitContainer}; use middle::ty; use middle::typeck; @@ -257,34 +258,44 @@ fn item_ty_param_defs(item: ebml::Doc, tcx: &ty::ctxt, cdata: Cmd, tag: uint) - -> Rc > { - let mut bounds = Vec::new(); + -> subst::VecPerParamSpace { + let mut bounds = subst::VecPerParamSpace::empty(); reader::tagged_docs(item, tag, |p| { let bd = parse_type_param_def_data( p.data, p.start, cdata.cnum, tcx, |_, did| translate_def_id(cdata, did)); - bounds.push(bd); + bounds.push(bd.space, bd); true }); - Rc::new(bounds) + bounds } fn item_region_param_defs(item_doc: ebml::Doc, cdata: Cmd) - -> Rc > { - let mut v = Vec::new(); + -> subst::VecPerParamSpace +{ + let mut v = subst::VecPerParamSpace::empty(); reader::tagged_docs(item_doc, tag_region_param_def, |rp_doc| { - let ident_str_doc = reader::get_doc(rp_doc, - tag_region_param_def_ident); - let ident = item_name(&*token::get_ident_interner(), ident_str_doc); - let def_id_doc = reader::get_doc(rp_doc, - tag_region_param_def_def_id); - let def_id = reader::with_doc_data(def_id_doc, parse_def_id); - let def_id = translate_def_id(cdata, def_id); - v.push(ty::RegionParameterDef { name: ident.name, - def_id: def_id }); - true - }); - Rc::new(v) + let ident_str_doc = reader::get_doc(rp_doc, + tag_region_param_def_ident); + let ident = item_name(&*token::get_ident_interner(), ident_str_doc); + let def_id_doc = reader::get_doc(rp_doc, + tag_region_param_def_def_id); + let def_id = reader::with_doc_data(def_id_doc, parse_def_id); + let def_id = translate_def_id(cdata, def_id); + + 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 + }); + v } fn enum_variant_ids(item: ebml::Doc, cdata: Cmd) -> Vec { @@ -403,8 +414,8 @@ pub fn get_trait_def(cdata: Cmd, } ty::TraitDef { - generics: ty::Generics {type_param_defs: tp_defs, - region_param_defs: rp_defs}, + generics: ty::Generics {types: tp_defs, + regions: rp_defs}, bounds: bounds, 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); ty::ty_param_bounds_and_ty { - generics: ty::Generics {type_param_defs: tp_defs, - region_param_defs: rp_defs}, + generics: ty::Generics {types: tp_defs, + regions: rp_defs}, ty: t } } @@ -440,16 +451,13 @@ pub fn get_impl_trait(cdata: Cmd, pub fn get_impl_vtables(cdata: Cmd, id: ast::NodeId, - tcx: &ty::ctxt) -> typeck::impl_res + tcx: &ty::ctxt) + -> typeck::vtable_res { let item_doc = lookup_item(id, cdata.data()); let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables); let mut decoder = reader::Decoder::new(vtables_doc); - - typeck::impl_res { - trait_vtables: decoder.read_vtable_res(tcx, cdata), - self_vtables: decoder.read_vtable_param_res(tcx, cdata) - } + decoder.read_vtable_res(tcx, cdata) } @@ -802,8 +810,8 @@ pub fn get_method(intr: Rc, cdata: Cmd, id: ast::NodeId, ty::Method::new( name, ty::Generics { - type_param_defs: type_param_defs, - region_param_defs: rp_defs, + types: type_param_defs, + regions: rp_defs, }, fty, explicit_self, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index f5672dce16c6c..98d9b45738fd0 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -19,6 +19,7 @@ use metadata::common::*; use metadata::cstore; use metadata::decoder; use metadata::tyencode; +use middle::subst::VecPerParamSpace; use middle::ty::{node_id_to_type, lookup_item_type}; use middle::astencode; use middle::ty; @@ -128,10 +129,9 @@ fn encode_trait_ref(ebml_w: &mut Encoder, fn encode_impl_vtables(ebml_w: &mut Encoder, ecx: &EncodeContext, - vtables: &typeck::impl_res) { + vtables: &typeck::vtable_res) { ebml_w.start_tag(tag_item_impl_vtables); - astencode::encode_vtable_res(ecx, ebml_w, &vtables.trait_vtables); - astencode::encode_vtable_param_res(ecx, ebml_w, &vtables.self_vtables); + astencode::encode_vtable_res(ecx, ebml_w, vtables); 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, ecx: &EncodeContext, - params: &[ty::TypeParameterDef], + params: &VecPerParamSpace, tag: uint) { let ty_str_ctxt = &tyencode::ctxt { 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, - params: &[ty::RegionParameterDef]) { + params: &VecPerParamSpace) { for param in params.iter() { 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, 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(); } } @@ -191,9 +197,9 @@ fn encode_item_variances(ebml_w: &mut Encoder, fn encode_bounds_and_type(ebml_w: &mut Encoder, ecx: &EncodeContext, 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); - 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); } @@ -725,8 +731,7 @@ fn encode_method_ty_fields(ecx: &EncodeContext, method_ty: &ty::Method) { encode_def_id(ebml_w, method_ty.def_id); encode_name(ebml_w, method_ty.ident.name); - encode_ty_type_param_defs(ebml_w, ecx, - method_ty.generics.type_param_defs(), + encode_ty_type_param_defs(ebml_w, ecx, &method_ty.generics.types, tag_item_method_tps); encode_method_fty(ecx, ebml_w, &method_ty.fty); 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() { - let num_params = tpt.generics.type_param_defs().len(); - if num_params > 0u || - is_default_impl || - should_inline(ast_method.attrs.as_slice()) { + let any_types = !tpt.generics.types.is_empty(); + if any_types || is_default_impl || should_inline(ast_method.attrs.as_slice()) { encode_inlined_item(ecx, ebml_w, IIMethodRef(local_def(parent_id), false, &*ast_method)); @@ -1125,9 +1128,9 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_item_variances(ebml_w, ecx, item.id); let trait_def = ty::lookup_trait_def(tcx, def_id); encode_ty_type_param_defs(ebml_w, ecx, - trait_def.generics.type_param_defs(), + &trait_def.generics.types, 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_name(ebml_w, item.ident.name); encode_attributes(ebml_w, item.attrs.as_slice()); diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index a39be31c4b572..6a60f91a1ae4f 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -17,6 +17,7 @@ #![allow(non_camel_case_types)] use middle::subst; +use middle::subst::VecPerParamSpace; use middle::ty; 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, 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); parse_ty(&mut st, conv) } pub fn parse_bare_fn_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, 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); parse_bare_fn_ty(&mut st, conv) } pub fn parse_trait_ref_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, 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); parse_trait_ref(&mut st, conv) } pub fn parse_substs_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, 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); 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 { - let regions = parse_region_substs(st, |x,y| conv(x,y)); +fn parse_vec_per_param_space(st: &mut PState, + f: |&mut PState| -> T) + -> VecPerParamSpace +{ + let mut r = VecPerParamSpace::empty(); + for &space in subst::ParamSpace::all().iter() { + assert_eq!(next(st), '['); + while peek(st) != ']' { + r.push(space, f(st)); + } + assert_eq!(next(st), ']'); + } + r +} - let self_ty = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)) ); +fn parse_substs(st: &mut PState, conv: conv_did) -> subst::Substs { + let regions = + parse_region_substs(st, |x,y| conv(x,y)); - assert_eq!(next(st), '['); - let mut params: Vec = Vec::new(); - while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); } - st.pos = st.pos + 1u; + let types = + parse_vec_per_param_space(st, |st| parse_ty(st, |x,y| conv(x,y))); - return subst::Substs { - regions: regions, - self_ty: self_ty, - tps: params - }; + return subst::Substs { types: types, + regions: regions }; } fn parse_region_substs(st: &mut PState, conv: conv_did) -> subst::RegionSubsts { match next(st) { 'e' => subst::ErasedRegions, 'n' => { - let mut regions = vec!(); - while peek(st) != '.' { - let r = parse_region(st, |x,y| conv(x,y)); - regions.push(r); - } - assert_eq!(next(st), '.'); - subst::NonerasedRegions(regions) + subst::NonerasedRegions( + parse_vec_per_param_space( + st, |st| parse_region(st, |x,y| conv(x,y)))) } _ => 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), '['); let node_id = parse_uint(st) as ast::NodeId; assert_eq!(next(st), '|'); + let space = parse_param_space(st); + assert_eq!(next(st), '|'); let index = parse_uint(st); assert_eq!(next(st), '|'); 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' => { assert_eq!(next(st), '['); @@ -327,11 +354,11 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { 'p' => { let did = parse_def(st, TypeParameter, |x,y| conv(x,y)); debug!("parsed ty_param: did={:?}", did); - return ty::mk_param(st.tcx, parse_uint(st), did); - } - 's' => { - let did = parse_def(st, TypeParameter, |x,y| conv(x,y)); - return ty::mk_self(st.tcx, did); + let index = parse_uint(st); + assert_eq!(next(st), '|'); + let space = parse_param_space(st); + assert_eq!(next(st), '|'); + 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_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), ']'); return ty::mk_struct(st.tcx, did, substs); } + 'e' => { + return ty::mk_err(); + } 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 { let mut n = 0u; 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 { + 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 { - ident: parse_ident(st, ':'), - def_id: parse_def(st, NominalType, |x,y| conv(x,y)), - bounds: Rc::new(parse_bounds(st, |x,y| conv(x,y))), - default: parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y))) + ident: ident, + def_id: def_id, + space: space, + index: index, + bounds: bounds, + default: default } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 8b36256492fa0..b8987a382daed 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -18,7 +18,8 @@ use std::collections::HashMap; use std::io::MemWriter; use middle::subst; -use middle::ty::param_ty; +use middle::subst::VecPerParamSpace; +use middle::ty::ParamTy; use middle::ty; use syntax::abi::Abi; @@ -118,12 +119,23 @@ fn enc_opt(w: &mut MemWriter, t: Option, enc_f: |&mut MemWriter, T|) { } } +fn enc_vec_per_param_space(w: &mut MemWriter, + cx: &ctxt, + v: &VecPerParamSpace, + 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) { enc_region_substs(w, cx, &substs.regions); - enc_opt(w, substs.self_ty, |w, t| enc_ty(w, cx, t)); - mywrite!(w, "["); - for t in substs.tps.iter() { enc_ty(w, cx, *t); } - mywrite!(w, "]"); + enc_vec_per_param_space(w, cx, &substs.types, + |w, cx, &ty| enc_ty(w, cx, ty)); } 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) => { mywrite!(w, "n"); - for &r in regions.iter() { - enc_region(w, cx, r); - } - mywrite!(w, "."); + enc_vec_per_param_space(w, cx, regions, + |w, cx, &r| enc_region(w, cx, r)); } } } @@ -148,9 +158,10 @@ fn enc_region(w: &mut MemWriter, cx: &ctxt, r: ty::Region) { enc_bound_region(w, cx, br); mywrite!(w, "]"); } - ty::ReEarlyBound(node_id, index, name) => { - mywrite!(w, "B[{}|{}|{}]", + ty::ReEarlyBound(node_id, space, index, name) => { + mywrite!(w, "B[{}|{}|{}|{}]", node_id, + space.to_uint(), index, token::get_name(name)); } @@ -293,18 +304,17 @@ fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) { ty::ty_infer(_) => { cx.diag.handler().bug("cannot encode inference variable types"); } - ty::ty_param(param_ty {idx: id, def_id: did}) => { - mywrite!(w, "p{}|{}", (cx.ds)(did), id); - } - ty::ty_self(did) => { - mywrite!(w, "s{}|", (cx.ds)(did)); + ty::ty_param(ParamTy {space, idx: id, def_id: did}) => { + mywrite!(w, "p{}|{}|{}|", (cx.ds)(did), id, space.to_uint()) } ty::ty_struct(def, ref substs) => { mywrite!(w, "a[{}|", (cx.ds)(def)); enc_substs(w, cx, substs); 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) { - 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_opt(w, v.default, |w, t| enc_ty(w, cx, t)); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index cc356a8bf077c..289c2feef2db1 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -25,6 +25,7 @@ use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter, RegionParameter}; use metadata::tyencode; use middle::subst; +use middle::subst::VecPerParamSpace; use middle::typeck::{MethodCall, MethodCallee, MethodOrigin}; use middle::{ty, typeck}; use util::ppaux::ty_to_str; @@ -39,7 +40,7 @@ use libc; use std::io::Seek; use std::io::MemWriter; use std::mem; -use std::rc::Rc; +use std::string::String; use serialize::ebml::reader; use serialize::ebml; @@ -433,7 +434,7 @@ impl tr for def::Def { def::DefTrait(did) => def::DefTrait(did.tr(xcx)), def::DefTy(did) => def::DefTy(did.tr(xcx)), 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::DefUse(did) => def::DefUse(did.tr(xcx)), def::DefUpvar(nid1, def, nid2, nid3) => { @@ -476,13 +477,18 @@ impl tr for ty::AutoRef { impl tr for ty::Region { fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::Region { match *self { - ty::ReLateBound(id, br) => ty::ReLateBound(xcx.tr_id(id), - br.tr(xcx)), - ty::ReEarlyBound(id, index, ident) => ty::ReEarlyBound(xcx.tr_id(id), - index, - ident), - ty::ReScope(id) => ty::ReScope(xcx.tr_id(id)), - ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) => *self, + ty::ReLateBound(id, br) => { + ty::ReLateBound(xcx.tr_id(id), br.tr(xcx)) + } + ty::ReEarlyBound(id, space, index, 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::ReFree(ref fr) => { ty::ReFree(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id), bound_region: fr.bound_region.tr(xcx)}) @@ -634,15 +640,16 @@ fn encode_vtable_res_with_key(ecx: &e::EncodeContext, } pub fn encode_vtable_res(ecx: &e::EncodeContext, - ebml_w: &mut Encoder, - dr: &typeck::vtable_res) { + ebml_w: &mut Encoder, + dr: &typeck::vtable_res) { // can't autogenerate this code because automatic code of // ty::t doesn't work, and there is no way (atm) to have // hand-written encoding routines combine with auto-generated - // ones. perhaps we should fix this. - ebml_w.emit_from_vec(dr.as_slice(), |ebml_w, param_tables| { - Ok(encode_vtable_param_res(ecx, ebml_w, param_tables)) - }).unwrap() + // ones. perhaps we should fix this. + encode_vec_per_param_space( + ebml_w, dr, + |ebml_w, param_tables| encode_vtable_param_res(ecx, ebml_w, + param_tables)) } 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) => { - 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| { 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() } pub trait vtable_decoder_helpers { + fn read_vec_per_param_space(&mut self, + f: |&mut Self| -> T) + -> VecPerParamSpace; fn read_vtable_res_with_key(&mut self, tcx: &ty::ctxt, cdata: &cstore::crate_metadata) @@ -703,6 +718,16 @@ pub trait vtable_decoder_helpers { } impl<'a> vtable_decoder_helpers for reader::Decoder<'a> { + fn read_vec_per_param_space(&mut self, + f: |&mut reader::Decoder<'a>| -> T) + -> VecPerParamSpace + { + 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, tcx: &ty::ctxt, cdata: &cstore::crate_metadata) @@ -718,10 +743,12 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> { } fn read_vtable_res(&mut self, - tcx: &ty::ctxt, cdata: &cstore::crate_metadata) - -> typeck::vtable_res { - self.read_to_vec(|this| Ok(this.read_vtable_param_res(tcx, cdata))) - .unwrap().move_iter().collect() + tcx: &ty::ctxt, + cdata: &cstore::crate_metadata) + -> typeck::vtable_res + { + self.read_vec_per_param_space( + |this| this.read_vtable_param_res(tcx, cdata)) } 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| { this.read_enum_variant(["vtable_static", "vtable_param", - "vtable_self"], + "vtable_error"], |this, i| { Ok(match i { 0 => { @@ -763,7 +790,9 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> { }).unwrap() ) } - // hard to avoid - user input + 2 => { + typeck::vtable_error + } _ => fail!("bad enum variant") }) }) @@ -771,6 +800,18 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> { } } +// ___________________________________________________________________________ +// + +fn encode_vec_per_param_space(ebml_w: &mut Encoder, + v: &subst::VecPerParamSpace, + 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 @@ -827,14 +868,15 @@ impl<'a> ebml_writer_helpers for Encoder<'a> { self.emit_struct("ty_param_bounds_and_ty", 2, |this| { this.emit_struct_field("generics", 0, |this| { this.emit_struct("Generics", 2, |this| { - this.emit_struct_field("type_param_defs", 0, |this| { - this.emit_from_vec(tpbt.generics.type_param_defs(), - |this, type_param_def| { - Ok(this.emit_type_param_def(ecx, type_param_def)) - }) + this.emit_struct_field("types", 0, |this| { + Ok(encode_vec_per_param_space( + this, &tpbt.generics.types, + |this, def| this.emit_type_param_def(ecx, def))) }); - this.emit_struct_field("region_param_defs", 1, |this| { - tpbt.generics.region_param_defs().encode(this) + this.emit_struct_field("regions", 1, |this| { + Ok(encode_vec_per_param_space( + this, &tpbt.generics.regions, + |this, def| def.encode(this).unwrap())) }) }) }); @@ -1186,22 +1228,17 @@ impl<'a> ebml_decoder_decoder_helpers for reader::Decoder<'a> { generics: this.read_struct_field("generics", 0, |this| { this.read_struct("Generics", 2, |this| { Ok(ty::Generics { - type_param_defs: - this.read_struct_field("type_param_defs", - 0, - |this| { - Ok(Rc::new(this.read_to_vec(|this| - Ok(this.read_type_param_def(xcx))) - .unwrap() - .move_iter() - .collect())) + types: + this.read_struct_field("types", 0, |this| { + Ok(this.read_vec_per_param_space( + |this| this.read_type_param_def(xcx))) }).unwrap(), - region_param_defs: - this.read_struct_field("region_param_defs", - 1, - |this| { - Decodable::decode(this) - }).unwrap() + + regions: + this.read_struct_field("regions", 1, |this| { + Ok(this.read_vec_per_param_space( + |this| Decodable::decode(this).unwrap())) + }).unwrap() }) }) }).unwrap(), diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 6805c86f1694c..7ee8b33b1fa67 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::subst::ParamSpace; use syntax::ast; use syntax::ast_util::local_def; @@ -27,7 +28,7 @@ pub enum Def { DefTy(ast::DefId), DefTrait(ast::DefId), DefPrimTy(ast::PrimTy), - DefTyParam(ast::DefId, uint), + DefTyParam(ParamSpace, ast::DefId, uint), DefBinding(ast::NodeId, ast::BindingMode), DefUse(ast::DefId), DefUpvar(ast::NodeId, // id of closed over var @@ -61,7 +62,7 @@ impl Def { match *self { DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(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, _) => { id } diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index df6b20b62f590..9979f13093535 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -86,12 +86,9 @@ fn check_struct_safe_for_destructor(cx: &mut Context, span: Span, struct_did: DefId) { let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did); - if !struct_tpt.generics.has_type_params() { - let struct_ty = ty::mk_struct(cx.tcx, struct_did, subst::Substs { - regions: subst::NonerasedRegions(Vec::new()), - self_ty: None, - tps: Vec::new() - }); + if !struct_tpt.generics.has_type_params(subst::TypeSpace) { + let struct_ty = ty::mk_struct(cx.tcx, struct_did, + subst::Substs::empty()); if !ty::type_is_sendable(cx.tcx, struct_ty) { cx.tcx.sess.span_err(span, "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)); // Handle any kind bounds on type parameters - { - 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) - } - } - } + check_bounds_on_type_parameters(cx, e); match e.node { ExprUnary(UnBox, ref interior) => { @@ -331,6 +284,77 @@ pub fn check_expr(cx: &mut Context, e: &Expr) { 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) { check_cast_for_escaping_regions(cx, source_ty, target_ty, span); 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 did = def_map.get_copy(&id).def_id(); let generics = ty::lookup_item_type(cx.tcx, did).generics; - let type_param_defs = generics.type_param_defs(); - for (&ty, type_param_def) in - item_substs.substs.tps.iter().zip( - type_param_defs.iter()) - { - check_typaram_bounds(cx, aty.span, ty, type_param_def) + for def in generics.types.iter() { + let ty = *item_substs.substs.types.get(def.space, + def.index); + check_typaram_bounds(cx, aty.span, ty, def) } } } @@ -555,7 +577,12 @@ pub fn check_cast_for_escaping_regions( |ty| { match ty::get(ty).sty { 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) */ } else { check_static(cx.tcx, ty, source_span); /* case (3) */ diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 7fc31c974e939..47bc2521689ae 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -17,6 +17,7 @@ use middle::def::*; use middle::lang_items::LanguageItems; use middle::lint::{UnnecessaryQualification, UnusedImports}; use middle::pat_util::pat_bindings; +use middle::subst::{ParamSpace, FnSpace, TypeSpace}; use util::nodemap::{NodeMap, DefIdSet, FnvHashMap}; use syntax::ast::*; @@ -227,25 +228,20 @@ enum FallbackSuggestion { } enum TypeParameters<'a> { - NoTypeParameters, //< No type parameters. - HasTypeParameters(&'a Generics, //< Type parameters. - NodeId, //< ID of the enclosing item - - // The index to start numbering the type parameters at. - // This is zero if this is the outermost set of type - // parameters, or equal to the number of outer type - // parameters. For example, if we have: - // - // impl I { - // fn method() { ... } - // } - // - // 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. - RibKind) + NoTypeParameters, + HasTypeParameters( + // Type parameters. + &'a Generics, + + // Identifies the things that these parameters + // were declared on (type, fn, etc) + ParamSpace, + + // ID of the enclosing item. + NodeId, + + // The kind of the rib used for type parameters. + RibKind) } // The rib kind controls the translation of argument or local definitions @@ -1532,8 +1528,8 @@ impl<'a> Resolver<'a> { self.with_type_parameter_rib( HasTypeParameters(generics, + FnSpace, foreign_item.id, - 0, NormalRibKind), f); } @@ -3439,7 +3435,7 @@ impl<'a> Resolver<'a> { // If the def is a ty param, and came from the parent // item, it's ok match def { - DefTyParam(did, _) if { + DefTyParam(_, did, _) if { self.def_map.borrow().find(&did.node).map(|x| *x) == Some(DefTyParamBinder(item_id)) } => { @@ -3574,8 +3570,8 @@ impl<'a> Resolver<'a> { // but maybe it's okay since the first time will signal an // error if there is one? -- tjc self.with_type_parameter_rib(HasTypeParameters(generics, + TypeSpace, item.id, - 0, ItemRibKind), |this| { visit::walk_item(this, item, ()); @@ -3584,8 +3580,8 @@ impl<'a> Resolver<'a> { ItemTy(_, ref generics) => { self.with_type_parameter_rib(HasTypeParameters(generics, + TypeSpace, item.id, - 0, ItemRibKind), |this| { visit::walk_item(this, item, ()); @@ -3615,8 +3611,8 @@ impl<'a> Resolver<'a> { // Create a new rib for the trait-wide type parameters. self.with_type_parameter_rib(HasTypeParameters(generics, + TypeSpace, item.id, - 0, NormalRibKind), |this| { this.resolve_type_parameters(&generics.ty_params); @@ -3636,8 +3632,8 @@ impl<'a> Resolver<'a> { ast::Required(ref ty_m) => { this.with_type_parameter_rib (HasTypeParameters(&ty_m.generics, + FnSpace, item.id, - generics.ty_params.len(), MethodRibKind(item.id, Required)), |this| { @@ -3655,9 +3651,8 @@ impl<'a> Resolver<'a> { } ast::Provided(ref m) => { this.resolve_method(MethodRibKind(item.id, - Provided(m.id)), - &**m, - generics.ty_params.len()) + Provided(m.id)), + &**m) } } } @@ -3687,7 +3682,7 @@ impl<'a> Resolver<'a> { ForeignItemFn(_, ref generics) => { this.with_type_parameter_rib( HasTypeParameters( - generics, foreign_item.id, 0, + generics, FnSpace, foreign_item.id, ItemRibKind), |this| visit::walk_foreign_item(this, &**foreign_item, @@ -3708,8 +3703,8 @@ impl<'a> Resolver<'a> { Some(fn_decl), HasTypeParameters (generics, + FnSpace, item.id, - 0, ItemRibKind), block); } @@ -3730,7 +3725,7 @@ impl<'a> Resolver<'a> { type_parameters: TypeParameters, f: |&mut Resolver|) { match type_parameters { - HasTypeParameters(generics, node_id, initial_index, + HasTypeParameters(generics, space, node_id, rib_kind) => { let function_type_rib = Rib::new(rib_kind); @@ -3739,9 +3734,9 @@ impl<'a> Resolver<'a> { let ident = type_parameter.ident; debug!("with_type_parameter_rib: {} {}", node_id, type_parameter.id); - let def_like = DlDef(DefTyParam - (local_def(type_parameter.id), - index + initial_index)); + let def_like = DlDef(DefTyParam(space, + local_def(type_parameter.id), + index)); // Associate this type parameter with // the item that bound it self.record_def(type_parameter.id, @@ -3897,8 +3892,8 @@ impl<'a> Resolver<'a> { fields: &[StructField]) { // If applicable, create a rib for the type parameters. self.with_type_parameter_rib(HasTypeParameters(generics, + TypeSpace, id, - 0, ItemRibKind), |this| { // Resolve the type parameters. @@ -3948,14 +3943,12 @@ impl<'a> Resolver<'a> { // to be NormalRibKind? fn resolve_method(&mut self, rib_kind: RibKind, - method: &Method, - outer_type_parameter_count: uint) { + method: &Method) { let method_generics = &method.generics; - let type_parameters = - HasTypeParameters(method_generics, - method.id, - outer_type_parameter_count, - rib_kind); + let type_parameters = HasTypeParameters(method_generics, + FnSpace, + method.id, + rib_kind); self.resolve_function(rib_kind, Some(method.decl), type_parameters, method.body); } @@ -3992,16 +3985,15 @@ impl<'a> Resolver<'a> { } fn resolve_implementation(&mut self, - id: NodeId, - generics: &Generics, - opt_trait_reference: &Option, - self_type: &Ty, - methods: &[Gc]) { + id: NodeId, + generics: &Generics, + opt_trait_reference: &Option, + self_type: &Ty, + methods: &[Gc]) { // 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, + TypeSpace, id, - 0, NormalRibKind), |this| { // Resolve the type parameters. @@ -4016,8 +4008,7 @@ impl<'a> Resolver<'a> { for method in methods.iter() { // We also need a new scope for the method-specific type parameters. this.resolve_method(MethodRibKind(id, Provided(method.id)), - &**method, - outer_type_parameter_count); + &**method); } }); }); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 7065772d74f6c..f416686efd869 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -18,7 +18,7 @@ */ use driver::session::Session; -use util::nodemap::NodeMap; +use middle::subst; use syntax::ast; use syntax::codemap::Span; use syntax::owned_slice::OwnedSlice; @@ -27,10 +27,24 @@ use syntax::parse::token; use syntax::print::pprust::{lifetime_to_str}; use syntax::visit; 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 // that it corresponds to -pub type NamedRegionMap = NodeMap; +pub type NamedRegionMap = NodeMap; // Returns an instance of some type that implements std::fmt::Show fn lifetime_show(lt_name: &ast::Name) -> token::InternedString { @@ -45,7 +59,7 @@ struct LifetimeContext<'a> { enum ScopeChain<'a> { /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc. - EarlyScope(uint, &'a Vec, Scope<'a>), + EarlyScope(subst::ParamSpace, &'a Vec, Scope<'a>), /// LateScope(binder_id, ['a, 'b, ...], s) extends s with late-bound /// lifetimes introduced by the declaration binder_id. LateScope(ast::NodeId, &'a Vec, Scope<'a>), @@ -86,7 +100,7 @@ impl<'a, 'b> Visitor> for LifetimeContext<'b> { ast::ItemImpl(ref generics, _, _, _) | ast::ItemTrait(ref generics, _, _, _) => { self.check_lifetime_names(&generics.lifetimes); - EarlyScope(0, &generics.lifetimes, &root) + EarlyScope(subst::TypeSpace, &generics.lifetimes, &root) } }; debug!("entering scope {:?}", scope); @@ -152,33 +166,13 @@ impl<'a, 'b> Visitor> for LifetimeContext<'b> { lifetime_ref: &ast::Lifetime, scope: Scope<'a>) { if lifetime_ref.name == special_idents::statik.name { - self.insert_lifetime(lifetime_ref, ast::DefStaticRegion); + self.insert_lifetime(lifetime_ref, DefStaticRegion); return; } 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> { /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. fn visit_fn_decl(&mut self, @@ -212,14 +206,11 @@ impl<'a> LifetimeContext<'a> { self.check_lifetime_names(&generics.lifetimes); - let early_count = scope.count_early_params(); let referenced_idents = free_lifetimes(&generics.ty_params); debug!("pushing fn scope id={} due to fn item/method\ - referenced_idents={:?} \ - early_count={}", + referenced_idents={:?}", n, - referenced_idents.iter().map(lifetime_show).collect::>(), - early_count); + referenced_idents.iter().map(lifetime_show).collect::>()); if referenced_idents.is_empty() { let scope1 = LateScope(n, &generics.lifetimes, scope); walk(self, &scope1) @@ -227,7 +218,7 @@ impl<'a> LifetimeContext<'a> { let (early, late) = generics.lifetimes.clone().partition( |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); walk(self, &scope2); @@ -256,11 +247,10 @@ impl<'a> LifetimeContext<'a> { break; } - EarlyScope(base, lifetimes, s) => { + EarlyScope(space, lifetimes, s) => { match search_lifetimes(lifetimes, lifetime_ref) { - Some((offset, decl_id)) => { - let index = base + offset; - let def = ast::DefEarlyBoundRegion(index, decl_id); + Some((index, decl_id)) => { + let def = DefEarlyBoundRegion(space, index, decl_id); self.insert_lifetime(lifetime_ref, def); return; } @@ -274,7 +264,7 @@ impl<'a> LifetimeContext<'a> { LateScope(binder_id, lifetimes, s) => { match search_lifetimes(lifetimes, lifetime_ref) { 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); return; } @@ -325,7 +315,7 @@ impl<'a> LifetimeContext<'a> { match search_result { 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); } @@ -374,7 +364,7 @@ impl<'a> LifetimeContext<'a> { fn insert_lifetime(&mut self, lifetime_ref: &ast::Lifetime, - def: ast::DefRegion) { + def: DefRegion) { if lifetime_ref.id == ast::DUMMY_NODE_ID { self.sess.span_bug(lifetime_ref.span, "lifetime reference not renumbered, \ diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index 2c73bc847a3b7..7e26d9c79386e 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -231,7 +231,7 @@ impl <'l> DxrVisitor<'l> { def::DefTyParamBinder(_) | def::DefLabel(_) | def::DefStaticMethod(_, _, _) | - def::DefTyParam(_, _) | + def::DefTyParam(..) | def::DefUse(_) | def::DefMethod(_, _) | def::DefPrimTy(_) => { diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index c4121d830dbdc..5e7284dbfd1de 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -15,11 +15,81 @@ use middle::ty_fold; use middle::ty_fold::{TypeFoldable, TypeFolder}; use util::ppaux::Repr; +use std::iter::Chain; +use std::mem; +use std::raw; +use std::slice::{Items, MutItems}; 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 { + 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 HomogeneousTuple3 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, + pub regions: RegionSubsts, +} + /** * Represents the values to use when substituting lifetime parameters. * If the value is `ErasedRegions`, then this subst is occurring during @@ -27,46 +97,49 @@ use syntax::codemap::Span; #[deriving(Clone, PartialEq, Eq, Hash)] pub enum RegionSubsts { ErasedRegions, - NonerasedRegions(Vec) -} - -/** - * 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, - pub tps: Vec, - pub regions: RegionSubsts, + NonerasedRegions(VecPerParamSpace) } impl Substs { + pub fn new(t: VecPerParamSpace, + r: VecPerParamSpace) + -> Substs + { + Substs { types: t, regions: NonerasedRegions(r) } + } + + pub fn new_type(t: Vec, + r: Vec) + -> Substs + { + Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()), + VecPerParamSpace::new(r, Vec::new(), Vec::new())) + } + + pub fn new_trait(t: Vec, + r: Vec, + 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) -> Substs + { + Substs { types: t, regions: ErasedRegions } + } + pub fn empty() -> Substs { Substs { - self_ty: None, - tps: Vec::new(), - regions: NonerasedRegions(Vec::new()) + types: VecPerParamSpace::empty(), + regions: NonerasedRegions(VecPerParamSpace::empty()), } } pub fn trans_empty() -> Substs { Substs { - self_ty: None, - tps: Vec::new(), + types: VecPerParamSpace::empty(), regions: ErasedRegions } } @@ -74,16 +147,251 @@ impl Substs { pub fn is_noop(&self) -> bool { let regions_is_noop = match self.regions { 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.self_ty.is_none() + regions_is_noop && self.types.is_empty() + } + + pub fn self_ty(&self) -> Option { + 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 { + /*! + * 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 self_ty(&self) -> ty::t { - self.self_ty.unwrap() + pub fn mut_regions<'a>(&'a mut self) -> &'a mut VecPerParamSpace { + /*! + * 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, + m_regions: Vec) + -> 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(self, + a: A, + op: |VecPerParamSpace, A| -> VecPerParamSpace) + -> 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 { + vecs: (Vec, Vec, Vec) +} + +impl VecPerParamSpace { + pub fn empty() -> VecPerParamSpace { + VecPerParamSpace { + vecs: (Vec::new(), Vec::new(), Vec::new()) + } + } + + pub fn params_from_type(types: Vec) -> VecPerParamSpace { + VecPerParamSpace::empty().with_vec(TypeSpace, types) + } + + pub fn new(t: Vec, s: Vec, f: Vec) -> VecPerParamSpace { + VecPerParamSpace { + vecs: (t, s, f) + } + } + + pub fn sort(t: Vec, space: |&T| -> ParamSpace) -> VecPerParamSpace { + 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 { + self.vecs.get(space as uint).unwrap() + } + + pub fn get_mut_vec<'a>(&'a mut self, space: ParamSpace) -> &'a mut Vec { + 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, + Chain, + 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| -> 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(&self, pred: |&T| -> U) -> VecPerParamSpace { + 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(&self, pred: |&T| -> U) -> VecPerParamSpace { + /*! + * 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 = 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 = self.vecs.ref1().iter().rev().map(|p| pred(p)).collect(); + selfs.reverse(); + let mut tys: Vec = self.vecs.ref0().iter().rev().map(|p| pred(p)).collect(); + tys.reverse(); + VecPerParamSpace::new(tys, selfs, fns) + } + + pub fn split(self) -> (Vec, Vec, Vec) { + self.vecs + } + + pub fn with_vec(mut self, space: ParamSpace, vec: Vec) + -> VecPerParamSpace + { + 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 // `middle::typeck::check::regionmanip::replace_late_regions_in_fn_sig()`. match r { - ty::ReEarlyBound(_, i, _) => { + ty::ReEarlyBound(_, space, i, _) => { match self.substs.regions { ErasedRegions => ty::ReStatic, - NonerasedRegions(ref regions) => *regions.get(i), + NonerasedRegions(ref regions) => *regions.get(space, i), } } _ => r @@ -173,52 +481,11 @@ impl<'a> TypeFolder for SubstFolder<'a> { let t1 = match ty::get(t).sty { ty::ty_param(p) => { - // FIXME -- This...really shouldn't happen. We should - // 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::mk_err() - } + check(self, t, self.substs.types.opt_get(p.space, p.idx)) } - 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) } - _ => ty_fold::super_fold_ty(self, t) }; assert_eq!(depth + 1, self.ty_stack_depth); @@ -227,6 +494,24 @@ impl<'a> TypeFolder for SubstFolder<'a> { 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()); + } + } + } } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 9cebc79171f5f..3e15d5a1a615a 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -457,11 +457,11 @@ pub fn get_res_dtor(ccx: &CrateContext, did }; - if !substs.tps.is_empty() || !substs.self_ty.is_none() { + if !substs.types.is_empty() { assert_eq!(did.krate, ast::LOCAL_CRATE); 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 } else if did.krate == ast::LOCAL_CRATE { diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 2f4b086b5b0e1..8b484e90898c9 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -23,7 +23,7 @@ use lib::llvm::llvm; use metadata::csearch; use middle::def; use middle::subst; -use middle::subst::Subst; +use middle::subst::{Subst, VecPerParamSpace}; use middle::trans::base; use middle::trans::base::*; 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, impl_id: ast::DefId, - method: &ty::Method, substs: &subst::Substs, 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 let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id); @@ -211,32 +209,30 @@ fn resolve_default_method_vtables(bcx: &Block, // trait_vtables under. let param_substs = param_substs { substs: (*substs).clone(), - vtables: impl_vtables.clone(), - self_vtables: None + vtables: impl_vtables.clone() }; let mut param_vtables = resolve_vtables_under_param_substs( - bcx.tcx(), ¶m_substs, impl_res.trait_vtables.as_slice()); + bcx.tcx(), ¶m_substs, &impl_res); // Now we pull any vtables for parameters on the actual method. - let num_method_vtables = method.generics.type_param_defs().len(); - let num_impl_type_parameters = impl_vtables.len() - num_method_vtables; - param_vtables.push_all(impl_vtables.tailn(num_impl_type_parameters)); - - let self_vtables = resolve_param_vtables_under_param_substs( - bcx.tcx(), ¶m_substs, impl_res.self_vtables.as_slice()); + param_vtables + .get_mut_vec(subst::FnSpace) + .push_all( + impl_vtables.get_vec(subst::FnSpace).as_slice()); - (param_vtables, self_vtables) + param_vtables } pub fn trans_fn_ref_with_vtables( - bcx: &Block, // - def_id: ast::DefId, // def id of fn - node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A - substs: subst::Substs, // values for fn's ty params - vtables: typeck::vtable_res) // vtables for the call - -> ValueRef { + bcx: &Block, // + def_id: ast::DefId, // def id of fn + node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A + substs: subst::Substs, // values for fn's ty params + vtables: typeck::vtable_res) // vtables for the call + -> ValueRef +{ /*! * Translates a reference to a fn/method item, monomorphizing and * inlining as it goes. @@ -264,7 +260,7 @@ pub fn trans_fn_ref_with_vtables( substs.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) 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 modify the def_id and our substs in order to monomorphize // 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) { - None => (false, def_id, substs, None, vtables), + None => (false, def_id, substs, vtables), Some(source_id) => { // There are two relevant substitutions when compiling // default methods. First, there is the substitution for @@ -305,7 +301,7 @@ pub fn trans_fn_ref_with_vtables( // Compute the first substitution let first_subst = make_substs_for_receiver_types( - tcx, impl_id, &*trait_ref, &*method); + tcx, &*trait_ref, &*method); // And compose them 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), vtables.repr(tcx)); - let (param_vtables, self_vtables) = - resolve_default_method_vtables(bcx, impl_id, - &*method, &substs, vtables); + let param_vtables = + resolve_default_method_vtables(bcx, impl_id, &substs, vtables); debug!("trans_fn_with_vtables - default method: \ - self_vtable = {}, param_vtables = {}", - self_vtables.repr(tcx), param_vtables.repr(tcx)); + param_vtables = {}", + param_vtables.repr(tcx)); - (true, source_id, - new_substs, Some(self_vtables), param_vtables) + (true, source_id, new_substs, 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 that is inlined from a different crate, we want to reemit the // 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 } else if def_id.krate == ast::LOCAL_CRATE { let map_node = session::expect( @@ -375,8 +369,7 @@ pub fn trans_fn_ref_with_vtables( let (val, must_cast) = monomorphize::monomorphic_fn(ccx, def_id, &substs, - vtables, self_vtables, - opt_ref_id); + vtables, opt_ref_id); let mut val = val; if must_cast && node != ExprId(0) { // Monotype of the REFERENCE to the function (type params @@ -498,7 +491,7 @@ pub fn trans_lang_call<'a>( did, 0, subst::Substs::empty(), - Vec::new()) + VecPerParamSpace::empty()) }, ArgVals(args), dest) diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 9bd6b8ed3618c..565ec7d824710 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -181,25 +181,18 @@ pub type ExternMap = HashMap; pub struct param_substs { pub substs: subst::Substs, pub vtables: typeck::vtable_res, - pub self_vtables: Option } impl param_substs { pub fn empty() -> param_substs { param_substs { substs: subst::Substs::trans_empty(), - vtables: Vec::new(), - self_vtables: None + vtables: subst::VecPerParamSpace::empty(), } } pub fn validate(&self) { - for t in self.substs.tps.iter() { - assert!(!ty::type_needs_infer(*t)); - } - for t in self.substs.self_ty.iter() { - assert!(!ty::type_needs_infer(*t)); - } + assert!(self.substs.types.all(|t| !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( 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) -> typeck::vtable_res { bcx.tcx().vtable_map.borrow().find(&id).map(|vts| { - resolve_vtables_in_fn_ctxt(bcx.fcx, vts.as_slice()) - }).unwrap_or_else(|| Vec::new()) + resolve_vtables_in_fn_ctxt(bcx.fcx, vts) + }).unwrap_or_else(|| subst::VecPerParamSpace::empty()) } // Apply the typaram substitutions in the FunctionContext to some // vtables. This should eliminate any vtable_params. pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, - vts: &[typeck::vtable_param_res]) + vts: &typeck::vtable_res) -> typeck::vtable_res { resolve_vtables_under_param_substs(fcx.ccx.tcx(), 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, param_substs: ¶m_substs, - vts: &[typeck::vtable_param_res]) - -> typeck::vtable_res { - vts.iter().map(|ds| { - resolve_param_vtables_under_param_substs(tcx, - param_substs, - ds.as_slice()) - }).collect() -} - -pub fn resolve_param_vtables_under_param_substs( - tcx: &ty::ctxt, - param_substs: ¶m_substs, - ds: &[typeck::vtable_origin]) - -> typeck::vtable_param_res { + vts: &typeck::vtable_res) + -> typeck::vtable_res +{ + vts.map(|ds| { + resolve_param_vtables_under_param_substs(tcx, + param_substs, + ds) + }) +} + +pub fn resolve_param_vtables_under_param_substs(tcx: &ty::ctxt, + param_substs: ¶m_substs, + ds: &typeck::vtable_param_res) + -> typeck::vtable_param_res +{ ds.iter().map(|d| { resolve_vtable_under_param_substs(tcx, param_substs, @@ -794,17 +788,20 @@ pub fn resolve_param_vtables_under_param_substs( pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt, param_substs: ¶m_substs, vt: &typeck::vtable_origin) - -> typeck::vtable_origin { + -> typeck::vtable_origin +{ match *vt { typeck::vtable_static(trait_id, ref vtable_substs, ref sub) => { let vtable_substs = vtable_substs.substp(tcx, param_substs); typeck::vtable_static( - trait_id, vtable_substs, - resolve_vtables_under_param_substs(tcx, param_substs, sub.as_slice())) + trait_id, + vtable_substs, + resolve_vtables_under_param_substs(tcx, param_substs, sub)) } typeck::vtable_param(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={})", n_param, n_bound, ps.repr(tcx)); - let param_bounds = match n_param { - typeck::param_self => ps.self_vtables.as_ref().expect("self vtables missing"), - typeck::param_numbered(n) => { - ps.vtables.get(n) - } - }; + let param_bounds = ps.vtables.get(n_param.space, + n_param.index); param_bounds.get(n_bound).clone() } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 0b10db56cc426..b5a002fd8247e 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -520,10 +520,11 @@ impl TypeMap { // 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('<'); - 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_as_string(param_type_id); output.push_str(param_type_id.as_slice()); @@ -1209,7 +1210,7 @@ pub fn create_function_debug_context(cx: &CrateContext, file_metadata: DIFile, name_to_append_suffix_to: &mut String) -> DIArray { - let self_type = param_substs.substs.self_ty; + let self_type = param_substs.substs.self_ty(); // Only true for static default methods: let has_self_type = self_type.is_some(); @@ -1263,7 +1264,7 @@ pub fn create_function_debug_context(cx: &CrateContext, } // Handle other generic parameters - let actual_types = ¶m_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() { let actual_type = *actual_types.get(index); // 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 mut name = ppaux::trait_store_to_str(cx.tcx(), trait_store); name.push_str(ident_string.get()); + // Add type and region parameters - let name = ppaux::parameterized(cx.tcx(), - name.as_slice(), - &substs.regions, - substs.tps.as_slice(), - def_id, - true); + let trait_def = ty::lookup_trait_def(cx.tcx(), def_id); + let name = ppaux::parameterized(cx.tcx(), name.as_slice(), + substs, &trait_def.generics); let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id); diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index 55ea4a3a0bb1e..095645f4d6b67 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -118,18 +118,18 @@ pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) ccx.external.borrow_mut().insert(fn_id, Some(mth.id)); ccx.external_srcs.borrow_mut().insert(mth.id, fn_id); - ccx.stats.n_inlines.set(ccx.stats.n_inlines.get() + 1); + ccx.stats.n_inlines.set(ccx.stats.n_inlines.get() + 1); - // If this is a default method, we can't look up the - // impl type. But we aren't going to translate anyways, so don't. - if is_provided { return local_def(mth.id); } + // If this is a default method, we can't look up the + // impl type. But we aren't going to translate anyways, so don't. + if is_provided { return local_def(mth.id); } let impl_tpt = ty::lookup_item_type(ccx.tcx(), impl_did); - let num_type_params = - impl_tpt.generics.type_param_defs().len() + - mth.generics.ty_params.len(); + let unparameterized = + impl_tpt.generics.types.is_empty() && + mth.generics.ty_params.is_empty(); - if num_type_params == 0 { + if unparameterized { let llfn = get_item_val(ccx, mth.id); trans_fn(ccx, &*mth.decl, &*mth.body, llfn, ¶m_substs::empty(), mth.id, []); diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index 1edd802f1444e..5f37365e74353 100644 --- a/src/librustc/middle/trans/intrinsic.rs +++ b/src/librustc/middle/trans/intrinsic.rs @@ -14,6 +14,7 @@ use arena::TypedArena; use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg}; use lib::llvm::{ValueRef, Pointer, Array, Struct}; use lib; +use middle::subst::FnSpace; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::common::*; @@ -295,7 +296,7 @@ pub fn trans_intrinsic(ccx: &CrateContext, RetVoid(bcx); } "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); 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 // intrinsics, there are no argument cleanups to // 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 src = Datum {val: get_param(decl, first_real_arg + 1u), ty: tp_ty, @@ -314,17 +315,17 @@ pub fn trans_intrinsic(ccx: &CrateContext, RetVoid(bcx); } "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); Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty) as uint)); } "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); Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty) as uint)); } "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); glue::lazily_emit_visit_glue(ccx, &*static_ti); @@ -339,7 +340,7 @@ pub fn trans_intrinsic(ccx: &CrateContext, "type_id" => { let hash = ty::hash_crate_independent( ccx.tcx(), - *substs.substs.tps.get(0), + *substs.substs.types.get(FnSpace, 0), &ccx.link_meta.crate_hash); // NB: This needs to be kept in lockstep with the TypeId struct in // libstd/unstable/intrinsics.rs @@ -354,7 +355,7 @@ pub fn trans_intrinsic(ccx: &CrateContext, } } "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); match bcx.fcx.llretptr.get() { Some(ptr) => { Store(bcx, C_null(lltp_ty), ptr); RetVoid(bcx); } @@ -364,7 +365,7 @@ pub fn trans_intrinsic(ccx: &CrateContext, } "uninit" => { // 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) { unsafe { Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref())); @@ -377,8 +378,8 @@ pub fn trans_intrinsic(ccx: &CrateContext, RetVoid(bcx); } "transmute" => { - let (in_type, out_type) = (*substs.substs.tps.get(0), - *substs.substs.tps.get(1)); + let (in_type, out_type) = (*substs.substs.types.get(FnSpace, 0), + *substs.substs.types.get(FnSpace, 1)); let llintype = type_of::type_of(ccx, in_type); let llouttype = type_of::type_of(ccx, out_type); @@ -447,11 +448,11 @@ pub fn trans_intrinsic(ccx: &CrateContext, } } "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))); } "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())); } "visit_tydesc" => { @@ -468,19 +469,26 @@ pub fn trans_intrinsic(ccx: &CrateContext, Ret(bcx, lladdr); } "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_intrinsic(bcx, true, false, *substs.substs.tps.get(0)) + copy_intrinsic(bcx, true, false, *substs.substs.types.get(FnSpace, 0)) } "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" => - copy_intrinsic(bcx, false, true, *substs.substs.tps.get(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_nonoverlapping_memory" => { + copy_intrinsic(bcx, false, true, *substs.substs.types.get(FnSpace, 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"), "ctlz16" => count_zeros_intrinsic(bcx, "llvm.ctlz.i16"), diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 59387c549db61..bde48b94473e6 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -155,22 +155,6 @@ pub fn trans_static_method_callee(bcx: &Block, ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id); - // When we translate a static fn defined in a trait like: - // - // trait Trait { - // fn foo(...) {...} - // } - // - // this winds up being translated as something like: - // - // fn foo,M1...Mn>(...) {...} - // - // So when we see a call to this function foo, we have to figure - // out which impl the `Trait` 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 { match bcx.tcx().map.get(method_id.node) { 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)); let vtable_key = MethodCall::expr(expr_id); - let vtbls = resolve_vtables_in_fn_ctxt(bcx.fcx, ccx.tcx.vtable_map.borrow() - .get(&vtable_key).as_slice()); + let vtbls = resolve_vtables_in_fn_ctxt( + bcx.fcx, + ccx.tcx.vtable_map.borrow().get(&vtable_key)); - match vtbls.move_iter().nth(bound_index).unwrap().move_iter().nth(0).unwrap() { - typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => { - assert!(rcvr_substs.tps.iter().all(|t| !ty::type_needs_infer(*t))); + match *vtbls.get_self().unwrap().get(0) { + typeck::vtable_static(impl_did, ref rcvr_substs, ref rcvr_origins) => { + assert!(rcvr_substs.types.all(|t| !ty::type_needs_infer(*t))); let mth_id = method_with_name(ccx, impl_did, mname); let (callee_substs, callee_origins) = combine_impl_and_methods_tps( - bcx, mth_id, ExprId(expr_id), - rcvr_substs, rcvr_origins); + bcx, ExprId(expr_id), + (*rcvr_substs).clone(), (*rcvr_origins).clone()); let llfn = trans_fn_ref_with_vtables(bcx, mth_id, ExprId(expr_id), callee_substs, @@ -252,8 +237,7 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>, // those from the impl and those from the method: let (callee_substs, callee_origins) = combine_impl_and_methods_tps( - bcx, mth_id, MethodCall(method_call), - rcvr_substs, rcvr_origins); + bcx, MethodCall(method_call), rcvr_substs, rcvr_origins); // translate the function 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) } } 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, - mth_did: ast::DefId, node: ExprOrMethodCall, rcvr_substs: subst::Substs, rcvr_origins: typeck::vtable_res) @@ -295,38 +283,33 @@ fn combine_impl_and_methods_tps(bcx: &Block, */ 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 { ExprId(id) => MethodCall::expr(id), MethodCall(method_call) => method_call }; - let mut vtables = rcvr_origins; - let vt = node_vtables(bcx, vtable_key); - let start = vt.len() - n_m_tps; - vtables.extend(vt.move_iter().skip(start)); + let node_substs = node_id_substs(bcx, node); + let node_vtables = node_vtables(bcx, vtable_key); + + 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 { - tps: tps, 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) } @@ -426,7 +409,12 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>, fn get_vtable(bcx: &Block, self_ty: ty::t, 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 _icx = push_ctxt("meth::get_vtable"); @@ -503,8 +491,9 @@ fn emit_vtable_methods(bcx: &Block, debug!("(making impl vtable) emitting method {} at subst {}", m.repr(tcx), substs.repr(tcx)); - if m.generics.has_type_params() || - ty::type_has_self(ty::mk_bare_fn(tcx, m.fty.clone())) { + if m.generics.has_type_params(subst::FnSpace) || + ty::type_has_self(ty::mk_bare_fn(tcx, m.fty.clone())) + { debug!("(making impl vtable) method has self or type params: {}", token::get_ident(ident)); 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(); resolve_param_vtables_under_param_substs(ccx.tcx(), 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 llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]); diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 0315815266ee5..125fa6828c556 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -33,32 +33,27 @@ pub fn monomorphic_fn(ccx: &CrateContext, fn_id: ast::DefId, real_substs: &subst::Substs, vtables: typeck::vtable_res, - self_vtables: Option, ref_id: Option) -> (ValueRef, bool) { debug!("monomorphic_fn(\ fn_id={}, \ real_substs={}, \ vtables={}, \ - self_vtable={}, \ ref_id={:?})", fn_id.repr(ccx.tcx()), real_substs.repr(ccx.tcx()), vtables.repr(ccx.tcx()), - self_vtables.repr(ccx.tcx()), 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) })); let _icx = push_ctxt("monomorphic_fn"); - let substs_iter = real_substs.self_ty.iter().chain(real_substs.tps.iter()); - let param_ids: Vec = substs_iter.map(|t| *t).collect(); let hash_id = MonoId { def: fn_id, - params: param_ids + params: real_substs.types.clone() }; match ccx.monomorphized.borrow().find(&hash_id) { @@ -73,7 +68,6 @@ pub fn monomorphic_fn(ccx: &CrateContext, let psubsts = param_substs { substs: (*real_substs).clone(), vtables: vtables, - self_vtables: self_vtables }; debug!("monomorphic_fn(\ @@ -87,10 +81,6 @@ pub fn monomorphic_fn(ccx: &CrateContext, let tpt = ty::lookup_item_type(ccx.tcx(), fn_id); 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( ccx.sess(), 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); } } - 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())); - let mono_ty = match is_static_provided { - 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) - } - }; + let mono_ty = llitem_ty.subst(ccx.tcx(), real_substs); ccx.stats.n_monos.set(ccx.stats.n_monos.get() + 1); @@ -306,7 +252,7 @@ pub struct MonoParamId { #[deriving(PartialEq, Eq, Hash)] pub struct MonoId { pub def: ast::DefId, - pub params: Vec + pub params: subst::VecPerParamSpace } 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, _) => { MonoId { def: impl_id, - params: substs.tps.iter().map(|subst| *subst).collect() + params: substs.types.clone() } } diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 3b469a1d11063..f67fc57bb4407 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -366,7 +366,6 @@ impl<'a, 'b> Reflector<'a, 'b> { let extra = vec!(self.c_uint(p.idx)); self.visit("param", extra.as_slice()) } - ty::ty_self(..) => self.leaf("self") } } diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 3ba3954e44574..4701a9e322500 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -15,7 +15,6 @@ use middle::trans::adt; use middle::trans::common::*; use middle::trans::foreign; use middle::ty; -use util::ppaux; use util::ppaux::Repr; 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 => { cx.sess().bug(format!("fictitious type {:?} in sizing_type_of()", 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 // of the enum's variants refers to the enum itself. 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()) } 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 // infinite recursion with recursive struct types. let repr = adt::represent_type(cx, t); - let name = llvm_type_name(cx, - a_struct, - did, - substs.tps.as_slice()); + let tps = substs.types.get_vec(subst::TypeSpace); + let name = llvm_type_name(cx, a_struct, did, tps); adt::incomplete_type_of(cx, &*repr, name.as_slice()) } } 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_self(..) => cx.sess().unimpl("type_of with ty_self"), ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"), ty::ty_param(..) => cx.sess().bug("type_of with ty_param"), 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, what: named_ty, did: ast::DefId, - tps: &[ty::t]) - -> String { + tps: &Vec) + -> String +{ let name = match what { a_struct => { "struct" } an_enum => { "enum" } }; - let tstr = ppaux::parameterized(cx.tcx(), - ty::item_path_str(cx.tcx(), - did).as_slice(), - &subst::ErasedRegions, - tps, - did, - false); + + let base = ty::item_path_str(cx.tcx(), did); + let strings: Vec = tps.iter().map(|t| t.repr(cx.tcx())).collect(); + let tstr = format!("{}<{}>", base, strings); if did.krate == 0 { format!("{}.{}", name, tstr) } else { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 2a0873e327bc2..e3d94c73bb4e9 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -24,7 +24,7 @@ use middle::freevars; use middle::resolve; use middle::resolve_lifetime; use middle::subst; -use middle::subst::{Subst, Substs}; +use middle::subst::{Subst, Substs, VecPerParamSpace}; use middle::ty; use middle::typeck; use middle::typeck::MethodCall; @@ -58,7 +58,6 @@ use syntax::codemap::Span; use syntax::parse::token; use syntax::parse::token::InternedString; use syntax::{ast, ast_map}; -use syntax::owned_slice::OwnedSlice; use syntax::util::small_vector::SmallVector; use std::collections::enum_set::{EnumSet, CLike}; @@ -190,9 +189,8 @@ pub enum ast_ty_to_ty_cache_entry { #[deriving(Clone, PartialEq, Decodable, Encodable)] pub struct ItemVariances { - pub self_param: Option, - pub type_params: OwnedSlice, - pub region_params: OwnedSlice + pub types: VecPerParamSpace, + pub regions: VecPerParamSpace, } #[deriving(Clone, PartialEq, Decodable, Encodable, Show)] @@ -455,7 +453,8 @@ pub struct FnSig { } #[deriving(Clone, PartialEq, Eq, Hash)] -pub struct param_ty { +pub struct ParamTy { + pub space: subst::ParamSpace, pub idx: uint, pub def_id: DefId } @@ -466,7 +465,10 @@ pub enum Region { // Region bound in a type or fn declaration which will be // substituted 'early' -- that is, at the same time when type // parameters are substituted. - ReEarlyBound(/* param id */ ast::NodeId, /*index*/ uint, ast::Name), + ReEarlyBound(/* param id */ ast::NodeId, + subst::ParamSpace, + /*index*/ uint, + ast::Name), // Region bound in a function scope, which will be substituted when the // function is called. The first argument must be the `binder_id` of @@ -713,10 +715,7 @@ pub enum sty { ty_struct(DefId, Substs), ty_tup(Vec), - ty_param(param_ty), // type parameter - ty_self(DefId), /* special, implicit `self` type parameter; - * def_id is the id of the trait */ - + ty_param(ParamTy), // type parameter ty_infer(InferTy), // something used only during inference/typeck ty_err, // Also only used during inference/typeck, to represent // the type of an erroneous expression (helps cut down @@ -734,7 +733,7 @@ pub struct TyTrait { #[deriving(PartialEq, Eq, Hash)] pub struct TraitRef { pub def_id: DefId, - pub substs: Substs + pub substs: Substs, } #[deriving(Clone, PartialEq)] @@ -964,6 +963,8 @@ impl fmt::Show for IntVarValue { pub struct TypeParameterDef { pub ident: ast::Ident, pub def_id: ast::DefId, + pub space: subst::ParamSpace, + pub index: uint, pub bounds: Rc, pub default: Option } @@ -972,29 +973,26 @@ pub struct TypeParameterDef { pub struct RegionParameterDef { pub name: ast::Name, pub def_id: ast::DefId, + pub space: subst::ParamSpace, + pub index: uint, } -/// Information about the type/lifetime parameters associated with an item. -/// Analogous to ast::Generics. +/// Information about the type/lifetime parameters associated with an +/// item or method. Analogous to ast::Generics. #[deriving(Clone)] pub struct Generics { - /// List of type parameters declared on the item. - pub type_param_defs: Rc>, - - /// List of region parameters declared on the item. - /// For a fn or method, only includes *early-bound* lifetimes. - pub region_param_defs: Rc>, + pub types: VecPerParamSpace, + pub regions: VecPerParamSpace, } impl Generics { - pub fn has_type_params(&self) -> bool { - !self.type_param_defs.is_empty() - } - pub fn type_param_defs<'a>(&'a self) -> &'a [TypeParameterDef] { - self.type_param_defs.as_slice() + pub fn empty() -> Generics { + Generics { types: VecPerParamSpace::empty(), + regions: VecPerParamSpace::empty() } } - pub fn region_param_defs<'a>(&'a self) -> &'a [RegionParameterDef] { - self.region_param_defs.as_slice() + + pub fn has_type_params(&self, space: subst::ParamSpace) -> bool { + !self.types.get_vec(space).is_empty() } } @@ -1018,11 +1016,8 @@ pub struct ParameterEnvironment { /// parameters in the same way, this only has an affect on regions. pub free_substs: Substs, - /// Bound on the Self parameter - pub self_param_bound: Option>, - - /// Bounds on each numbered type parameter - pub type_param_bounds: Vec, + /// Bounds on the various type parameters + pub bounds: VecPerParamSpace, } /// A polytype. @@ -1162,7 +1157,10 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { } fn sflags(substs: &Substs) -> uint { 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 { subst::ErasedRegions => {} subst::NonerasedRegions(ref regions) => { @@ -1185,9 +1183,14 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { // so we're doing it this way. &ty_bot => flags |= has_ty_bot 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_self(_) => flags |= has_self as uint, &ty_enum(_, ref substs) | &ty_struct(_, ref 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_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_self_type(cx: &ctxt, did: ast::DefId) -> t { + mk_param(cx, subst::SelfSpace, 0, did) +} -pub fn mk_param(cx: &ctxt, n: uint, k: DefId) -> t { - mk_t(cx, ty_param(param_ty { idx: n, def_id: k })) +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|) { @@ -1471,15 +1480,17 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) { } match get(ty).sty { ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_str | ty_self(_) | - ty_infer(_) | ty_param(_) | ty_err => {} + ty_str | ty_infer(_) | ty_param(_) | ty_err => { + } ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f), ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => { maybe_walk_ty(tm.ty, f); } ty_enum(_, ref substs) | ty_struct(_, 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_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 { - tref.substs.self_ty.iter().any(|&t| type_is_error(t)) || - tref.substs.tps.iter().any(|&t| type_is_error(t)) + tref.substs.types.any(|&t| type_is_error(t)) } 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 { match get(ty).sty { - ty_self(..) => true, + ty_param(ref p) => p.space == subst::SelfSpace, _ => false } } @@ -2103,16 +2113,6 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { 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(_) => { // This occurs during coherence, but shouldn't occur at other // times. @@ -2292,7 +2292,6 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool { ty_infer(_) | ty_err | ty_param(_) | - ty_self(_) | ty_vec(_, None) => { 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 // doesn't provide type parameter substitutions. 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) - -> Rc> { + -> VecPerParamSpace { match origin { typeck::MethodStatic(did) => { - // n.b.: When we encode impl methods, the bounds - // that we encode include both the impl bounds - // and then the method bounds themselves... - ty::lookup_item_type(tcx, did).generics.type_param_defs + ty::lookup_item_type(tcx, did).generics.types.clone() } - typeck::MethodParam(typeck::MethodParam { - trait_id: trt_id, - method_num: n_mth, ..}) | - typeck::MethodObject(typeck::MethodObject { - trait_id: trt_id, - method_num: n_mth, ..}) => { - // ...trait methods bounds, in contrast, include only the - // 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())) + typeck::MethodParam(typeck::MethodParam{trait_id: trt_id, + method_num: n_mth, ..}) | + typeck::MethodObject(typeck::MethodObject{trait_id: trt_id, + method_num: n_mth, ..}) => { + ty::trait_method(tcx, trt_id, n_mth).generics.types.clone() } } } @@ -3176,7 +3172,7 @@ pub fn method_idx(id: ast::Ident, meths: &[Rc]) -> Option { /// Returns a vector containing the indices of all type parameters that appear /// in `ty`. The vector may contain duplicates. Probably should be converted /// to a bitset or some other representation. -pub fn param_tys_in_type(ty: t) -> Vec { +pub fn param_tys_in_type(ty: t) -> Vec { let mut rslt = Vec::new(); walk_ty(ty, |ty| { 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(IntVar(_)) => "integral variable".to_string(), ty_infer(FloatVar(_)) => "floating-point variable".to_string(), - ty_param(_) => "type parameter".to_string(), - ty_self(_) => "self".to_string(), + ty_param(ref p) => { + if p.space == subst::SelfSpace { + "Self".to_string() + } else { + "type parameter".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, did: ast::DefId) - -> typeck::impl_res { + -> typeck::vtable_res { lookup_locally_or_in_crate_store( "impl_vtables", did, &mut *cx.impl_vtables.borrow_mut(), || csearch::get_impl_vtables(cx, did) ) @@ -4103,8 +4104,7 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t { substs: &subst::Substs) -> subst::Substs { subst::Substs { regions: subst::ErasedRegions, - self_ty: substs.self_ty.fold_with(self), - tps: substs.tps.fold_with(self) } + types: substs.types.fold_with(self) } } fn fold_sig(&mut self, @@ -4252,11 +4252,7 @@ pub fn visitor_object_ty(tcx: &ctxt, Ok(id) => id, Err(s) => { return Err(s); } }; - let substs = Substs { - regions: subst::NonerasedRegions(Vec::new()), - self_ty: None, - tps: Vec::new() - }; + let substs = Substs::empty(); let trait_ref = Rc::new(TraitRef { def_id: trait_lang_item, substs: substs }); Ok((trait_ref.clone(), mk_trait(tcx, @@ -4582,10 +4578,6 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { hash!(p.idx); did(&mut state, p.def_id); } - ty_self(d) => { - byte!(21); - did(&mut state, d); - } ty_infer(_) => unreachable!(), ty_err => byte!(23), } @@ -4607,11 +4599,7 @@ impl Variance { pub fn construct_parameter_environment( tcx: &ctxt, - self_bound: Option>, - item_type_params: &[TypeParameterDef], - method_type_params: &[TypeParameterDef], - item_region_params: &[RegionParameterDef], - method_region_params: &[RegionParameterDef], + generics: &ty::Generics, free_id: ast::NodeId) -> ParameterEnvironment { @@ -4621,75 +4609,76 @@ pub fn construct_parameter_environment( // Construct the free substs. // - // map Self => Self - let self_ty = self_bound.as_ref().map(|t| ty::mk_self(tcx, t.def_id)); - - // map A => A - let num_item_type_params = item_type_params.len(); - let num_method_type_params = method_type_params.len(); - let num_type_params = num_item_type_params + num_method_type_params; - let type_params = Vec::from_fn(num_type_params, |i| { - let def_id = if i < num_item_type_params { - item_type_params[i].def_id - } else { - method_type_params[i - num_item_type_params].def_id - }; - - ty::mk_param(tcx, i, def_id) - }); + // map T => T + let mut types = VecPerParamSpace::empty(); + for &space in subst::ParamSpace::all().iter() { + push_types_from_defs(tcx, &mut types, space, + generics.types.get_vec(space)); + } // map bound 'a => free 'a - let region_params = { - fn push_region_params(mut accum: Vec, - free_id: ast::NodeId, - region_params: &[RegionParameterDef]) - -> Vec { - 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 mut regions = VecPerParamSpace::empty(); + for &space in subst::ParamSpace::all().iter() { + push_region_params(&mut regions, space, free_id, + generics.regions.get_vec(space)); + } let free_substs = Substs { - self_ty: self_ty, - tps: type_params, - regions: subst::NonerasedRegions(region_params) + types: types, + regions: subst::NonerasedRegions(regions) }; // // Compute the bounds on Self and the type parameters. // - let self_bound_substd = self_bound.map(|b| b.subst(tcx, &free_substs)); - let type_param_bounds_substd = Vec::from_fn(num_type_params, |i| { - if i < num_item_type_params { - (*item_type_params[i].bounds).subst(tcx, &free_substs) - } else { - let j = i - num_item_type_params; - (*method_type_params[j].bounds).subst(tcx, &free_substs) - } - }); + let mut bounds = VecPerParamSpace::empty(); + for &space in subst::ParamSpace::all().iter() { + push_bounds_from_defs(tcx, &mut bounds, space, &free_substs, + generics.types.get_vec(space)); + } debug!("construct_parameter_environment: free_id={} \ free_subst={} \ - self_param_bound={} \ - type_param_bound={}", + bounds={}", free_id, free_substs.repr(tcx), - self_bound_substd.repr(tcx), - type_param_bounds_substd.repr(tcx)); + bounds.repr(tcx)); - ty::ParameterEnvironment { + return ty::ParameterEnvironment { free_substs: free_substs, - self_param_bound: self_bound_substd, - type_param_bounds: type_param_bounds_substd, + bounds: bounds + }; + + fn push_region_params(regions: &mut VecPerParamSpace, + space: subst::ParamSpace, + free_id: ast::NodeId, + region_params: &Vec) + { + 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, + space: subst::ParamSpace, + defs: &Vec) { + 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, + space: subst::ParamSpace, + free_substs: &subst::Substs, + defs: &Vec) { + for def in defs.iter() { + let b = (*def.bounds).subst(tcx, free_substs); + bounds.push(space, b); + } } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index e8f043b5f8695..e5fbe9df98f22 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -11,6 +11,7 @@ // Generalized type folding mechanism. use middle::subst; +use middle::subst::VecPerParamSpace; use middle::ty; use middle::typeck; use std::rc::Rc; @@ -127,6 +128,12 @@ impl TypeFoldable for OwnedSlice { } } +impl TypeFoldable for VecPerParamSpace { + fn fold_with(&self, folder: &mut F) -> VecPerParamSpace { + self.map(|t| t.fold_with(folder)) + } +} + impl TypeFoldable for ty::TraitStore { fn fold_with(&self, folder: &mut F) -> ty::TraitStore { folder.fold_trait_store(*self) @@ -212,15 +219,9 @@ impl TypeFoldable for typeck::vtable_origin { typeck::vtable_param(n, b) => { typeck::vtable_param(n, b) } - } - } -} - -impl TypeFoldable for typeck::impl_res { - fn fold_with(&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), + typeck::vtable_error => { + typeck::vtable_error + } } } } @@ -245,6 +246,8 @@ impl TypeFoldable for ty::TypeParameterDef { ty::TypeParameterDef { ident: self.ident, def_id: self.def_id, + space: self.space, + index: self.index, bounds: self.bounds.fold_with(folder), default: self.default.fold_with(folder), } @@ -260,8 +263,8 @@ impl TypeFoldable for ty::RegionParameterDef { impl TypeFoldable for ty::Generics { fn fold_with(&self, folder: &mut F) -> ty::Generics { ty::Generics { - type_param_defs: self.type_param_defs.fold_with(folder), - region_param_defs: self.region_param_defs.fold_with(folder) + types: self.types.fold_with(folder), + regions: self.regions.fold_with(folder), } } } @@ -291,8 +294,7 @@ pub fn super_fold_substs(this: &mut T, }; subst::Substs { regions: regions, - self_ty: substs.self_ty.fold_with(this), - tps: substs.tps.fold_with(this) } + types: substs.types.fold_with(this) } } pub fn super_fold_sig(this: &mut T, @@ -390,7 +392,7 @@ pub fn super_fold_sty(this: &mut T, 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_err | ty::ty_infer(_) | - ty::ty_param(..) | ty::ty_self(_) => { + ty::ty_param(..) => { (*sty).clone() } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 7db23ee264def..83c5be238168a 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -52,6 +52,7 @@ use middle::const_eval; use middle::def; use middle::lang_items::FnMutTraitLangItem; +use rl = middle::resolve_lifetime; use middle::subst::{Subst, Substs}; use middle::subst; 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"); } - Some(&ast::DefStaticRegion) => { + Some(&rl::DefStaticRegion) => { 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), lifetime.name)) } - Some(&ast::DefEarlyBoundRegion(index, id)) => { - ty::ReEarlyBound(id, index, lifetime.name) + Some(&rl::DefEarlyBoundRegion(space, index, id)) => { + ty::ReEarlyBound(id, space, index, lifetime.name) } - Some(&ast::DefFreeRegion(scope_id, id)) => { + Some(&rl::DefFreeRegion(scope_id, id)) => { ty::ReFree(ty::FreeRegion { scope_id: scope_id, bound_region: ty::BrNamed(ast_util::local_def(id), @@ -163,10 +164,21 @@ fn ast_path_substs( 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 // region with the current anon region binding (in other words, // 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 regions = if expected_num_region_params == supplied_num_region_params { path.segments.last().unwrap().lifetimes.iter().map( @@ -192,9 +204,10 @@ fn ast_path_substs( }; // 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 formal_ty_param_count = decl_generics.type_param_defs().len(); - let required_ty_param_count = decl_generics.type_param_defs().iter() + let formal_ty_param_count = ty_param_defs.len(); + let required_ty_param_count = ty_param_defs.iter() .take_while(|x| x.default.is_none()) .count(); if supplied_ty_param_count < required_ty_param_count { @@ -233,37 +246,29 @@ fn ast_path_substs( .map(|a_t| ast_ty_to_ty(this, rscope, &**a_t)) .collect(); - let mut substs = subst::Substs { - regions: subst::NonerasedRegions(regions), - self_ty: self_ty, - tps: tps - }; + let mut substs = subst::Substs::new_type(tps, regions); - for param in decl_generics.type_param_defs() - .slice_from(supplied_ty_param_count).iter() { - let ty = param.default.unwrap().subst_spanned(tcx, &substs, Some(path.span)); - substs.tps.push(ty); + match self_ty { + None => { + // If no self-type is provided, it's still possible that + // 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); + } } - substs -} - -pub fn ast_path_to_substs_and_ty( - 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); + 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); + } - 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 } + substs } pub fn ast_path_to_trait_ref( @@ -286,12 +291,14 @@ pub fn ast_path_to_ty( path: &ast::Path) -> ty_param_substs_and_ty { - // Look up the polytype of the item and then substitute the provided types - // for any type/region parameters. - let ty::ty_param_substs_and_ty { - substs: substs, - ty: ty - } = ast_path_to_substs_and_ty(this, rscope, did, path); + 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 } } @@ -519,10 +526,12 @@ fn ast_ty_to_mt(this: &AC, pub fn trait_ref_for_unboxed_function( - this: &AC, - rscope: &RS, - unboxed_function: &ast::UnboxedFnTy) - -> ty::TraitRef { + this: &AC, + rscope: &RS, + unboxed_function: &ast::UnboxedFnTy, + self_ty: Option) + -> ty::TraitRef +{ let fn_mut_trait_did = this.tcx() .lang_items .require(FnMutTraitLangItem) @@ -538,11 +547,14 @@ pub fn trait_ref_for_unboxed_function substs.types.push(subst::SelfSpace, s), + None => () + } + ty::TraitRef { def_id: fn_mut_trait_did, substs: substs, @@ -590,7 +602,8 @@ fn mk_pointer( def::DefTy(did) | def::DefStruct(did) => { 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); - ty::mk_param(tcx, n, id) + ty::mk_param(tcx, space, n, id) } def::DefSelfTy(id) => { // n.b.: resolve guarantees that the this type only appears in a @@ -811,7 +824,7 @@ pub fn ast_ty_to_ty( // substs check_path_args(tcx, path, NO_TPS | NO_REGIONS); let did = ast_util::local_def(id); - ty::mk_self(tcx, did) + ty::mk_self_type(tcx, did) } def::DefMod(id) => { tcx.sess.span_fatal(ast_ty.span, @@ -891,7 +904,9 @@ pub fn ty_of_method( fn_style: ast::FnStyle, untransformed_self_ty: ty::t, 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 { untransformed_self_ty: untransformed_self_ty, explicit_self: explicit_self diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index b950d569d56a9..3933c30d5c98b 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -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. 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: let v_def = lookup_def(pcx.fcx, pat.span, pat.id); 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 = { let vinfo = ty::enum_variant_with_id(tcx, enm, var); - let var_tpt = ty::lookup_item_type(tcx, var); - vinfo.args.iter().map(|t| { - if var_tpt.generics.type_param_defs().len() == - expected_substs.tps.len() - { - t.subst(tcx, expected_substs) - } - else { - *t // In this case, an error was already signaled - // anyway - } - }).collect() + if enm == expected_def_id { + vinfo.args.iter() + .map(|t| t.subst(tcx, expected_substs)) + .collect() + } else { + vinfo.args.iter() + .map(|_| ty::mk_err()) + .collect() + } }; kind_name = "variant"; @@ -569,11 +566,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { fields.as_slice(), etc, supplied_def_id, - &subst::Substs { - self_ty: None, - tps: Vec::new(), - regions: subst::ErasedRegions, - }); + &subst::Substs::empty()); } _ => () // Error, but we're already in an error case } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index ba53cbf0cab06..aa6877584035d 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -91,7 +91,7 @@ use middle::typeck::infer; use middle::typeck::MethodCallee; use middle::typeck::{MethodOrigin, MethodParam}; 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 util::common::indenter; use util::ppaux; @@ -235,31 +235,36 @@ fn construct_transformed_self_ty_for_object( trait_def_id: ast::DefId, rcvr_substs: &subst::Substs, method_ty: &ty::Method) - -> ty::t { + -> ty::t +{ /*! - * This is a bit tricky. We have a match against a trait method - * being invoked on an object, and we want to generate the - * self-type. As an example, consider a trait - * - * trait Foo { - * fn r_method<'a>(&'a self); - * fn u_method(Box); - * } - * - * Now, assuming that `r_method` is being called, we want the - * result to be `&'a Foo`. Assuming that `u_method` is being - * called, we want the result to be `Box`. Of course, - * this transformation has already been done as part of - * `method_ty.fty.sig.inputs[0]`, but there the type - * is expressed in terms of `Self` (i.e., `&'a Self`, `Box`). - * Because objects are not standalone types, we can't just substitute - * `s/Self/Foo/`, so we must instead perform this kind of hokey - * match below. - */ - - let substs = subst::Substs {regions: rcvr_substs.regions.clone(), - self_ty: None, - tps: rcvr_substs.tps.clone()}; + * This is a bit tricky. We have a match against a trait method + * being invoked on an object, and we want to generate the + * self-type. As an example, consider a trait + * + * trait Foo { + * fn r_method<'a>(&'a self); + * fn u_method(Box); + * } + * + * Now, assuming that `r_method` is being called, we want the + * result to be `&'a Foo`. Assuming that `u_method` is being + * called, we want the result to be `Box`. Of course, + * this transformation has already been done as part of + * `method_ty.fty.sig.inputs[0]`, but there the type + * is expressed in terms of `Self` (i.e., `&'a Self`, `Box`). + * Because objects are not standalone types, we can't just substitute + * `s/Self/Foo/`, so we must instead perform this kind of hokey + * match below. + */ + + let mut obj_substs = rcvr_substs.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 { ast::SelfStatic => { 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); match ty::get(transformed_self_ty).sty { ty::ty_rptr(r, mt) => { // must be SelfRegion - let r = r.subst(tcx, &substs); // handle Early-Bound lifetime - ty::mk_trait(tcx, trait_def_id, substs, + let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime + ty::mk_trait(tcx, trait_def_id, obj_substs, RegionTraitStore(r, mt.mutbl), ty::empty_builtin_bounds()) } ty::ty_uniq(_) => { // must be SelfUniq - ty::mk_trait(tcx, trait_def_id, substs, + ty::mk_trait(tcx, trait_def_id, obj_substs, UniqTraitStore, ty::empty_builtin_bounds()) } @@ -456,11 +461,6 @@ impl<'a> LookupContext<'a> { ty_param(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 */ } } @@ -516,10 +516,7 @@ impl<'a> LookupContext<'a> { // // `confirm_candidate()` also relies upon this substitution // for Self. (fix) - let rcvr_substs = subst::Substs { - self_ty: Some(ty::mk_err()), - ..(*substs).clone() - }; + let rcvr_substs = substs.with_self_ty(ty::mk_err()); let trait_ref = Rc::new(TraitRef { def_id: did, substs: rcvr_substs.clone() @@ -552,35 +549,27 @@ impl<'a> LookupContext<'a> { fn push_inherent_candidates_from_param(&mut self, rcvr_ty: ty::t, restrict_to: Option, - param_ty: param_ty) { + param_ty: ParamTy) { debug!("push_inherent_candidates_from_param(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) { - debug!("push_inherent_candidates_from_self()"); self.push_inherent_candidates_from_bounds( rcvr_ty, - [self.fcx.inh.param_env.self_param_bound.clone().unwrap()], + param_ty.space, + param_ty.idx, restrict_to, - param_self) + param_index { space: param_ty.space, index: param_ty.idx }); } + fn push_inherent_candidates_from_bounds(&mut self, self_ty: ty::t, - bounds: &[Rc], + space: subst::ParamSpace, + index: uint, restrict_to: Option, 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, |trait_ref, m, method_num, bound_num| { match restrict_to { @@ -937,7 +926,7 @@ impl<'a> LookupContext<'a> { ty_bare_fn(..) | ty_box(..) | ty_uniq(..) | ty_rptr(..) | ty_infer(IntVar(_)) | 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_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) | ty_tup(..) | 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) - -> MethodCallee { + -> MethodCallee + { // This method performs two sets of substitutions, one after the other: // 1. Substitute values for any type/lifetime parameters from the impl and // 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 // variables. let num_supplied_tps = self.supplied_tps.len(); - let num_method_tps = candidate.method_ty.generics.type_param_defs().len(); - let m_substs = { + let num_method_tps = candidate.method_ty.generics.types.len(subst::FnSpace); + let m_types = { if num_supplied_tps == 0u { self.fcx.infcx().next_ty_vars(num_method_tps) } else if num_method_tps == 0u { @@ -1129,37 +1119,23 @@ impl<'a> LookupContext<'a> { } else if num_supplied_tps != num_method_tps { tcx.sess.span_err( self.span, - "incorrect number of type \ - parameters given for this method"); + "incorrect number of type parameters given for this method"); self.fcx.infcx().next_ty_vars(num_method_tps) } else { 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 - let mut all_regions: Vec = 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 = self.fcx.infcx().region_vars_for_defs( self.span, - candidate.method_ty.generics.region_param_defs.as_slice()); - for &r in m_regions.iter() { - all_regions.push(r); - } + candidate.method_ty.generics.regions.get_vec(subst::FnSpace)); - // Construct the full set of type parameters for the method, - // 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 all_substs = candidate.rcvr_substs.clone().with_method(m_types, m_regions); let ref bare_fn_ty = candidate.method_ty.fty; @@ -1285,7 +1261,8 @@ impl<'a> LookupContext<'a> { 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.span, "cannot call a generic method through an object"); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index a6615d6bce9ff..544990d19a51a 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -83,10 +83,10 @@ use middle::lint::UnreachableCode; use middle::pat_util::pat_id_map; use middle::pat_util; use middle::subst; -use middle::subst::{Subst, Substs}; +use middle::subst::{Subst, Substs, VecPerParamSpace, ParamSpace}; use middle::ty::{FnSig, VariantInfo}; use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty}; -use middle::ty::{param_ty, Disr, ExprTyProvider}; +use middle::ty::{ParamTy, Disr, ExprTyProvider}; use middle::ty; use middle::ty_fold::TypeFolder; use middle::typeck::astconv::AstConv; @@ -285,8 +285,7 @@ fn blank_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> { // and statement context, but we might as well do write the code only once let param_env = ty::ParameterEnvironment { free_substs: subst::Substs::empty(), - self_param_bound: None, - type_param_bounds: Vec::new() + bounds: subst::VecPerParamSpace::empty() }; Inherited::new(ccx.tcx, param_env) } @@ -453,9 +452,9 @@ fn check_fn<'a>(ccx: &'a CrateCtxt<'a>, let arg_tys = fn_sig.inputs.as_slice(); let ret_ty = fn_sig.output; - debug!("check_fn(arg_tys={:?}, ret_ty={:?})", - arg_tys.iter().map(|&a| ppaux::ty_to_str(tcx, a)).collect::>(), - ppaux::ty_to_str(tcx, ret_ty)); + debug!("check_fn(arg_tys={}, ret_ty={})", + arg_tys.repr(tcx), + ret_ty.repr(tcx)); // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. @@ -647,14 +646,9 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { ast::ItemFn(ref decl, _, _, _, ref body) => { let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); - let param_env = ty::construct_parameter_environment( - ccx.tcx, - None, - fn_tpt.generics.type_param_defs(), - [], - [], - fn_tpt.generics.region_param_defs.as_slice(), - body.id); + let param_env = ty::construct_parameter_environment(ccx.tcx, + &fn_tpt.generics, + body.id); check_bare_fn(ccx, &**decl, &**body, it.id, fn_tpt.ty, param_env); } @@ -663,7 +657,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); for m in ms.iter() { - check_method_body(ccx, &impl_tpt.generics, None, &**m); + check_method_body(ccx, &impl_tpt.generics, &**m); } match *opt_trait_ref { @@ -672,7 +666,6 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id); check_impl_methods_against_trait(ccx, it.span, - &impl_tpt.generics, ast_trait_ref, &*impl_trait_ref, ms.as_slice()); @@ -691,8 +684,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { // bodies to check. } Provided(m) => { - check_method_body(ccx, &trait_def.generics, - Some(trait_def.trait_ref.clone()), &*m); + check_method_body(ccx, &trait_def.generics, &*m); } } } @@ -712,7 +704,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { } else { for item in m.items.iter() { let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id)); - if tpt.generics.has_type_params() { + if !tpt.generics.types.is_empty() { ccx.tcx.sess.span_err(item.span, "foreign items may not have type parameters"); } @@ -734,7 +726,6 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { fn check_method_body(ccx: &CrateCtxt, item_generics: &ty::Generics, - self_bound: Option>, method: &ast::Method) { /*! * Type checks a method body. @@ -746,25 +737,16 @@ fn check_method_body(ccx: &CrateCtxt, * - `method`: the method definition */ - debug!("check_method_body(item_generics={}, \ - self_bound={}, \ - method.id={})", + debug!("check_method_body(item_generics={}, method.id={})", item_generics.repr(ccx.tcx), - self_bound.repr(ccx.tcx), method.id); let method_def_id = local_def(method.id); let method_ty = ty::method(ccx.tcx, method_def_id); let method_generics = &method_ty.generics; - let param_env = - ty::construct_parameter_environment( - ccx.tcx, - self_bound, - item_generics.type_param_defs(), - method_generics.type_param_defs(), - item_generics.region_param_defs(), - method_generics.region_param_defs(), - method.body.id); + let param_env = ty::construct_parameter_environment(ccx.tcx, + method_generics, + method.body.id); let fty = ty::node_id_to_type(ccx.tcx, method.id); @@ -773,7 +755,6 @@ fn check_method_body(ccx: &CrateCtxt, fn check_impl_methods_against_trait(ccx: &CrateCtxt, impl_span: Span, - impl_generics: &ty::Generics, ast_trait_ref: &ast::TraitRef, impl_trait_ref: &ty::TraitRef, impl_methods: &[Gc]) { @@ -795,7 +776,6 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt, match opt_trait_method_ty { Some(trait_method_ty) => { compare_impl_method(ccx.tcx, - impl_generics, &*impl_method_ty, impl_method.span, impl_method.body.id, @@ -849,20 +829,17 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt, * - impl_m_span: span to use for reporting errors * - impl_m_body_id: id of the method body * - trait_m: the method in the trait - * - trait_substs: the substitutions used on the type of the trait + * - trait_to_impl_substs: the substitutions used on the type of the trait */ fn compare_impl_method(tcx: &ty::ctxt, - impl_generics: &ty::Generics, impl_m: &ty::Method, impl_m_span: Span, impl_m_body_id: ast::NodeId, trait_m: &ty::Method, - trait_substs: &subst::Substs) { + trait_to_impl_substs: &subst::Substs) { debug!("compare_impl_method()"); let infcx = infer::new_infer_ctxt(tcx); - let impl_tps = impl_generics.type_param_defs().len(); - // Try to give more informative error messages about self typing // mismatches. Note that any mismatch will also be detected // below, where we construct a canonical function type that @@ -897,8 +874,8 @@ fn compare_impl_method(tcx: &ty::ctxt, } } - let num_impl_m_type_params = impl_m.generics.type_param_defs().len(); - let num_trait_m_type_params = trait_m.generics.type_param_defs().len(); + let num_impl_m_type_params = impl_m.generics.types.len(subst::FnSpace); + let num_trait_m_type_params = trait_m.generics.types.len(subst::FnSpace); if num_impl_m_type_params != num_trait_m_type_params { tcx.sess.span_err( impl_m_span, @@ -925,8 +902,8 @@ fn compare_impl_method(tcx: &ty::ctxt, return; } - let it = trait_m.generics.type_param_defs().iter() - .zip(impl_m.generics.type_param_defs().iter()); + let it = trait_m.generics.types.get_vec(subst::FnSpace).iter() + .zip(impl_m.generics.types.get_vec(subst::FnSpace).iter()); for (i, (trait_param_def, impl_param_def)) in it.enumerate() { // Check that the impl does not require any builtin-bounds @@ -971,62 +948,89 @@ fn compare_impl_method(tcx: &ty::ctxt, } } - // Create a substitution that maps the type parameters on the impl - // to themselves and which replace any references to bound regions - // in the self type with free regions. So, for example, if the - // impl type is "&'a str", then this would replace the self - // type with a free region `self`. - let dummy_impl_tps: Vec = - impl_generics.type_param_defs().iter().enumerate(). - map(|(i,t)| ty::mk_param(tcx, i, t.def_id)). - collect(); - let dummy_method_tps: Vec = - impl_m.generics.type_param_defs().iter().enumerate(). - map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)). - collect(); - let dummy_impl_regions: Vec = - impl_generics.region_param_defs().iter(). - map(|l| ty::ReFree(ty::FreeRegion { - scope_id: impl_m_body_id, - bound_region: ty::BrNamed(l.def_id, l.name)})). - collect(); - let dummy_substs = subst::Substs { - tps: dummy_impl_tps.append(dummy_method_tps.as_slice()), - regions: subst::NonerasedRegions(dummy_impl_regions), - self_ty: None }; - - // Create a bare fn type for trait/impl - // It'd be nice to refactor so as to provide the bare fn types instead. - let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone()); + // This code is best explained by example. Consider a trait: + // + // trait Trait { + // fn method<'a,M>(t: T, m: &'a M) -> Self; + // } + // + // And an impl: + // + // impl<'i, U> Trait<&'i U> for Foo { + // fn method<'b,N>(t: &'i U, m: &'b N) -> Foo; + // } + // + // We wish to decide if those two method types are compatible. + // + // We start out with trait_to_impl_substs, that maps the trait type + // parameters to impl type parameters: + // + // trait_to_impl_substs = {T => &'i U, Self => Foo} + // + // We create a mapping `dummy_substs` that maps from the impl type + // parameters to fresh types and regions. For type parameters, + // this is the identity transform, but we could as well use any + // skolemized types. For regions, we convert from bound to free + // regions (Note: but only early-bound regions, i.e., those + // declared on the impl or used in type parameter bounds). + // + // impl_to_skol_substs = {'i => 'i0, U => U0, N => N0 } + // + // Now we can apply skol_substs to the type of the impl method + // to yield a new function type in terms of our fresh, skolemized + // types: + // + // <'b> fn(t: &'i0 U0, m: &'b) -> Foo + // + // We now want to extract and substitute the type of the *trait* + // method and compare it. To do so, we must create a compound + // substitution by combining trait_to_impl_substs and + // impl_to_skol_substs, and also adding a mapping for the method + // type parameters. We extend the mapping to also include + // the method parameters. + // + // trait_to_skol_substs = { T => &'i0 U0, Self => Foo, M => N0 } + // + // Applying this to the trait method type yields: + // + // <'a> fn(t: &'i0 U0, m: &'a) -> Foo + // + // This type is also the same but the name of the bound region ('a + // vs 'b). However, the normal subtyping rules on fn types handle + // this kind of equivalency just fine. + + // Create mapping from impl to skolemized. + let skol_tps = + impl_m.generics.types.map( + |d| ty::mk_param_from_def(tcx, d)); + let skol_regions = + impl_m.generics.regions.map( + |l| ty::free_region_from_def(impl_m_body_id, l)); + let impl_to_skol_substs = + subst::Substs::new(skol_tps.clone(), skol_regions.clone()); + + // Compute skolemized form of impl method ty. let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone()); - - // Perform substitutions so that the trait/impl methods are expressed - // in terms of the same set of type/region parameters: - // - replace trait type parameters with those from `trait_substs`, - // except with any reference to bound self replaced with `dummy_self_r` - // - replace method parameters on the trait with fresh, dummy parameters - // that correspond to the parameters we will find on the impl - // - replace self region with a fresh, dummy region - let impl_fty = { - debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty)); - impl_fty.subst(tcx, &dummy_substs) - }; - debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty)); - let trait_fty = { - let subst::Substs { regions: trait_regions, - tps: trait_tps, - self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs); - let substs = subst::Substs { - regions: trait_regions, - tps: trait_tps.append(dummy_method_tps.as_slice()), - self_ty: self_ty, - }; - debug!("trait_fty (pre-subst): {} substs={}", - trait_fty.repr(tcx), substs.repr(tcx)); - trait_fty.subst(tcx, &substs) - }; - debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx)); - + let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs); + + // Compute skolemized form of trait method ty. + let trait_to_skol_substs = + trait_to_impl_substs + .subst(tcx, &impl_to_skol_substs) + .with_method(skol_tps.get_vec(subst::FnSpace).clone(), + skol_regions.get_vec(subst::FnSpace).clone()); + let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone()); + let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); + + // Check the impl method type IM is a subtype of the trait method + // type TM. To see why this makes sense, think of a vtable. The + // expected type of the function pointers in the vtable is the + // type TM of the trait method. The actual type will be the type + // IM of the impl method. Because we know that IM <: TM, that + // means that anywhere a TM is expected, a IM will do instead. In + // other words, anyone expecting to call a method with the type + // from the trait, can safely call a method with the type from the + // impl instead. match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span), impl_fty, trait_fty) { Ok(()) => {} @@ -1792,18 +1796,13 @@ pub fn impl_self_ty(vcx: &VtableContext, let ity = ty::lookup_item_type(tcx, did); let (n_tps, rps, raw_ty) = - (ity.generics.type_param_defs().len(), - ity.generics.region_param_defs(), + (ity.generics.types.len(subst::TypeSpace), + ity.generics.regions.get_vec(subst::TypeSpace), ity.ty); let rps = vcx.infcx.region_vars_for_defs(span, rps); let tps = vcx.infcx.next_ty_vars(n_tps); - - let substs = subst::Substs { - regions: subst::NonerasedRegions(rps), - self_ty: None, - tps: tps, - }; + let substs = subst::Substs::new_type(tps, rps); let substd_ty = raw_ty.subst(tcx, &substs); ty_param_substs_and_ty { substs: substs, ty: substd_ty } @@ -1850,170 +1849,6 @@ enum TupleArgumentsFlag { TupleArguments, } -// Given the provenance of a static method, returns the generics of the static -// method's container. -fn generics_of_static_method_container(type_context: &ty::ctxt, - provenance: def::MethodProvenance) - -> ty::Generics { - match provenance { - def::FromTrait(trait_def_id) => { - ty::lookup_trait_def(type_context, trait_def_id).generics.clone() - } - def::FromImpl(impl_def_id) => { - ty::lookup_item_type(type_context, impl_def_id).generics.clone() - } - } -} - -// Verifies that type parameters supplied in paths are in the right -// locations. -fn check_type_parameter_positions_in_path(function_context: &FnCtxt, - path: &ast::Path, - def: def::Def) { - // We only care about checking the case in which the path has two or - // more segments. - if path.segments.len() < 2 { - return - } - - // Verify that no lifetimes or type parameters are present anywhere - // except the final two elements of the path. - for i in range(0, path.segments.len() - 2) { - for lifetime in path.segments.get(i).lifetimes.iter() { - function_context.tcx() - .sess - .span_err(lifetime.span, - "lifetime parameters may not \ - appear here"); - break; - } - - for typ in path.segments.get(i).types.iter() { - function_context.tcx() - .sess - .span_err(typ.span, - "type parameters may not appear here"); - break; - } - } - - // If there are no parameters at all, there is nothing more to do; the - // rest of typechecking will (attempt to) infer everything. - if path.segments - .iter() - .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) { - return - } - - match def { - // If this is a static method of a trait or implementation, then - // ensure that the segment of the path which names the trait or - // implementation (the penultimate segment) is annotated with the - // right number of type parameters. - def::DefStaticMethod(_, provenance, _) => { - let generics = - generics_of_static_method_container(function_context.ccx.tcx, - provenance); - let name = match provenance { - def::FromTrait(_) => "trait", - def::FromImpl(_) => "impl", - }; - - let trait_segment = &path.segments.get(path.segments.len() - 2); - - // Make sure lifetime parameterization agrees with the trait or - // implementation type. - let trait_region_parameter_count = generics.region_param_defs().len(); - let supplied_region_parameter_count = trait_segment.lifetimes.len(); - if trait_region_parameter_count != supplied_region_parameter_count - && supplied_region_parameter_count != 0 { - function_context.tcx() - .sess - .span_err(path.span, - format!("expected {} lifetime parameter{} \ - found {} liftime parameter{}", - trait_region_parameter_count, - if trait_region_parameter_count == 1 {""} - else {"s"}, - supplied_region_parameter_count, - if supplied_region_parameter_count == 1 {""} - else {"s"}).as_slice()); - } - - // Make sure the number of type parameters supplied on the trait - // or implementation segment equals the number of type parameters - // on the trait or implementation definition. - let formal_ty_param_count = generics.type_param_defs().len(); - let required_ty_param_count = generics.type_param_defs().iter() - .take_while(|x| x.default.is_none()) - .count(); - let supplied_ty_param_count = trait_segment.types.len(); - if supplied_ty_param_count < required_ty_param_count { - let msg = if required_ty_param_count < generics.type_param_defs().len() { - format!("the {} referenced by this path needs at least \ - {} type parameter{}, but {} type parameters were \ - supplied", - name, - required_ty_param_count, - if required_ty_param_count == 1 {""} else {"s"}, - supplied_ty_param_count) - } else { - format!("the {} referenced by this path needs \ - {} type parameter{}, but {} type parameters were \ - supplied", - name, - required_ty_param_count, - if required_ty_param_count == 1 {""} else {"s"}, - supplied_ty_param_count) - }; - function_context.tcx().sess.span_err(path.span, - msg.as_slice()) - } else if supplied_ty_param_count > formal_ty_param_count { - let msg = if required_ty_param_count < generics.type_param_defs().len() { - format!("the {} referenced by this path needs at most \ - {} type parameter{}, but {} type parameters were \ - supplied", - name, - formal_ty_param_count, - if formal_ty_param_count == 1 {""} else {"s"}, - supplied_ty_param_count) - } else { - format!("the {} referenced by this path needs \ - {} type parameter{}, but {} type parameters were \ - supplied", - name, - formal_ty_param_count, - if formal_ty_param_count == 1 {""} else {"s"}, - supplied_ty_param_count) - }; - function_context.tcx().sess.span_err(path.span, - msg.as_slice()) - } - } - _ => { - // Verify that no lifetimes or type parameters are present on - // the penultimate segment of the path. - let segment = &path.segments.get(path.segments.len() - 2); - for lifetime in segment.lifetimes.iter() { - function_context.tcx() - .sess - .span_err(lifetime.span, - "lifetime parameters may not - appear here"); - break; - } - for typ in segment.types.iter() { - function_context.tcx() - .sess - .span_err(typ.span, - "type parameters may not appear \ - here"); - break; - } - } - } -} - /// Invariant: /// If an expression has any sub-expressions that result in a type error, /// inspecting that expression's type with `ty::type_is_error` will return @@ -2689,19 +2524,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // Look up the number of type parameters and the raw type, and // determine whether the class is region-parameterized. let item_type = ty::lookup_item_type(tcx, class_id); - let type_parameter_count = item_type.generics.type_param_defs().len(); - let region_param_defs = item_type.generics.region_param_defs(); let raw_type = item_type.ty; // Generate the struct type. - let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs); - let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); - let substitutions = subst::Substs { - regions: subst::NonerasedRegions(regions), - self_ty: None, - tps: type_parameters - }; - + let substitutions = fcx.infcx().fresh_substs_for_type( + span, &item_type.generics); let mut struct_type = raw_type.subst(tcx, &substitutions); // Look up and check the fields. @@ -2745,20 +2572,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // Look up the number of type parameters and the raw type, and // determine whether the enum is region-parameterized. let item_type = ty::lookup_item_type(tcx, enum_id); - let type_parameter_count = item_type.generics.type_param_defs().len(); - let region_param_defs = item_type.generics.region_param_defs(); - let raw_type = item_type.ty; - - // Generate the enum type. - let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs); - let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); - let substitutions = subst::Substs { - regions: subst::NonerasedRegions(regions), - self_ty: None, - tps: type_parameters - }; - - let enum_type = raw_type.subst(tcx, &substitutions); + let substitutions = fcx.infcx().fresh_substs_for_type(span, &item_type.generics); + let enum_type = item_type.ty.subst(tcx, &substitutions); // Look up and check the enum variant fields. let variant_fields = ty::lookup_struct_fields(tcx, variant_id); @@ -3039,8 +2854,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } ast::ExprPath(ref pth) => { let defn = lookup_def(fcx, pth.span, id); - - check_type_parameter_positions_in_path(fcx, pth, defn); let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn); instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id); } @@ -3983,179 +3796,367 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: &FnCtxt, // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. pub fn instantiate_path(fcx: &FnCtxt, - pth: &ast::Path, - tpt: ty_param_bounds_and_ty, + path: &ast::Path, + polytype: ty_param_bounds_and_ty, def: def::Def, span: Span, node_id: ast::NodeId) { - debug!(">>> instantiate_path"); - - let ty_param_count = tpt.generics.type_param_defs().len(); - let ty_param_req = tpt.generics.type_param_defs().iter() - .take_while(|x| x.default.is_none()) - .count(); - let mut ty_substs_len = 0; - for segment in pth.segments.iter() { - ty_substs_len += segment.types.len() - } + debug!("instantiate_path(path={}, def={}, node_id={}, polytype={})", + path.repr(fcx.tcx()), + def.repr(fcx.tcx()), + node_id, + polytype.repr(fcx.tcx())); + + // We need to extract the type parameters supplied by the user in + // the path `path`. Due to the current setup, this is a bit of a + // tricky-process; the problem is that resolve only tells us the + // end-point of the path resolution, and not the intermediate steps. + // Luckily, we can (at least for now) deduce the intermediate steps + // just from the end-point. + // + // There are basically three cases to consider: + // + // 1. Reference to a *type*, such as a struct or enum: + // + // mod a { struct Foo { ... } } + // + // Because we don't allow types to be declared within one + // another, a path that leads to a type will always look like + // `a::b::Foo` where `a` and `b` are modules. This implies + // that only the final segment can have type parameters, and + // they are located in the TypeSpace. + // + // *Note:* Generally speaking, references to types don't + // actually pass through this function, but rather the + // `ast_ty_to_ty` function in `astconv`. However, in the case + // of struct patterns (and maybe literals) we do invoke + // `instantiate_path` to get the general type of an instance of + // a struct. (In these cases, there are actually no type + // parameters permitted at present, but perhaps we will allow + // them in the future.) + // + // 1b. Reference to a enum variant or tuple-like struct: + // + // struct foo(...) + // enum E { foo(...) } + // + // In these cases, the parameters are declared in the type + // space. + // + // 2. Reference to a *fn item*: + // + // fn foo() { } + // + // In this case, the path will again always have the form + // `a::b::foo::` where only the final segment should have + // type parameters. However, in this case, those parameters are + // declared on a value, and hence are in the `FnSpace`. + // + // 3. Reference to a *method*: + // + // impl SomeStruct { + // fn foo(...) + // } + // + // Here we can have a path like + // `a::b::SomeStruct::::foo::`, in which case parameters + // may appear in two places. The penultimate segment, + // `SomeStruct::`, contains parameters in TypeSpace, and the + // final segment, `foo::` contains parameters in fn space. + // + // The first step then is to categorize the segments appropriately. - debug!("tpt={} ty_param_count={:?} ty_substs_len={:?}", - tpt.repr(fcx.tcx()), - ty_param_count, - ty_substs_len); - - // determine the region parameters, using the value given by the user - // (if any) and otherwise using a fresh region variable - let num_expected_regions = tpt.generics.region_param_defs().len(); - let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len(); - let regions = if num_expected_regions == num_supplied_regions { - pth.segments.last().unwrap().lifetimes - .iter() - .map(|l| ast_region_to_region(fcx.tcx(), l)) - .collect() - } else { - if num_supplied_regions != 0 { - fcx.ccx.tcx.sess.span_err( - span, - format!("expected {} lifetime parameter{}, \ - found {} lifetime parameter{}", - num_expected_regions, - if num_expected_regions == 1 {""} else {"s"}, - num_supplied_regions, - if num_supplied_regions == 1 {""} else {"s"}).as_slice()); + assert!(path.segments.len() >= 1); + let mut segment_spaces; + match def { + // Case 1 and 1b. Reference to a *type* or *enum variant*. + def::DefSelfTy(..) | + def::DefStruct(..) | + def::DefVariant(..) | + def::DefTyParamBinder(..) | + def::DefTy(..) | + def::DefTrait(..) | + def::DefPrimTy(..) | + def::DefTyParam(..) => { + // Everything but the final segment should have no + // parameters at all. + segment_spaces = Vec::from_elem(path.segments.len() - 1, None); + segment_spaces.push(Some(subst::TypeSpace)); } - fcx.infcx().region_vars_for_defs(span, tpt.generics.region_param_defs.as_slice()) - }; - let regions = subst::NonerasedRegions(regions); + // Case 2. Reference to a top-level value. + def::DefFn(..) | + def::DefStatic(..) => { + segment_spaces = Vec::from_elem(path.segments.len() - 1, None); + segment_spaces.push(Some(subst::FnSpace)); + } - // Special case: If there is a self parameter, omit it from the list of - // type parameters. - // - // Here we calculate the "user type parameter count", which is the number - // of type parameters actually manifest in the AST. This will differ from - // the internal type parameter count when there are self types involved. - let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def { - def::DefStaticMethod(_, provenance @ def::FromTrait(_), _) => { - let generics = generics_of_static_method_container(fcx.ccx.tcx, - provenance); - (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs().len())) + // Case 3. Reference to a method. + def::DefStaticMethod(..) => { + assert!(path.segments.len() >= 2); + segment_spaces = Vec::from_elem(path.segments.len() - 2, None); + segment_spaces.push(Some(subst::TypeSpace)); + segment_spaces.push(Some(subst::FnSpace)); } - _ => (ty_param_count, ty_param_req, None), - }; - // determine values for type parameters, using the values given by - // the user (if any) and otherwise using fresh type variables - let (tps, regions) = if ty_substs_len == 0 { - (fcx.infcx().next_ty_vars(ty_param_count), regions) - } else if ty_param_count == 0 { - fcx.ccx.tcx.sess.span_err - (span, "this item does not take type parameters"); - (fcx.infcx().next_ty_vars(ty_param_count), regions) - } else if ty_substs_len > user_ty_param_count { - let expected = if user_ty_param_req < user_ty_param_count { - "expected at most" - } else { - "expected" - }; - fcx.ccx.tcx.sess.span_err - (span, - format!("too many type parameters provided: {} {}, found {}", - expected, user_ty_param_count, ty_substs_len).as_slice()); - (fcx.infcx().next_ty_vars(ty_param_count), regions) - } else if ty_substs_len < user_ty_param_req { - let expected = if user_ty_param_req < user_ty_param_count { - "expected at least" - } else { - "expected" - }; - fcx.ccx.tcx.sess.span_err( - span, - format!("not enough type parameters provided: {} {}, found {}", - expected, - user_ty_param_req, - ty_substs_len).as_slice()); - (fcx.infcx().next_ty_vars(ty_param_count), regions) - } else { - if ty_substs_len > user_ty_param_req - && !fcx.tcx().sess.features.default_type_params.get() { - fcx.tcx().sess.span_err(pth.span, "default type parameters are \ - experimental and possibly buggy"); - fcx.tcx().sess.span_note(pth.span, "add #![feature(default_type_params)] \ - to the crate attributes to enable"); + // Other cases. Various nonsense that really shouldn't show up + // here. If they do, an error will have been reported + // elsewhere. (I hope) + def::DefMod(..) | + def::DefForeignMod(..) | + def::DefArg(..) | + def::DefLocal(..) | + def::DefMethod(..) | + def::DefBinding(..) | + def::DefUse(..) | + def::DefRegion(..) | + def::DefLabel(..) | + def::DefUpvar(..) => { + segment_spaces = Vec::from_elem(path.segments.len(), None); } + } + assert_eq!(segment_spaces.len(), path.segments.len()); + + debug!("segment_spaces={}", segment_spaces); + + // Next, examine the definition, and determine how many type + // parameters we expect from each space. + let type_defs = &polytype.generics.types; + let region_defs = &polytype.generics.regions; + + // Now that we have categorized what space the parameters for each + // segment belong to, let's sort out the parameters that the user + // provided (if any) into their appropriate spaces. We'll also report + // errors if type parameters are provided in an inappropriate place. + let mut substs = Substs::empty(); + for (opt_space, segment) in segment_spaces.iter().zip(path.segments.iter()) { + match *opt_space { + None => { + report_error_if_segment_contains_type_parameters(fcx, segment); + } - // Build up the list of type parameters, inserting the self parameter - // at the appropriate position. - let mut tps = Vec::new(); - let mut pushed = false; - for (i, ty) in pth.segments.iter() - .flat_map(|segment| segment.types.iter()) - .map(|ast_type| fcx.to_ty(&**ast_type)) - .enumerate() { - match self_parameter_index { - Some(index) if index == i => { - tps.push(*fcx.infcx().next_ty_vars(1).get(0)); - pushed = true; - } - _ => {} + Some(space) => { + push_explicit_parameters_from_segment_to_substs(fcx, + space, + type_defs, + region_defs, + segment, + &mut substs); } - tps.push(ty) } + } - let mut substs = subst::Substs { - regions: regions, - self_ty: None, - tps: tps - }; + // Now we have to compare the types that the user *actually* + // provided against the types that were *expected*. If the user + // did not provide any types, then we want to substitute inference + // variables. If the user provided some types, we may still need + // to add defaults. If the user provided *too many* types, that's + // a problem. + for &space in ParamSpace::all().iter() { + adjust_type_parameters(fcx, span, space, type_defs, &mut substs); + assert_eq!(substs.types.get_vec(space).len(), + type_defs.get_vec(space).len()); + + adjust_region_parameters(fcx, span, space, region_defs, &mut substs); + assert_eq!(substs.regions().get_vec(space).len(), + region_defs.get_vec(space).len()); + } - let defaults = tpt.generics.type_param_defs().iter() - .enumerate().filter_map(|(i, x)| { - match self_parameter_index { - Some(index) if index == i => None, - _ => Some(x.default) - } - }); - for (i, default) in defaults.skip(ty_substs_len).enumerate() { - match self_parameter_index { - Some(index) if index == i + ty_substs_len => { - substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0)); - pushed = true; + fcx.write_ty_substs(node_id, polytype.ty, ty::ItemSubsts { + substs: substs, + }); + + fn report_error_if_segment_contains_type_parameters( + fcx: &FnCtxt, + segment: &ast::PathSegment) + { + for typ in segment.types.iter() { + fcx.tcx().sess.span_err( + typ.span, + "type parameters may not appear here"); + break; + } + + for lifetime in segment.lifetimes.iter() { + fcx.tcx().sess.span_err( + lifetime.span, + "lifetime parameters may not appear here"); + break; + } + } + + fn push_explicit_parameters_from_segment_to_substs( + fcx: &FnCtxt, + space: subst::ParamSpace, + type_defs: &VecPerParamSpace, + region_defs: &VecPerParamSpace, + segment: &ast::PathSegment, + substs: &mut Substs) + { + /*! + * Finds the parameters that the user provided and adds them + * to `substs`. If too many parameters are provided, then + * reports an error and clears the output vector. + * + * We clear the output vector because that will cause the + * `adjust_XXX_parameters()` later to use inference + * variables. This seems less likely to lead to derived + * errors. + * + * Note that we *do not* check for *too few* parameters here. + * Due to the presence of defaults etc that is more + * complicated. I wanted however to do the reporting of *too + * many* parameters here because we can easily use the precise + * span of the N+1'th parameter. + */ + + { + let type_count = type_defs.get_vec(space).len(); + assert_eq!(substs.types.get_vec(space).len(), 0); + for (i, &typ) in segment.types.iter().enumerate() { + let t = fcx.to_ty(&*typ); + if i < type_count { + substs.types.push(space, t); + } else if i == type_count { + fcx.tcx().sess.span_err( + typ.span, + format!( + "too many type parameters provided: \ + expected at most {} parameter(s) \ + but found {} parameter(s)", + type_count, + segment.types.len()).as_slice()); + substs.types.get_mut_vec(space).truncate(0); } - _ => {} } - match default { - Some(default) => { - let ty = default.subst_spanned(fcx.tcx(), &substs, Some(span)); - substs.tps.push(ty); - } - None => { - fcx.tcx().sess.span_bug(span, - "missing default for a not explicitly provided type param") + } + + { + let region_count = region_defs.get_vec(space).len(); + assert_eq!(substs.regions().get_vec(space).len(), 0); + for (i, lifetime) in segment.lifetimes.iter().enumerate() { + let r = ast_region_to_region(fcx.tcx(), lifetime); + if i < region_count { + substs.mut_regions().push(space, r); + } else if i == region_count { + fcx.tcx().sess.span_err( + lifetime.span, + format!( + "too many lifetime parameters provided: \ + expected {} parameter(s) but found {} parameter(s)", + region_count, + segment.lifetimes.len()).as_slice()); + substs.mut_regions().get_mut_vec(space).truncate(0); } } } + } - // If the self parameter goes at the end, insert it there. - if !pushed && self_parameter_index.is_some() { - substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0)) + fn adjust_type_parameters( + fcx: &FnCtxt, + span: Span, + space: ParamSpace, + defs: &VecPerParamSpace, + substs: &mut Substs) + { + let provided_len = substs.types.get_vec(space).len(); + let desired = defs.get_vec(space).as_slice(); + let required_len = desired.iter() + .take_while(|d| d.default.is_none()) + .count(); + + debug!("adjust_type_parameters(space={}, \ + provided_len={}, \ + desired_len={}, \ + required_len={})", + space, + provided_len, + desired.len(), + required_len); + + // Enforced by `push_explicit_parameters_from_segment_to_substs()`. + assert!(provided_len <= desired.len()); + + // Nothing specified at all: supply inference variables for + // everything. + if provided_len == 0 { + let provided = substs.types.get_mut_vec(space); + *provided = fcx.infcx().next_ty_vars(desired.len()); + return; } - assert_eq!(substs.tps.len(), ty_param_count) + // Too few parameters specified: report an error and use Err + // for everything. + if provided_len < required_len { + let qualifier = + if desired.len() != required_len { "at least " } else { "" }; + fcx.tcx().sess.span_err( + span, + format!("too few type parameters provided: \ + expected {}{} parameter(s) \ + but found {} parameter(s)", + qualifier, + required_len, + provided_len).as_slice()); + let provided = substs.types.get_mut_vec(space); + *provided = Vec::from_elem(desired.len(), ty::mk_err()); + return; + } - let subst::Substs {tps, regions, ..} = substs; - (tps, regions) - }; + // Otherwise, add in any optional parameters that the user + // omitted. The case of *too many* parameters is handled + // already by + // push_explicit_parameters_from_segment_to_substs(). Note + // that the *default* type are expressed in terms of all prior + // parameters, so we have to substitute as we go with the + // partial substitution that we have built up. + for i in range(provided_len, desired.len()) { + let default = desired[i].default.unwrap(); + let default = default.subst_spanned(fcx.tcx(), substs, Some(span)); + substs.types.push(space, default); + } + assert_eq!(substs.types.get_vec(space).len(), desired.len()); - let substs = subst::Substs { regions: regions, - self_ty: None, - tps: tps }; + debug!("Final substs: {}", substs.repr(fcx.tcx())); + } - fcx.write_ty_substs(node_id, tpt.ty, ty::ItemSubsts { - substs: substs, - }); + fn adjust_region_parameters( + fcx: &FnCtxt, + span: Span, + space: ParamSpace, + defs: &VecPerParamSpace, + substs: &mut Substs) + { + let provided = substs.mut_regions().get_mut_vec(space); + let desired = defs.get_vec(space); + + // Enforced by `push_explicit_parameters_from_segment_to_substs()`. + assert!(provided.len() <= desired.len()); + + // If nothing was provided, just use inference variables. + if provided.len() == 0 { + *provided = fcx.infcx().region_vars_for_defs(span, desired); + return; + } + + // If just the right number were provided, everybody is happy. + if provided.len() == desired.len() { + return; + } - debug!("<<<"); + // Otherwise, too few were provided. Report an error and then + // use inference variables. + fcx.tcx().sess.span_err( + span, + format!( + "too few lifetime parameters provided: \ + expected {} parameter(s) \ + but found {} parameter(s)", + desired.len(), + provided.len()).as_slice()); + + *provided = fcx.infcx().region_vars_for_defs(span, desired); + } } // Resolves `typ` by a single level if `typ` is a type variable. If no @@ -4292,14 +4293,8 @@ pub fn check_bounds_are_used(ccx: &CrateCtxt, ty::walk_ty(ty, |t| { match ty::get(t).sty { - #[cfg(stage0)] - ty::ty_param(param_ty {idx, ..}) => { - debug!("Found use of ty param \\#{}", idx); - *tps_used.get_mut(idx) = true; - } - #[cfg(not(stage0))] - ty::ty_param(param_ty {idx, ..}) => { - debug!("Found use of ty param #{}", idx); + ty::ty_param(ParamTy {idx, ..}) => { + debug!("Found use of ty param num {}", idx); *tps_used.get_mut(idx) = true; } _ => () @@ -4318,7 +4313,7 @@ pub fn check_bounds_are_used(ccx: &CrateCtxt, pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { fn param(ccx: &CrateCtxt, n: uint) -> ty::t { - ty::mk_param(ccx.tcx, n, local_def(0)) + ty::mk_param(ccx.tcx, subst::FnSpace, n, local_def(0)) } let tcx = ccx.tcx; @@ -4390,11 +4385,10 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "type_id" => { let langid = ccx.tcx.lang_items.require(TypeIdLangItem); match langid { - Ok(did) => (1u, Vec::new(), ty::mk_struct(ccx.tcx, did, subst::Substs { - self_ty: None, - tps: Vec::new(), - regions: subst::NonerasedRegions(Vec::new()) - }) ), + Ok(did) => (1u, + Vec::new(), + ty::mk_struct(ccx.tcx, did, + subst::Substs::empty())), Err(msg) => { tcx.sess.span_fatal(it.span, msg.as_slice()); } @@ -4593,7 +4587,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { } }); let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); - let i_n_tps = i_ty.generics.type_param_defs().len(); + let i_n_tps = i_ty.generics.types.len(subst::FnSpace); if i_n_tps != n_tps { tcx.sess.span_err(it.span, format!("intrinsic has wrong number of type \ diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 546eaa1fceb74..7d2b9d9aa8697 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -10,7 +10,7 @@ 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::typeck::astconv::AstConv; 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; use middle::typeck::{vtable_origin, vtable_res, vtable_param_res}; -use middle::typeck::{vtable_static, vtable_param, impl_res}; -use middle::typeck::{param_numbered, param_self, param_index}; +use middle::typeck::{vtable_static, vtable_param, vtable_error}; +use middle::typeck::{param_index}; use middle::typeck::MethodCall; use middle::subst; -use middle::subst::Subst; +use middle::subst::{Subst, VecPerParamSpace}; use util::common::indenter; use util::ppaux; use util::ppaux::Repr; @@ -76,38 +76,32 @@ impl<'a> VtableContext<'a> { fn lookup_vtables(vcx: &VtableContext, span: Span, - type_param_defs: &[ty::TypeParameterDef], + type_param_defs: &VecPerParamSpace, substs: &subst::Substs, - is_early: bool) -> vtable_res { - debug!("lookup_vtables(span={:?}, \ - type_param_defs={}, \ - substs={}", - span, + is_early: bool) + -> VecPerParamSpace +{ + debug!("lookup_vtables(\ + type_param_defs={}, \ + substs={}", type_param_defs.repr(vcx.tcx()), substs.repr(vcx.tcx())); // We do this backwards for reasons discussed above. - assert_eq!(substs.tps.len(), type_param_defs.len()); - let mut result: Vec = - substs.tps.iter() - .rev() - .zip(type_param_defs.iter().rev()) - .map(|(ty, def)| - lookup_vtables_for_param(vcx, span, Some(substs), - &*def.bounds, *ty, is_early)) - .collect(); - result.reverse(); - - assert_eq!(substs.tps.len(), result.len()); + let result = type_param_defs.map_rev(|def| { + let ty = *substs.types.get(def.space, def.index); + lookup_vtables_for_param(vcx, span, Some(substs), + &*def.bounds, ty, is_early) + }); + debug!("lookup_vtables result(\ - span={:?}, \ type_param_defs={}, \ substs={}, \ result={})", - span, type_param_defs.repr(vcx.tcx()), substs.repr(vcx.tcx()), result.repr(vcx.tcx())); + result } @@ -117,9 +111,15 @@ fn lookup_vtables_for_param(vcx: &VtableContext, substs: Option<&subst::Substs>, type_param_bounds: &ty::ParamBounds, ty: ty::t, - is_early: bool) -> vtable_param_res { + is_early: bool) + -> vtable_param_res { 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... 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, // 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, trait_ref.def_id); @@ -157,11 +161,9 @@ fn lookup_vtables_for_param(vcx: &VtableContext, }); debug!("lookup_vtables_for_param result(\ - span={:?}, \ type_param_bounds={}, \ ty={}, \ result={})", - span, type_param_bounds.repr(vcx.tcx()), ty.repr(vcx.tcx()), param_result.repr(vcx.tcx())); @@ -216,10 +218,11 @@ fn lookup_vtable(vcx: &VtableContext, ty: ty::t, trait_ref: Rc, is_early: bool) - -> Option { + -> Option +{ debug!("lookup_vtable(ty={}, trait_ref={})", - vcx.infcx.ty_to_str(ty), - vcx.infcx.trait_ref_to_str(&*trait_ref)); + ty.repr(vcx.tcx()), + trait_ref.repr(vcx.tcx())); let _i = indenter(); 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 // do early resolution on it. Return some completely bogus vtable // 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 // bounds to see if they include the trait we are looking for. let vtable_opt = match ty::get(ty).sty { - ty::ty_param(param_ty {idx: n, ..}) => { - let env_bounds = &vcx.param_env.type_param_bounds; - if env_bounds.len() > n { - let type_param_bounds: &[Rc] = - env_bounds.get(n).trait_bounds.as_slice(); - lookup_vtable_from_bounds(vcx, span, - type_param_bounds, - param_numbered(n), - trait_ref.clone()) - } else { - None - } - } - - ty::ty_self(_) => { - let self_param_bound = vcx.param_env.self_param_bound.clone().unwrap(); + ty::ty_param(ParamTy {space, idx: n, ..}) => { + let env_bounds = &vcx.param_env.bounds; + let type_param_bounds = &env_bounds.get(space, n).trait_bounds; lookup_vtable_from_bounds(vcx, span, - [self_param_bound], - param_self, + type_param_bounds.as_slice(), + param_index { space: space, + index: n }, trait_ref.clone()) } @@ -373,8 +368,8 @@ fn search_for_vtable(vcx: &VtableContext, // Now, in the previous example, for_ty is bound to // the type self_ty, and substs is bound to [T]. debug!("The self ty is {} and its substs are {}", - vcx.infcx.ty_to_str(for_ty), - vcx.infcx.tys_to_str(substs.tps.as_slice())); + for_ty.repr(tcx), + substs.types.repr(tcx)); // Next, we unify trait_ref -- the type that we want to cast // 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. This would fail if T // and U weren't compatible. - debug!("(checking vtable) {}2 relating trait \ - ty {} to of_trait_ref {}", "#", + let of_trait_ref = of_trait_ref.subst(tcx, &substs); + + 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(&*of_trait_ref)); - let of_trait_ref = of_trait_ref.subst(tcx, &substs); 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. let im_generics = ty::lookup_item_type(tcx, impl_did).generics; - let subres = lookup_vtables(vcx, span, - im_generics.type_param_defs(), &substs, + let subres = lookup_vtables(vcx, + span, + &im_generics.types, + &substs, is_early); - // substs might contain type variables, so we call // fixup_substs to resolve them. let substs_f = match fixup_substs(vcx, span, @@ -419,15 +416,15 @@ fn search_for_vtable(vcx: &VtableContext, None => { assert!(is_early); // Bail out with a bogus answer - return Some(vtable_param(param_self, 0)); + return Some(vtable_error); } }; debug!("The fixed-up substs are {} - \ they will be unified with the bounds for \ the target ty, {}", - vcx.infcx.tys_to_str(substs_f.tps.as_slice()), - vcx.infcx.trait_ref_to_str(&*trait_ref)); + substs_f.types.repr(tcx), + trait_ref.repr(tcx)); // Next, we unify the fixed-up substitutions for the impl self // 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) { - debug!("insert_vtables(vtable_key={}, vtables={:?})", + debug!("insert_vtables(vtable_key={}, vtables={})", vtable_key, vtables.repr(fcx.tcx())); 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(); + + // 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 { def_id: target_def_id, substs: subst::Substs { - tps: target_substs.tps.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); 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 @@ -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, fcx.infcx().ty_to_str(item_ty.ty)); 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 vtbls = lookup_vtables(&vcx, ex.span, - item_ty.generics.type_param_defs(), + &item_ty.generics.types, &item_substs.substs, is_early); if !is_early { 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 vcx = fcx.vtable_context(); let vtbls = lookup_vtables(&vcx, ex.span, - type_param_defs.as_slice(), + &type_param_defs, &substs, is_early); if !is_early { 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); let vcx = fcx.vtable_context(); let vtbls = lookup_vtables(&vcx, ex.span, - type_param_defs.deref() - .as_slice(), + &type_param_defs, &method.substs, is_early); if !is_early { insert_vtables(fcx, method_call, vtbls); @@ -726,64 +732,84 @@ pub fn resolve_impl(tcx: &ty::ctxt, impl_item: &ast::Item, impl_generics: &ty::Generics, impl_trait_ref: &ty::TraitRef) { + /*! + * The situation is as follows. We have some trait like: + * + * trait Foo : Bar { + * fn method() { ... } + * } + * + * and an impl like: + * + * impl Foo 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={})", impl_item.id); - let param_env = ty::construct_parameter_environment( - tcx, - None, - impl_generics.type_param_defs(), - [], - impl_generics.region_param_defs(), - [], - impl_item.id); + let param_env = ty::construct_parameter_environment(tcx, + impl_generics, + impl_item.id); + // The impl_trait_ref in our example above would be + // `Foo for int` let impl_trait_ref = impl_trait_ref.subst(tcx, ¶m_env.free_substs); debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx)); let infcx = &infer::new_infer_ctxt(tcx); let vcx = VtableContext { infcx: infcx, param_env: ¶m_env }; - // First, check that the impl implements any trait bounds - // on the trait. - let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id); - let vtbls = lookup_vtables(&vcx, impl_item.span, - trait_def.generics.type_param_defs(), - &impl_trait_ref.substs, - false); - - // Now, locate the vtable for the impl itself. The real - // purpose of this is to check for supertrait impls, - // but that falls out of doing this. - let param_bounds = ty::ParamBounds { - builtin_bounds: ty::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, ¶m_env.free_substs); - debug!("=== Doing a self lookup now."); + // Resolve the vtables for the trait reference on the impl. This + // serves many purposes, best explained by example. Imagine we have: + // + // trait A : C { fn x(&self) { ... } } + // + // and + // + // impl A for uint { ... } + // + // In that case, the trait ref will be `A 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(...) { .. .}) - // 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, - ¶m_bounds, t, false); + let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id); + let vtbls = lookup_vtables(&vcx, + impl_item.span, + &trait_def.generics.types, + &impl_trait_ref.substs, + false); infcx.resolve_regions_and_report_errors(); - let res = impl_res { - trait_vtables: vtbls, - self_vtables: self_vtable_res - }; - let res = writeback::resolve_impl_res(infcx, impl_item.span, &res); + let vtbls = writeback::resolve_impl_res(infcx, impl_item.span, &vtbls); let impl_def_id = ast_util::local_def(impl_item.id); debug!("impl_vtables for {} are {}", 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. @@ -791,15 +817,14 @@ pub fn resolve_impl(tcx: &ty::ctxt, pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId, substs: &subst::Substs) -> vtable_res { let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics; - let type_param_defs = &*generics.type_param_defs; let vcx = VtableContext { 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, tcx.map.span(id), - type_param_defs.as_slice(), + &generics.types, substs, false) } diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index d503f8bedb6d8..db9e90ecd509d 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -14,7 +14,6 @@ use middle::def; use middle::pat_util; -use middle::subst; use middle::ty; use middle::ty_fold::{TypeFolder,TypeFoldable}; 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::resolve_type; use middle::typeck::infer; -use middle::typeck::impl_res; use middle::typeck::{MethodCall, MethodCallee}; +use middle::typeck::vtable_res; use middle::typeck::write_substs_to_tcx; use middle::typeck::write_ty_to_tcx; 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, span: Span, - impl_res: &impl_res) - -> impl_res { + vtable_res: &vtable_res) + -> vtable_res { let errors = Cell::new(false); // nobody cares let mut resolver = Resolver::from_infcx(infcx, &errors, 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={})", method_call, method.repr(self.tcx())); - let mut new_method = MethodCallee { + let new_method = MethodCallee { origin: method.origin, ty: self.resolve(&method.ty, 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( method_call, new_method); diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index d205376046702..04bf939ceb8d1 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -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::{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_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::type_is_ty_var; use middle::subst::Subst; @@ -43,7 +43,7 @@ use syntax::ast; use syntax::ast_map::NodeItem; use syntax::ast_map; use syntax::ast_util::{local_def}; -use syntax::codemap::Span; +use syntax::codemap::{Span, DUMMY_SP}; use syntax::parse::token; 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_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(_, _) => { debug!("(getting base type) no base type; found {:?}", get(original_type).sty); @@ -338,7 +338,8 @@ impl<'a> CoherenceChecker<'a> { // Creates default method IDs and performs type substitutions for an impl // and trait pair. Then, for each provided method in the trait, inserts a // `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, all_methods: &mut Vec) { let tcx = self.crate_context.tcx; @@ -360,6 +361,7 @@ impl<'a> CoherenceChecker<'a> { Rc::new(subst_receiver_types_in_method_ty( tcx, impl_id, + &impl_poly_type, trait_ref, new_did, &**trait_method, @@ -368,17 +370,11 @@ impl<'a> CoherenceChecker<'a> { debug!("new_method_ty={}", new_method_ty.repr(tcx)); all_methods.push(new_did); - // construct the polytype for the method based on the method_ty - let new_generics = ty::Generics { - type_param_defs: - 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())) - }; + // construct the polytype for the method based on the + // method_ty. it will have all the generics from the + // impl, plus its own. 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()) }; 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 // type variables. Returns the monotype and the type variables created. fn universally_quantify_polytype(&self, polytype: ty_param_bounds_and_ty) - -> UniversalQuantificationResult { - let region_parameters = - polytype.generics.region_param_defs().iter() - .map(|d| self.inference_context.next_region_var( - infer::BoundRegionInCoherence(d.name))) - .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 - }; + -> UniversalQuantificationResult + { + let substitutions = + self.inference_context.fresh_substs_for_type(DUMMY_SP, + &polytype.generics); let monotype = polytype.ty.subst(self.crate_context.tcx, &substitutions); UniversalQuantificationResult { @@ -731,69 +717,67 @@ impl<'a> CoherenceChecker<'a> { } pub fn make_substs_for_receiver_types(tcx: &ty::ctxt, - impl_id: ast::DefId, trait_ref: &ty::TraitRef, method: &ty::Method) - -> subst::Substs { + -> subst::Substs +{ /*! * Substitutes the values for the receiver's type parameters * that are found in method, leaving the method's type parameters - * intact. This is in fact a mildly complex operation, - * largely because of the hokey way that we concatenate the - * receiver and method generics. + * intact. */ - 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 = - method.generics.type_param_defs().iter().enumerate() - .map(|(i, t)| ty::mk_param(tcx, i + num_impl_tps, t.def_id)) + method.generics.types.get_vec(subst::FnSpace) + .iter() + .map(|def| ty::mk_param_from_def(tcx, def)) .collect(); let meth_regions: Vec = - method.generics.region_param_defs().iter().enumerate() - .map(|(i, l)| ty::ReEarlyBound(l.def_id.node, i + num_impl_regions, l.name)) + method.generics.regions.get_vec(subst::FnSpace) + .iter() + .map(|def| ty::ReEarlyBound(def.def_id.node, def.space, + def.index, def.name)) .collect(); - let mut combined_tps = trait_ref.substs.tps.clone(); - 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 - } + trait_ref.substs.clone().with_method(meth_tps, meth_regions) } fn subst_receiver_types_in_method_ty(tcx: &ty::ctxt, impl_id: ast::DefId, + impl_poly_type: &ty::ty_param_bounds_and_ty, trait_ref: &ty::TraitRef, new_def_id: ast::DefId, method: &ty::Method, provided_source: Option) - -> ty::Method { - - let combined_substs = make_substs_for_receiver_types( - tcx, impl_id, trait_ref, method); + -> ty::Method +{ + let combined_substs = make_substs_for_receiver_types(tcx, trait_ref, method); + + debug!("subst_receiver_types_in_method_ty: combined_substs={}", + 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(); + } - ty::Method::new( - method.ident, + debug!("subst_receiver_types_in_method_ty: method_generics={}", + method_generics.repr(tcx)); - // method types *can* appear in the generic bounds - method.generics.subst(tcx, &combined_substs), + let method_fty = method.fty.subst(tcx, &combined_substs); - // method types *can* appear in the fty - method.fty.subst(tcx, &combined_substs), + debug!("subst_receiver_types_in_method_ty: method_ty={}", + method.fty.repr(tcx)); + ty::Method::new( + method.ident, + method_generics, + method_fty, method.explicit_self, method.vis, new_def_id, diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index f1de8ff6daba9..55969b79b5241 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -36,7 +36,7 @@ use middle::def; use middle::lang_items::SizedTraitLangItem; use middle::resolve_lifetime; use middle::subst; -use middle::subst::{Subst, Substs}; +use middle::subst::{Substs}; use middle::ty::{ImplContainer, MethodContainer, TraitContainer}; use middle::ty::{ty_param_bounds_and_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; match tcx.map.get(trait_id) { ast_map::NodeItem(item) => { match item.node { - ast::ItemTrait(ref generics, _, _, ref ms) => { - let trait_ty_generics = ty_generics_for_type(ccx, generics); - + ast::ItemTrait(_, _, _, ref ms) => { // For each method, construct a suitable ty::Method and // store it into the `tcx.methods` table: for m in ms.iter() { let ty_method = Rc::new(match m { &ast::Required(ref m) => { 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.generics, &m.fn_style, &*m.decl) } &ast::Provided(ref m) => { 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.generics, &m.fn_style, &*m.decl) } }); if ty_method.explicit_self == ast::SelfStatic { - make_static_method_ty(ccx, trait_id, &*ty_method, - &trait_ty_generics); + make_static_method_ty(ccx, &*ty_method); } 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 */ } } - fn make_static_method_ty(ccx: &CrateCtxt, - trait_id: ast::NodeId, - m: &ty::Method, - 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 { - generics: ty::Generics { - type_param_defs: Rc::new(new_type_param_defs), - region_param_defs: new_early_region_param_defs - }, - ty: ty - }); + fn make_static_method_ty(ccx: &CrateCtxt, m: &ty::Method) { + ccx.tcx.tcache.borrow_mut().insert( + m.def_id, + ty_param_bounds_and_ty { + generics: m.generics.clone(), + ty: ty::mk_bare_fn(ccx.tcx, m.fty.clone()) }); } 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_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, *m_explicit_self, m_decl); - let num_trait_type_params = trait_generics.type_param_defs().len(); - let ty_generics = ty_generics_for_fn_or_method(this, m_generics, - num_trait_type_params); + let ty_generics = + ty_generics_for_fn_or_method(this, + m_generics, + (*trait_generics).clone()); ty::Method::new( *m_ident, 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> = 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, struct_generics: &ty::Generics, v: &ast::StructField, @@ -490,7 +325,6 @@ fn convert_methods(ccx: &CrateCtxt, ms: &[Gc], untransformed_rcvr_ty: ty::t, rcvr_ty_generics: &ty::Generics, - rcvr_ast_generics: &ast::Generics, rcvr_visibility: ast::Visibility) { let tcx = ccx.tcx; @@ -500,14 +334,11 @@ fn convert_methods(ccx: &CrateCtxt, 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, container, &**m, untransformed_rcvr_ty, - rcvr_ast_generics, + rcvr_ty_generics, rcvr_visibility)); let fty = ty::mk_bare_fn(tcx, mty.fty.clone()); debug!("method {} (id {}) has type {}", @@ -516,17 +347,8 @@ fn convert_methods(ccx: &CrateCtxt, fty.repr(ccx.tcx)); tcx.tcache.borrow_mut().insert( 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 { - generics: ty::Generics { - 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())), - }, + generics: mty.generics.clone(), ty: fty }); @@ -539,8 +361,9 @@ fn convert_methods(ccx: &CrateCtxt, container: MethodContainer, m: &ast::Method, untransformed_rcvr_ty: ty::t, - rcvr_generics: &ast::Generics, - rcvr_visibility: ast::Visibility) -> ty::Method + rcvr_ty_generics: &ty::Generics, + rcvr_visibility: ast::Visibility) + -> ty::Method { let fty = astconv::ty_of_method(ccx, m.id, m.fn_style, untransformed_rcvr_ty, @@ -552,19 +375,17 @@ fn convert_methods(ccx: &CrateCtxt, // foo(); }`). let method_vis = m.vis.inherit_from(rcvr_visibility); - let num_rcvr_type_params = rcvr_generics.ty_params.len(); let m_ty_generics = - ty_generics_for_fn_or_method(ccx, &m.generics, num_rcvr_type_params); - ty::Method::new( - m.ident, - m_ty_generics, - fty, - m.explicit_self.node, - method_vis, - local_def(m.id), - container, - None - ) + ty_generics_for_fn_or_method(ccx, &m.generics, + (*rcvr_ty_generics).clone()); + ty::Method::new(m.ident, + m_ty_generics, + fty, + m.explicit_self.node, + method_vis, + local_def(m.id), + container, + None) } } @@ -634,32 +455,30 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ms.as_slice(), selfty, &ty_generics, - generics, parent_visibility); for trait_ref in opt_trait_ref.iter() { 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); // Run convert_methods on the provided methods. let (_, provided_methods) = 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, TraitContainer(local_def(it.id)), provided_methods.as_slice(), untransformed_rcvr_ty, &trait_def.generics, - generics, it.vis); // We need to do this *after* converting methods, since // convert_methods produces a tcache entry that is wrong for // 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) => { 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); - 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); // 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 { _ => {} } - match it.node { + let (generics, sized, supertraits) = match it.node { ast::ItemTrait(ref generics, sized, ref supertraits, _) => { - let self_ty = ty::mk_self(tcx, def_id); - 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 + (generics, sized, supertraits) } ref s => { tcx.sess.span_bug( it.span, 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, + 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> = 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; } 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, it.id, fn_style, @@ -957,7 +869,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) ast::ItemEnum(_, ref generics) => { // Create a new generic polytype. 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 tpt = ty_param_bounds_and_ty { generics: ty_generics, @@ -972,7 +884,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) } ast::ItemStruct(_, ref 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 tpt = ty_param_bounds_and_ty { generics: ty_generics, @@ -1001,10 +913,7 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, } ast::ForeignItemStatic(t, _) => { ty::ty_param_bounds_and_ty { - generics: ty::Generics { - type_param_defs: Rc::new(Vec::new()), - region_param_defs: Rc::new(Vec::new()), - }, + generics: ty::Generics::empty(), ty: ast_ty_to_ty(ccx, &ExplicitRscope, &*t) } } @@ -1013,75 +922,139 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, fn ty_generics_for_type(ccx: &CrateCtxt, generics: &ast::Generics) - -> ty::Generics { - ty_generics(ccx, &generics.lifetimes, &generics.ty_params, 0) + -> ty::Generics +{ + 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, generics: &ast::Generics, - base_index: uint) - -> ty::Generics { + base_generics: ty::Generics) + -> ty::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, + space: subst::ParamSpace, lifetimes: &Vec, - ty_params: &OwnedSlice, - base_index: uint) -> ty::Generics { - return ty::Generics { - region_param_defs: Rc::new(lifetimes.iter().map(|l| { - ty::RegionParameterDef { name: l.name, - def_id: local_def(l.id) } - }).collect()), - type_param_defs: Rc::new(ty_params.iter().enumerate().map(|(offset, param)| { - let existing_def_opt = { - let ty_param_defs = ccx.tcx.ty_param_defs.borrow(); - ty_param_defs.find(¶m.id).map(|def| def.clone()) - }; - existing_def_opt.unwrap_or_else(|| { - let param_ty = ty::param_ty {idx: base_index + offset, - def_id: local_def(param.id)}; - let bounds = Rc::new(compute_bounds(ccx, - param_ty, - ¶m.bounds, - param.sized, - param.ident, - param.span)); - let default = param.default.map(|path| { - let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*path); - let cur_idx = param_ty.idx; - - ty::walk_ty(ty, |t| { - match ty::get(t).sty { - ty::ty_param(p) => if p.idx > cur_idx { - ccx.tcx.sess.span_err(path.span, - "type parameters with a default cannot use \ - forward declared identifiers") - }, - _ => {} - } - }); + types: &OwnedSlice, + base_generics: ty::Generics) + -> ty::Generics +{ + let mut result = base_generics; + + for (i, l) in lifetimes.iter().enumerate() { + result.regions.push(space, + ty::RegionParameterDef { name: l.name, + space: space, + index: i, + def_id: local_def(l.id) }); + } - ty - }); + for (i, param) in types.iter().enumerate() { + let def = get_or_create_type_parameter_def(ccx, space, param, i); + debug!("def for param: {}", def.repr(ccx.tcx)); + result.types.push(space, def); + } - let def = ty::TypeParameterDef { - ident: param.ident, - def_id: local_def(param.id), - bounds: bounds, - default: default - }; - debug!("def for param: {}", def.repr(ccx.tcx)); - ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); - def - }) - }).collect()), - }; + 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(¶m.id) { + Some(d) => { return (*d).clone(); } + None => { } + } + + let param_ty = ty::ParamTy {space: space, + idx: index, + def_id: local_def(param.id)}; + let bounds = Rc::new(compute_bounds(ccx, + param_ty, + ¶m.bounds, + param.sized, + param.ident, + param.span)); + let default = param.default.map(|path| { + let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*path); + let cur_idx = param_ty.idx; + + ty::walk_ty(ty, |t| { + match ty::get(t).sty { + ty::ty_param(p) => if p.idx > cur_idx { + ccx.tcx.sess.span_err( + path.span, + "type parameters with a default cannot use \ + forward declared identifiers") + }, + _ => {} + } + }); + + ty + }); + + let def = ty::TypeParameterDef { + space: space, + index: index, + ident: param.ident, + def_id: local_def(param.id), + bounds: bounds, + default: default + }; + + ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); + + def + } fn compute_bounds( ccx: &CrateCtxt, - param_ty: ty::param_ty, + param_ty: ty::ParamTy, ast_bounds: &OwnedSlice, sized: ast::Sized, ident: ast::Ident, @@ -1101,7 +1074,8 @@ fn ty_generics(ccx: &CrateCtxt, for ast_bound in ast_bounds.iter() { match *ast_bound { 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); if !ty::try_add_builtin_trait( ccx.tcx, trait_ref.def_id, @@ -1117,15 +1091,15 @@ fn ty_generics(ccx: &CrateCtxt, UnboxedFnTyParamBound(ref unboxed_function) => { 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, + param_ty.space, param_ty.idx, 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)); } @@ -1196,7 +1170,8 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, } 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 input_tys = decl.inputs .iter() @@ -1225,19 +1200,17 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, } pub fn mk_item_substs(ccx: &CrateCtxt, - ty_generics: &ty::Generics, - self_ty: Option) + ty_generics: &ty::Generics) -> subst::Substs { - let params: Vec = - ty_generics.type_param_defs().iter().enumerate().map( - |(i, t)| ty::mk_param(ccx.tcx, i, t.def_id)).collect(); + let types = + ty_generics.types.map( + |def| ty::mk_param_from_def(ccx.tcx, def)); - let regions: Vec = - ty_generics.region_param_defs().iter().enumerate().map( - |(i, l)| ty::ReEarlyBound(l.def_id.node, i, l.name)).collect(); + let regions = + ty_generics.regions.map( + |def| ty::ReEarlyBound(def.def_id.node, def.space, + def.index, def.name)); - subst::Substs {regions: subst::NonerasedRegions(regions), - self_ty: self_ty, - tps: params} + subst::Substs::new(types, regions) } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 5099cc9c5a858..ac6851518083d 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -53,7 +53,7 @@ use middle::ty::{FloatVar, FnSig, IntVar, TyVar}; use middle::ty::{IntType, UintType}; use middle::ty::{BuiltinBounds}; use middle::ty; -use middle::typeck::infer::{then, ToUres}; +use middle::typeck::infer::{ToUres}; use middle::typeck::infer::glb::Glb; use middle::typeck::infer::lub::Lub; use middle::typeck::infer::sub::Sub; @@ -84,113 +84,115 @@ pub trait Combine { fn contratys(&self, a: ty::t, b: ty::t) -> cres; fn tys(&self, a: ty::t, b: ty::t) -> cres; - fn tps(&self, as_: &[ty::t], bs: &[ty::t]) -> cres > { - - // Note: type parameters are always treated as *invariant* - // (otherwise the type system would be unsound). In the - // 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(), - bs.len()))) + fn tps(&self, + space: subst::ParamSpace, + as_: &[ty::t], + bs: &[ty::t]) + -> cres> + { + // 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. + + if as_.len() != bs.len() { + return Err(ty::terr_ty_param_size(expected_found(self, + as_.len(), + bs.len()))); } - } - - fn self_tys(&self, a: Option, b: Option) - -> cres> { - match (a, b) { - (None, None) => { - Ok(None) - } - (Some(a), Some(b)) => { - // FIXME(#5781) this should be eq_tys - // eq_tys(self, a, b).then(|| Ok(Some(a)) ) - self.contratys(a, b).and_then(|t| Ok(Some(t))) + match space { + 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 }) } - (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"); + + subst::TypeSpace | subst::FnSpace => { + try!(result::fold_(as_ + .iter() + .zip(bs.iter()) + .map(|(a, b)| eq_tys(self, *a, *b)))); + Ok(Vec::from_slice(as_)) } } } fn substs(&self, item_def_id: ast::DefId, - as_: &subst::Substs, - bs: &subst::Substs) + a_subst: &subst::Substs, + b_subst: &subst::Substs) -> cres { + let variances = ty::item_variances(self.infcx().tcx, item_def_id); + let mut substs = subst::Substs::empty(); + + for &space in subst::ParamSpace::all().iter() { + let a_tps = a_subst.types.get_vec(space); + let b_tps = b_subst.types.get_vec(space); + let tps = if_ok!(self.tps(space, + a_tps.as_slice(), + 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; + } + + return Ok(substs); + fn relate_region_params(this: &C, item_def_id: ast::DefId, - a: &subst::RegionSubsts, - b: &subst::RegionSubsts) - -> cres { + variances: &Vec, + a_rs: &Vec, + b_rs: &Vec) + -> cres> + { let tcx = this.infcx().tcx; - match (a, b) { - (&subst::ErasedRegions, _) | (_, &subst::ErasedRegions) => { - Ok(subst::ErasedRegions) - } - - (&subst::NonerasedRegions(ref a_rs), - &subst::NonerasedRegions(ref b_rs)) => { - let variances = ty::item_variances(tcx, item_def_id); - let region_params = &variances.region_params; - let num_region_params = region_params.len(); - - debug!("relate_region_params(\ - item_def_id={}, \ - a_rs={}, \ - b_rs={}, - region_params={})", - item_def_id.repr(tcx), - a_rs.repr(tcx), - b_rs.repr(tcx), - region_params.repr(tcx)); - - assert_eq!(num_region_params, a_rs.len()); - assert_eq!(num_region_params, b_rs.len()); - let mut rs = vec!(); - for i in range(0, num_region_params) { - let a_r = *a_rs.get(i); - let b_r = *b_rs.get(i); - let variance = *region_params.get(i); - let r = match variance { - ty::Invariant => { - eq_regions(this, a_r, b_r) - .and_then(|()| Ok(a_r)) - } - ty::Covariant => this.regions(a_r, b_r), - ty::Contravariant => this.contraregions(a_r, b_r), - ty::Bivariant => Ok(a_r), - }; - rs.push(if_ok!(r)); + let num_region_params = variances.len(); + + debug!("relate_region_params(\ + item_def_id={}, \ + a_rs={}, \ + b_rs={}, + variances={})", + item_def_id.repr(tcx), + a_rs.repr(tcx), + b_rs.repr(tcx), + variances.repr(tcx)); + + assert_eq!(num_region_params, a_rs.len()); + assert_eq!(num_region_params, b_rs.len()); + let mut rs = vec!(); + for i in range(0, num_region_params) { + let a_r = *a_rs.get(i); + let b_r = *b_rs.get(i); + let variance = *variances.get(i); + let r = match variance { + ty::Invariant => { + eq_regions(this, a_r, b_r) + .and_then(|()| Ok(a_r)) } - Ok(subst::NonerasedRegions(rs)) - } + ty::Covariant => this.regions(a_r, b_r), + ty::Contravariant => this.contraregions(a_r, b_r), + ty::Bivariant => Ok(a_r), + }; + rs.push(if_ok!(r)); } + Ok(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, diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 7c313d53b2c3e..bcd66ed4d66f2 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -61,6 +61,7 @@ time of error detection. use std::collections::HashSet; use middle::def; +use middle::subst; use middle::ty; use middle::ty::{Region, ReFree}; use middle::typeck::infer; @@ -1055,9 +1056,10 @@ impl<'a> Rebuilder<'a> { ty: _ } = ty::lookup_item_type(self.tcx, did); - let expected = generics.region_param_defs().len(); - let lifetimes = &path.segments.last() - .unwrap().lifetimes; + let expected = + generics.regions.len(subst::TypeSpace); + let lifetimes = + &path.segments.last().unwrap().lifetimes; let mut insert = Vec::new(); if lifetimes.len() == 0 { let anon = self.cur_anon.get(); diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 646dad879eef3..f43ee1e8aabaa 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -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_rvar}; -use std::collections::HashMap; +use middle::subst; +use middle::subst::Substs; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid}; use middle::ty; 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::error_reporting::ErrorReporting; use std::cell::{Cell, RefCell}; +use std::collections::HashMap; use std::rc::Rc; use syntax::ast; use syntax::codemap; @@ -588,6 +590,7 @@ impl<'a> InferCtxt<'a> { let vals = &mut ty_var_bindings.vals; vals.insert(id, Root(Bounds { lb: None, ub: None }, 0u)); } + debug!("created type variable {}", TyVid(id)); return TyVid(id); } @@ -623,13 +626,35 @@ impl<'a> InferCtxt<'a> { pub fn region_vars_for_defs(&self, span: Span, - defs: &[ty::RegionParameterDef]) + defs: &Vec) -> Vec { defs.iter() .map(|d| self.next_region_var(EarlyBoundRegion(span, d.name))) .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 { self.region_vars.new_bound(binder_id) } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 56fc79fa5e702..b5c103b84812a 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -66,6 +66,7 @@ use driver::config; use middle::def; use middle::resolve; use middle::subst; +use middle::subst::VecPerParamSpace; use middle::ty; use util::common::time; use util::ppaux::Repr; @@ -73,7 +74,6 @@ use util::ppaux; use util::nodemap::{DefIdMap, FnvHashMap}; use std::cell::RefCell; -use std::rc::Rc; use syntax::codemap::Span; use syntax::print::pprust::*; use syntax::{ast, ast_map, abi}; @@ -87,9 +87,9 @@ pub mod coherence; pub mod variance; #[deriving(Clone, Encodable, Decodable, PartialEq, PartialOrd)] -pub enum param_index { - param_numbered(uint), - param_self +pub struct param_index { + pub space: subst::ParamSpace, + pub index: uint } #[deriving(Clone, Encodable, Decodable)] @@ -176,8 +176,9 @@ impl MethodCall { pub type MethodMap = RefCell>; pub type vtable_param_res = Vec; + // Resolutions for bounds of all parameters, left to right, for a given path. -pub type vtable_res = Vec; +pub type vtable_res = VecPerParamSpace; #[deriving(Clone)] pub enum vtable_origin { @@ -197,6 +198,14 @@ pub enum vtable_origin { and the second is the bound number (identifying baz) */ 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 { @@ -213,6 +222,10 @@ impl Repr for vtable_origin { 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>; -// Information about the vtable resolutions for a trait impl. -// 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>; +pub type impl_vtable_map = RefCell>; pub struct CrateCtxt<'a> { // 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, item_substs.repr(tcx)); - assert!(item_substs.substs.tps.iter(). - all(|t| !ty::type_needs_infer(*t))); + assert!(item_substs.substs.types.all(|t| !ty::type_needs_infer(*t))); 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 { ty::ty_param_bounds_and_ty { - generics: ty::Generics {type_param_defs: Rc::new(Vec::new()), - region_param_defs: Rc::new(Vec::new())}, + generics: ty::Generics {types: VecPerParamSpace::empty(), + regions: VecPerParamSpace::empty()}, ty: t } } diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 80bc09904ec18..3731990e61faa 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -195,14 +195,15 @@ represents the "variance transform" as defined in the paper: use std::collections::HashMap; use arena; use arena::Arena; +use rl = middle::resolve_lifetime; use middle::subst; +use middle::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace}; use middle::ty; use std::fmt; use std::rc::Rc; use syntax::ast; use syntax::ast_map; use syntax::ast_util; -use syntax::owned_slice::OwnedSlice; use syntax::visit; use syntax::visit::Visitor; use util::ppaux::Repr; @@ -266,11 +267,17 @@ struct TermsContext<'a> { inferred_infos: Vec> , } -enum ParamKind { TypeParam, RegionParam, SelfParam } +#[deriving(Show)] +enum ParamKind { + TypeParam, + RegionParam +} struct InferredInfo<'a> { item_id: ast::NodeId, kind: ParamKind, + space: ParamSpace, + index: uint, param_id: ast::NodeId, 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 // no type/region parameters empty_variances: Rc::new(ty::ItemVariances { - self_param: None, - type_params: OwnedSlice::empty(), - region_params: OwnedSlice::empty() + types: VecPerParamSpace::empty(), + regions: VecPerParamSpace::empty() }) }; @@ -303,12 +309,15 @@ impl<'a> TermsContext<'a> { fn add_inferred(&mut self, item_id: ast::NodeId, kind: ParamKind, + space: ParamSpace, index: uint, param_id: ast::NodeId) { let inf_index = InferredIndex(self.inferred_infos.len()); let term = self.arena.alloc(|| InferredTerm(inf_index)); self.inferred_infos.push(InferredInfo { item_id: item_id, kind: kind, + space: space, + index: index, param_id: param_id, term: term }); 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. match item.node { 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::ItemTrait(ref generics, _, _, _) => { 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() { - 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, @@ -399,9 +408,9 @@ struct ConstraintContext<'a> { // are indexed by the `ParamKind` (type, lifetime, self). Note // that there are no marker types for self, so the entries for // self are always None. - invariant_lang_items: [Option, ..3], - covariant_lang_items: [Option, ..3], - contravariant_lang_items: [Option, ..3], + invariant_lang_items: [Option, ..2], + covariant_lang_items: [Option, ..2], + contravariant_lang_items: [Option, ..2], // These are pointers to common `ConstantTerm` instances covariant: VarianceTermPtr<'a>, @@ -422,9 +431,9 @@ struct Constraint<'a> { fn add_constraints_from_crate<'a>(terms_cx: TermsContext<'a>, krate: &ast::Crate) -> ConstraintContext<'a> { - let mut invariant_lang_items = [None, ..3]; - let mut covariant_lang_items = [None, ..3]; - let mut contravariant_lang_items = [None, ..3]; + let mut invariant_lang_items = [None, ..2]; + let mut covariant_lang_items = [None, ..2]; + let mut contravariant_lang_items = [None, ..2]; covariant_lang_items[TypeParam as uint] = terms_cx.tcx.lang_items.covariant_type(); @@ -547,7 +556,7 @@ impl<'a> ConstraintContext<'a> { let tcx = self.terms_cx.tcx; assert!(is_lifetime(&tcx.map, param_id)); match tcx.named_region_map.find(¶m_id) { - Some(&ast::DefEarlyBoundRegion(_, lifetime_decl_id)) + Some(&rl::DefEarlyBoundRegion(_, _, lifetime_decl_id)) => lifetime_decl_id, Some(_) => fail!("should not encounter non early-bound cases"), @@ -611,6 +620,7 @@ impl<'a> ConstraintContext<'a> { param_def_id: ast::DefId, item_def_id: ast::DefId, kind: ParamKind, + space: ParamSpace, index: uint) -> VarianceTermPtr<'a> { /*! @@ -637,9 +647,8 @@ impl<'a> ConstraintContext<'a> { // variance already inferred, just look it up. let variances = ty::item_variances(self.tcx(), item_def_id); let variance = match kind { - SelfParam => variances.self_param.unwrap(), - TypeParam => *variances.type_params.get(index), - RegionParam => *variances.region_params.get(index), + TypeParam => *variances.types.get(space, index), + RegionParam => *variances.regions.get(space, index), }; self.constant_term(variance) } @@ -736,17 +745,50 @@ impl<'a> ConstraintContext<'a> { ty::ty_enum(def_id, ref substs) | ty::ty_struct(def_id, ref substs) => { let item_type = ty::lookup_item_type(self.tcx(), def_id); - self.add_constraints_from_substs(def_id, &item_type.generics, - substs, variance); + let generics = &item_type.generics; + + // 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, .. }) => { let trait_def = ty::lookup_trait_def(self.tcx(), def_id); - self.add_constraints_from_substs(def_id, &trait_def.generics, - substs, variance); + let generics = &trait_def.generics; + + // 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); match self.terms_cx.inferred_map.find(&def_id.node) { 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_closure(box ty::ClosureTy { ref sig, @@ -796,28 +832,28 @@ impl<'a> ConstraintContext<'a> { /// object, etc) appearing in a context with ambient variance `variance` fn add_constraints_from_substs(&mut self, def_id: ast::DefId, - generics: &ty::Generics, + type_param_defs: &Vec, + region_param_defs: &Vec, substs: &subst::Substs, variance: VarianceTermPtr<'a>) { 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 = - 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); - 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 { - subst::ErasedRegions => {} - subst::NonerasedRegions(ref rps) => { - for (i, p) in generics.region_param_defs().iter().enumerate() { - let variance_decl = - self.declared_variance(p.def_id, def_id, RegionParam, i); - let variance_i = self.xform(variance, variance_decl); - self.add_constraints_from_region(*rps.get(i), variance_i); - } - } + for p in region_param_defs.iter() { + let variance_decl = + self.declared_variance(p.def_id, def_id, + RegionParam, p.space, p.index); + let variance_i = self.xform(variance, variance_decl); + 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, variance: VarianceTermPtr<'a>) { match region { - ty::ReEarlyBound(param_id, _, _) => { + ty::ReEarlyBound(param_id, _, _, _) => { if self.is_to_be_inferred(param_id) { let index = self.inferred_index(param_id); self.add_constraint(index, variance); @@ -931,7 +967,7 @@ impl<'a> SolveContext<'a> { let new_value = glb(variance, old_value); if old_value != new_value { debug!("Updating inferred {} (node {}) \ - from {:?} to {:?} due to {}", + from {} to {} due to {}", inferred, self.terms_cx .inferred_infos @@ -965,32 +1001,29 @@ impl<'a> SolveContext<'a> { let num_inferred = self.terms_cx.num_inferred(); while index < num_inferred { let item_id = inferred_infos.get(index).item_id; - let mut self_param = None; - let mut type_params = vec!(); - let mut region_params = vec!(); + let mut types = VecPerParamSpace::empty(); + let mut regions = VecPerParamSpace::empty(); while index < num_inferred && inferred_infos.get(index).item_id == item_id { 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 { - SelfParam => { - assert!(self_param.is_none()); - self_param = Some(*solutions.get(index)); - } TypeParam => { - type_params.push(*solutions.get(index)); + types.push(info.space, variance); } RegionParam => { - region_params.push(*solutions.get(index)); + regions.push(info.space, variance); } } index += 1; } let item_variances = ty::ItemVariances { - self_param: self_param, - type_params: OwnedSlice::from_vec(type_params), - region_params: OwnedSlice::from_vec(region_params) + types: types, + regions: regions }; debug!("item_id={} item_variances={}", item_id, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index ff57747256e19..31994d08d2347 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -9,17 +9,18 @@ // except according to those terms. +use middle::def; use middle::subst; -use middle::subst::Subst; +use middle::subst::{VecPerParamSpace,Subst}; use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{BoundRegion, BrAnon, BrNamed}; 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, ReEmpty}; 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_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; 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()`. match region { ty::ReScope(_) => prefix.to_string(), - ty::ReEarlyBound(_, _, name) => { + ty::ReEarlyBound(_, _, _, name) => { token::get_name(name).get().to_string() } 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_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) { Some(def) => token::get_ident(def.ident).get().to_string(), // This can only happen when a type mismatch error happens and @@ -391,29 +392,25 @@ pub fn ty_to_str(cx: &ctxt, typ: t) -> String { format!("{}:{:?}", ident, did) } } - ty_self(..) => "Self".to_string(), ty_enum(did, ref substs) | ty_struct(did, ref substs) => { - let base = ty::item_path_str(cx, did); - parameterized(cx, - base.as_slice(), - &substs.regions, - substs.tps.as_slice(), - did, - false) + let base = ty::item_path_str(cx, did); + let generics = ty::lookup_item_type(cx, did).generics; + parameterized(cx, base.as_slice(), substs, &generics) } ty_trait(box ty::TyTrait { def_id: did, ref substs, store, ref bounds }) => { - let base = ty::item_path_str(cx, did); - let ty = parameterized(cx, base.as_slice(), &substs.regions, - substs.tps.as_slice(), did, true); - let bound_sep = if bounds.is_empty() { "" } else { ":" }; - let bound_str = bounds.repr(cx); - format!("{}{}{}{}", - trait_store_to_str(cx, store), - ty, - bound_sep, - bound_str) + let base = ty::item_path_str(cx, did); + let trait_def = ty::lookup_trait_def(cx, did); + let ty = parameterized(cx, base.as_slice(), + substs, &trait_def.generics); + let bound_sep = if bounds.is_empty() { "" } else { ":" }; + let bound_str = bounds.repr(cx); + format!("{}{}{}{}", + trait_store_to_str(cx, store), + ty, + bound_sep, + bound_str) } ty_str => "str".to_string(), ty_vec(ref mt, sz) => { @@ -429,39 +426,38 @@ pub fn ty_to_str(cx: &ctxt, typ: t) -> String { pub fn parameterized(cx: &ctxt, base: &str, - regions: &subst::RegionSubsts, - tps: &[ty::t], - did: ast::DefId, - is_trait: bool) - -> String { + substs: &subst::Substs, + generics: &ty::Generics) + -> String +{ let mut strs = Vec::new(); - match *regions { + + match substs.regions { subst::ErasedRegions => { } subst::NonerasedRegions(ref regions) => { 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 { - ty::lookup_trait_def(cx, did).generics.clone() - } else { - ty::lookup_item_type(cx, did).generics - }; - let ty_params = generics.type_param_defs(); + let tps = substs.types.get_vec(subst::TypeSpace); + let ty_params = generics.types.get_vec(subst::TypeSpace); let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some()); - let num_defaults = if has_defaults { - // 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 - }; + let num_defaults = if has_defaults && !cx.sess.verbose() { ty_params.iter().zip(tps.iter()).rev().take_while(|&(def, &actual)| { - substs.tps.pop(); match def.default { - Some(default) => default.subst(cx, &substs) == actual, + Some(default) => default.subst(cx, substs) == actual, None => false } }).count() @@ -473,6 +469,12 @@ pub fn parameterized(cx: &ctxt, 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 { format!("{}<{}>", base, strs.connect(",")) } else { @@ -554,6 +556,12 @@ impl Repr for Vec { } } +impl Repr for def::Def { + fn repr(&self, _tcx: &ctxt) -> String { + format!("{:?}", *self) + } +} + impl Repr for ty::TypeParameterDef { fn repr(&self, tcx: &ctxt) -> String { format!("TypeParameterDef({:?}, {})", self.def_id, @@ -577,10 +585,18 @@ impl Repr for ty::t { impl Repr for subst::Substs { fn repr(&self, tcx: &ctxt) -> String { - format!("substs(regions={}, self_ty={}, tps={})", - self.regions.repr(tcx), - self.self_ty.repr(tcx), - self.tps.repr(tcx)) + format!("Substs[types={}, regions={}]", + self.types.repr(tcx), + self.regions.repr(tcx)) + } +} + +impl Repr for subst::VecPerParamSpace { + 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 { fn repr(&self, tcx: &ctxt) -> String { format!("item({})", tcx.map.node_to_str(self.id)) @@ -665,11 +687,12 @@ impl Repr for ty::BoundRegion { impl Repr for ty::Region { fn repr(&self, tcx: &ctxt) -> String { match *self { - ty::ReEarlyBound(id, index, name) => { - format!("ReEarlyBound({}, {}, {})", - id, - index, - token::get_name(name)) + ty::ReEarlyBound(id, space, index, name) => { + format!("ReEarlyBound({}, {}, {}, {})", + id, + space, + index, + token::get_name(name)) } ty::ReLateBound(binder_id, ref bound_region) => { @@ -697,9 +720,7 @@ impl Repr for ty::Region { } ty::ReInfer(ReSkolemized(id, ref bound_region)) => { - format!("re_skolemized({}, {})", - id, - bound_region.repr(tcx)) + format!("re_skolemized({}, {})", id, bound_region.repr(tcx)) } ty::ReEmpty => { @@ -753,18 +774,18 @@ impl Repr for ty::ty_param_bounds_and_ty { impl Repr for ty::Generics { fn repr(&self, tcx: &ctxt) -> String { - format!("Generics(type_param_defs: {}, region_param_defs: {})", - self.type_param_defs().repr(tcx), - self.region_param_defs().repr(tcx)) + format!("Generics(types: {}, regions: {})", + self.types.repr(tcx), + self.regions.repr(tcx)) } } impl Repr for ty::ItemVariances { fn repr(&self, tcx: &ctxt) -> String { - format!("IterVariances(self_param={}, type_params={}, region_params={})", - self.self_param.repr(tcx), - self.type_params.repr(tcx), - self.region_params.repr(tcx)) + format!("ItemVariances(types={}, \ + regions={})", + self.types.repr(tcx), + self.regions.repr(tcx)) } } @@ -952,23 +973,8 @@ impl UserString for ty::BuiltinBounds { impl UserString for ty::TraitRef { fn user_string(&self, tcx: &ctxt) -> String { let base = ty::item_path_str(tcx, self.def_id); - if tcx.sess.verbose() && self.substs.self_ty.is_some() { - let mut all_tps = self.substs.tps.clone(); - 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) - } + let trait_def = ty::lookup_trait_def(tcx, self.def_id); + parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index db65939bdfcc7..dd6cc978ae71c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -27,6 +27,7 @@ use rustc::metadata::csearch; use rustc::metadata::decoder; use rustc::middle::def; use rustc::middle::subst; +use rustc::middle::subst::VecPerParamSpace; use rustc::middle::ty; use std::rc::Rc; @@ -53,6 +54,12 @@ impl, U> Clean> for Vec { } } +impl, U> Clean> for VecPerParamSpace { + fn clean(&self) -> VecPerParamSpace { + self.map(|x| x.clean()) + } +} + impl, U> Clean for Gc { fn clean(&self) -> U { (**self).clean() @@ -488,17 +495,17 @@ impl Clean for ast::TyParamBound { } 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 { global: false, segments: vec![PathSegment { name: name.to_string(), - lifetimes: match substs.regions { - subst::ErasedRegions => Vec::new(), - subst::NonerasedRegions(ref v) => { - v.iter().filter_map(|v| v.clean()).collect() - } - }, - types: substs.tps.clean(), + lifetimes: lifetimes, + types: types, }], } } @@ -578,12 +585,8 @@ impl Clean> for ty::ParamBounds { impl Clean>> for subst::Substs { fn clean(&self) -> Option> { let mut v = Vec::new(); - match self.regions { - subst::NonerasedRegions(..) => v.push(RegionBound), - subst::ErasedRegions => {} - } - v.extend(self.tps.iter().map(|t| TraitBound(t.clean()))); - + v.extend(self.regions().iter().map(|_| RegionBound)); + v.extend(self.types.iter().map(|t| TraitBound(t.clean()))); if v.len() > 0 {Some(v)} else {None} } } @@ -617,7 +620,7 @@ impl Clean> for ty::Region { ty::ReStatic => Some(Lifetime("static".to_string())), ty::ReLateBound(_, ty::BrNamed(_, name)) => 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::ReFree(..) | @@ -638,17 +641,41 @@ pub struct Generics { impl Clean for ast::Generics { fn clean(&self) -> Generics { Generics { - lifetimes: self.lifetimes.clean().move_iter().collect(), - type_params: self.ty_params.clean().move_iter().collect(), + lifetimes: self.lifetimes.clean(), + type_params: self.ty_params.clean(), } } } impl Clean for ty::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 { - lifetimes: self.region_param_defs.clean(), - type_params: self.type_param_defs.clean(), + type_params: self.types.get_vec(space).clean(), + lifetimes: self.regions.get_vec(space).clean(), } } } @@ -1259,8 +1286,13 @@ impl Clean for ty::t { } ty::ty_tup(ref t) => Tuple(t.iter().map(|t| t.clean()).collect()), - ty::ty_param(ref p) => Generic(p.def_id), - ty::ty_self(did) => Self(did), + ty::ty_param(ref p) => { + if p.space == subst::SelfSpace { + Self(p.def_id) + } else { + Generic(p.def_id) + } + } ty::ty_infer(..) => fail!("ty_infer"), ty::ty_err => fail!("ty_err"), @@ -1968,7 +2000,7 @@ fn resolve_type(path: Path, tpbs: Option>, ast::TyFloat(ast::TyF64) => return Primitive(F64), 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), _ => {} }; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7c1e82a2a6f72..941078b158b87 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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, // used to drive conditional compilation pub type CrateConfig = Vec>; diff --git a/src/test/compile-fail/bad-mid-path-type-params.rs b/src/test/compile-fail/bad-mid-path-type-params.rs index 58ed6624cbf3b..7ce6f7188b84f 100644 --- a/src/test/compile-fail/bad-mid-path-type-params.rs +++ b/src/test/compile-fail/bad-mid-path-type-params.rs @@ -45,11 +45,16 @@ impl Trait for S2 { fn foo<'a>() { let _ = S::new::(1, 1.0); - //~^ ERROR the impl referenced by this path needs 1 type parameter, but 0 type parameters were supplied - let _ = S::<'a,int>::new::(1, 1.0); //~ ERROR expected 0 lifetime parameters + //~^ ERROR too many type parameters provided + + let _ = S::<'a,int>::new::(1, 1.0); + //~^ ERROR too many lifetime parameters provided + let _: S2 = Trait::new::(1, 1.0); - //~^ ERROR the trait referenced by this path needs 1 type parameter, but 0 type parameters were supplied - let _: S2 = Trait::<'a,int>::new::(1, 1.0); //~ ERROR expected 0 lifetime parameters + //~^ ERROR too many type parameters provided + + let _: S2 = Trait::<'a,int>::new::(1, 1.0); + //~^ ERROR too many lifetime parameters provided } fn main() {} diff --git a/src/test/compile-fail/generic-impl-less-params-with-defaults.rs b/src/test/compile-fail/generic-impl-less-params-with-defaults.rs index d6a47ffd7863b..7e7eee3cfaca8 100644 --- a/src/test/compile-fail/generic-impl-less-params-with-defaults.rs +++ b/src/test/compile-fail/generic-impl-less-params-with-defaults.rs @@ -18,7 +18,5 @@ impl Foo { fn main() { Foo::::new(); - //~^ ERROR the impl referenced by this path needs at least 2 type parameters, - // but 1 was supplied - //~^^^ ERROR not enough type parameters provided: expected at least 2, found 1 + //~^ ERROR too few type parameters provided } diff --git a/src/test/compile-fail/generic-impl-more-params-with-defaults.rs b/src/test/compile-fail/generic-impl-more-params-with-defaults.rs index b0040878d628c..ceaed9438be53 100644 --- a/src/test/compile-fail/generic-impl-more-params-with-defaults.rs +++ b/src/test/compile-fail/generic-impl-more-params-with-defaults.rs @@ -20,7 +20,5 @@ impl Vec { fn main() { Vec::::new(); - //~^ ERROR the impl referenced by this path needs at most 2 type parameters, - // but 3 were supplied - //~^^^ ERROR too many type parameters provided: expected at most 2, found 3 + //~^ ERROR too many type parameters provided } diff --git a/src/test/compile-fail/issue-11844.rs b/src/test/compile-fail/issue-11844.rs index 4e11481b5d2e3..e5400bf60c361 100644 --- a/src/test/compile-fail/issue-11844.rs +++ b/src/test/compile-fail/issue-11844.rs @@ -12,7 +12,7 @@ fn main() { let a = Some(box 1); match a { Ok(a) => //~ ERROR: mismatched types - println!("{}",a), //~ ERROR: failed to find an implementation of trait + println!("{}",a), None => fail!() } } diff --git a/src/test/compile-fail/issue-13466.rs b/src/test/compile-fail/issue-13466.rs index 44a52148e5b9e..14cc0a82df5b2 100644 --- a/src/test/compile-fail/issue-13466.rs +++ b/src/test/compile-fail/issue-13466.rs @@ -15,7 +15,6 @@ pub fn main() { // the actual arm `Result` has two. typeck should not be // tricked into looking up a non-existing second type parameter. let _x: uint = match Some(1u) { - //~^ ERROR mismatched types: expected `uint` but found `` Ok(u) => u, //~ ERROR mismatched types: expected `core::option::Option` Err(e) => fail!(e) //~ ERROR mismatched types: expected `core::option::Option` }; diff --git a/src/test/compile-fail/issue-7092.rs b/src/test/compile-fail/issue-7092.rs index bcecab8075810..4b1c67918745a 100644 --- a/src/test/compile-fail/issue-7092.rs +++ b/src/test/compile-fail/issue-7092.rs @@ -15,7 +15,6 @@ fn foo(x: Whatever) { match x { Some(field) => field.access(), //~^ ERROR: mismatched types: expected `Whatever` but found - //~^^ ERROR: does not implement any method in scope named `access` } } diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index ae8444f015e7e..da4f9846187ca 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -14,7 +14,7 @@ // Regions that just appear in normal spots are contravariant: #[rustc_variance] -struct Test2<'a, 'b, 'c> { //~ ERROR region_params=[-, -, -] +struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]] x: &'a int, y: &'b [int], c: &'c str @@ -23,7 +23,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR region_params=[-, -, -] // Those same annotations in function arguments become covariant: #[rustc_variance] -struct Test3<'a, 'b, 'c> { //~ ERROR region_params=[+, +, +] +struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]] x: extern "Rust" fn(&'a int), y: extern "Rust" fn(&'b [int]), c: extern "Rust" fn(&'c str), @@ -32,7 +32,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR region_params=[+, +, +] // Mutability induces invariance: #[rustc_variance] -struct Test4<'a, 'b> { //~ ERROR region_params=[-, o] +struct Test4<'a, 'b> { //~ ERROR regions=[[-, o];[];[]] x: &'a mut &'b int, } @@ -40,7 +40,7 @@ struct Test4<'a, 'b> { //~ ERROR region_params=[-, o] // contravariant context: #[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), } @@ -50,21 +50,21 @@ struct Test5<'a, 'b> { //~ ERROR region_params=[+, o] // argument list occurs in an invariant context. #[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), } // No uses at all is bivariant: #[rustc_variance] -struct Test7<'a> { //~ ERROR region_params=[*] +struct Test7<'a> { //~ ERROR regions=[[*];[];[]] x: int } // Try enums too. #[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)), Test8B(&'b [int]), Test8C(&'b mut &'c str), diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index fa22bb41aa321..913335fa51b1a 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -13,29 +13,29 @@ // Try enums too. #[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)), Test8B(&'b [int]), Test8C(&'b mut &'c str), } #[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> } #[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> } #[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> } #[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> }