From 9153d8ad6c8259b3b23187f36dc3d3257a28d91c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 31 May 2014 18:53:13 -0400 Subject: [PATCH] Introduce VecPerParamSpace and use it to represent sets of types and parameters This involves numerous substeps: 1. Treat Self same as any other parameter. 2. No longer compute offsets for method parameters. 3. Store all generic types (both trait/impl and method) with a method, eliminating odd discrepancies. 4. Stop doing unspeakable things to static methods and instead just use the natural types, now that we can easily add the type parameters from trait into the method's polytype. 5. No doubt some more. It was hard to separate these into distinct commits. Fixes #13564 --- src/librustc/metadata/common.rs | 10 +- src/librustc/metadata/csearch.rs | 8 +- src/librustc/metadata/decoder.rs | 68 +- src/librustc/metadata/encoder.rs | 33 +- src/librustc/metadata/tydecode.rs | 103 +- src/librustc/metadata/tyencode.rs | 48 +- src/librustc/middle/astencode.rs | 125 ++- src/librustc/middle/def.rs | 5 +- src/librustc/middle/kind.rs | 143 +-- src/librustc/middle/resolve.rs | 93 +- src/librustc/middle/resolve_lifetime.rs | 66 +- src/librustc/middle/save/mod.rs | 2 +- src/librustc/middle/subst.rs | 453 +++++++-- src/librustc/middle/trans/base.rs | 4 +- src/librustc/middle/trans/callee.rs | 63 +- src/librustc/middle/trans/common.rs | 65 +- src/librustc/middle/trans/debuginfo.rs | 19 +- src/librustc/middle/trans/inline.rs | 16 +- src/librustc/middle/trans/intrinsic.rs | 46 +- src/librustc/middle/trans/meth.rs | 95 +- src/librustc/middle/trans/monomorphize.rs | 64 +- src/librustc/middle/trans/reflect.rs | 1 - src/librustc/middle/trans/type_of.rs | 29 +- src/librustc/middle/ty.rs | 279 +++--- src/librustc/middle/ty_fold.rs | 30 +- src/librustc/middle/typeck/astconv.rs | 125 +-- src/librustc/middle/typeck/check/_match.rs | 29 +- src/librustc/middle/typeck/check/method.rs | 137 ++- src/librustc/middle/typeck/check/mod.rs | 912 +++++++++--------- src/librustc/middle/typeck/check/vtable.rs | 247 ++--- src/librustc/middle/typeck/check/writeback.rs | 21 +- src/librustc/middle/typeck/coherence.rs | 122 +-- src/librustc/middle/typeck/collect.rs | 611 ++++++------ src/librustc/middle/typeck/infer/combine.rs | 184 ++-- .../middle/typeck/infer/error_reporting.rs | 8 +- src/librustc/middle/typeck/infer/mod.rs | 29 +- src/librustc/middle/typeck/mod.rs | 58 +- src/librustc/middle/typeck/variance.rs | 147 +-- src/librustc/util/ppaux.rs | 168 ++-- src/librustdoc/clean/mod.rs | 74 +- src/libsyntax/ast.rs | 8 - .../compile-fail/bad-mid-path-type-params.rs | 13 +- .../generic-impl-less-params-with-defaults.rs | 4 +- .../generic-impl-more-params-with-defaults.rs | 4 +- src/test/compile-fail/issue-11844.rs | 2 +- src/test/compile-fail/issue-13466.rs | 1 - src/test/compile-fail/issue-7092.rs | 1 - .../compile-fail/variance-regions-direct.rs | 14 +- .../compile-fail/variance-regions-indirect.rs | 10 +- 49 files changed, 2571 insertions(+), 2226 deletions(-) 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> }