diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 71a1f1b3f9b20..e2672338a8a0b 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -127,7 +127,7 @@ pub enum astencode_tag { // Reserves 0x50 -- 0x6f tag_table_node_type_subst = 0x58, tag_table_freevars = 0x59, tag_table_tcache = 0x5a, - tag_table_param_bounds = 0x5b, + tag_table_param_defs = 0x5b, tag_table_inferred_modes = 0x5c, tag_table_mutbl = 0x5d, tag_table_last_use = 0x5e, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 74e891a01942f..f7de281194f39 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -210,7 +210,7 @@ pub fn get_field_type(tcx: ty::ctxt, class_id: ast::def_id, debug!("got field data %?", the_field); let ty = decoder::item_type(def, the_field, tcx, cdata); ty::ty_param_bounds_and_ty { - generics: ty::Generics {bounds: @~[], + generics: ty::Generics {type_param_defs: @~[], region_param: None}, ty: ty } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index d9ef30ff297d0..472b455b73531 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -19,7 +19,8 @@ use metadata::csearch::{ProvidedTraitMethodInfo, StaticMethodInfo}; use metadata::csearch; use metadata::cstore; use metadata::decoder; -use metadata::tydecode::{parse_ty_data, parse_def_id, parse_bounds_data, +use metadata::tydecode::{parse_ty_data, parse_def_id, + parse_type_param_def_data, parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::{ty, resolve}; @@ -266,13 +267,14 @@ fn item_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::TraitRef { doc_trait_ref(tp, tcx, cdata) } -fn item_ty_param_bounds(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd, - tag: uint) - -> @~[ty::param_bounds] { +fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd, + tag: uint) + -> @~[ty::TypeParameterDef] { let mut bounds = ~[]; for reader::tagged_docs(item, tag) |p| { - let bd = parse_bounds_data(p.data, p.start, cdata.cnum, tcx, - |_, did| translate_def_id(cdata, did)); + let bd = parse_type_param_def_data( + p.data, p.start, cdata.cnum, tcx, + |_, did| translate_def_id(cdata, did)); bounds.push(bd); } @bounds @@ -378,11 +380,11 @@ pub fn get_trait_def(cdata: cmd, tcx: ty::ctxt) -> ty::TraitDef { let item_doc = lookup_item(item_id, cdata.data); - let tp_bounds = item_ty_param_bounds(item_doc, tcx, cdata, - tag_items_data_item_ty_param_bounds); + let tp_defs = item_ty_param_defs(item_doc, tcx, cdata, + tag_items_data_item_ty_param_bounds); let rp = item_ty_region_param(item_doc); ty::TraitDef { - generics: ty::Generics {bounds: tp_bounds, + generics: ty::Generics {type_param_defs: tp_defs, region_param: rp}, trait_ref: @item_trait_ref(item_doc, tcx, cdata) } @@ -394,12 +396,12 @@ pub fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) let item = lookup_item(id, cdata.data); let t = item_type(ast::def_id { crate: cdata.cnum, node: id }, item, tcx, cdata); - let tp_bounds = if family_has_type_params(item_family(item)) { - item_ty_param_bounds(item, tcx, cdata, tag_items_data_item_ty_param_bounds) + let tp_defs = if family_has_type_params(item_family(item)) { + item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds) } else { @~[] }; let rp = item_ty_region_param(item); ty::ty_param_bounds_and_ty { - generics: ty::Generics {bounds: tp_bounds, + generics: ty::Generics {type_param_defs: tp_defs, region_param: rp}, ty: t } @@ -753,9 +755,8 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, let method_doc = lookup_item(id, cdata.data); let def_id = item_def_id(method_doc, cdata); let name = item_name(intr, method_doc); - let bounds = - item_ty_param_bounds(method_doc, tcx, cdata, - tag_item_method_tps); + let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata, + tag_item_method_tps); let transformed_self_ty = doc_transformed_self_ty(method_doc, tcx, cdata); let fty = doc_method_fty(method_doc, tcx, cdata); let vis = item_visibility(method_doc); @@ -763,7 +764,7 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, ty::method { ident: name, generics: ty::Generics { - bounds: bounds, + type_param_defs: type_param_defs, region_param: None }, transformed_self_ty: transformed_self_ty, @@ -797,8 +798,9 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, let did = item_def_id(mth, cdata); - let bounds = item_ty_param_bounds(mth, tcx, cdata, - tag_items_data_item_ty_param_bounds); + let type_param_defs = + item_ty_param_defs(mth, tcx, cdata, + tag_items_data_item_ty_param_bounds); let name = item_name(intr, mth); let ty = doc_type(mth, tcx, cdata); @@ -815,7 +817,7 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, let ty_method = ty::method { ident: name, generics: ty::Generics { - bounds: bounds, + type_param_defs: type_param_defs, region_param: None }, transformed_self_ty: transformed_self_ty, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index e251af7c8a85b..b9f0f63040aef 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -179,10 +179,10 @@ fn encode_family(ebml_w: writer::Encoder, c: char) { pub fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) } -fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, - ecx: @EncodeContext, - params: @~[ty::param_bounds], - tag: uint) { +fn encode_ty_type_param_defs(ebml_w: writer::Encoder, + ecx: @EncodeContext, + params: @~[ty::TypeParameterDef], + tag: uint) { let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, @@ -191,7 +191,7 @@ fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; for params.each |param| { ebml_w.start_tag(tag); - tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, *param); + tyencode::enc_type_param_def(ebml_w.writer, ty_str_ctxt, param); ebml_w.end_tag(); } } @@ -199,10 +199,10 @@ fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, fn encode_type_param_bounds(ebml_w: writer::Encoder, ecx: @EncodeContext, params: &OptVec) { - let ty_param_bounds = - @params.map_to_vec(|param| *ecx.tcx.ty_param_bounds.get(¶m.id)); - encode_ty_type_param_bounds(ebml_w, ecx, ty_param_bounds, - tag_items_data_item_ty_param_bounds); + let ty_param_defs = + @params.map_to_vec(|param| *ecx.tcx.ty_param_defs.get(¶m.id)); + encode_ty_type_param_defs(ebml_w, ecx, ty_param_defs, + tag_items_data_item_ty_param_bounds); } @@ -588,8 +588,9 @@ fn encode_method_ty_fields(ecx: @EncodeContext, { encode_def_id(ebml_w, method_ty.def_id); encode_name(ecx, ebml_w, method_ty.ident); - encode_ty_type_param_bounds(ebml_w, ecx, method_ty.generics.bounds, - tag_item_method_tps); + encode_ty_type_param_defs(ebml_w, ecx, + method_ty.generics.type_param_defs, + tag_item_method_tps); encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty); encode_method_fty(ecx, ebml_w, &method_ty.fty); encode_visibility(ebml_w, method_ty.vis); @@ -952,8 +953,9 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder, method_ty.fty.purity)); let tpt = ty::lookup_item_type(tcx, method_def_id); - encode_ty_type_param_bounds(ebml_w, ecx, tpt.generics.bounds, - tag_items_data_item_ty_param_bounds); + encode_ty_type_param_defs(ebml_w, ecx, + tpt.generics.type_param_defs, + tag_items_data_item_ty_param_bounds); encode_type(ecx, ebml_w, tpt.ty); } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 2ec13abb483d6..867fe0cd816cc 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -547,11 +547,17 @@ pub fn parse_def_id(buf: &[u8]) -> ast::def_id { ast::def_id { crate: crate_num, node: def_num } } -pub fn parse_bounds_data(data: @~[u8], start: uint, - crate_num: int, tcx: ty::ctxt, conv: conv_did) - -> @~[ty::param_bound] { +pub fn parse_type_param_def_data(data: @~[u8], start: uint, + crate_num: int, tcx: ty::ctxt, + conv: conv_did) -> ty::TypeParameterDef +{ let st = parse_state_from_data(data, crate_num, start, tcx); - parse_bounds(st, conv) + parse_type_param_def(st, conv) +} + +fn parse_type_param_def(st: @mut PState, conv: conv_did) -> ty::TypeParameterDef { + ty::TypeParameterDef {def_id: parse_def(st, NominalType, conv), + bounds: parse_bounds(st, conv)} } fn parse_bounds(st: @mut PState, conv: conv_did) -> @~[ty::param_bound] { diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index ca2d66de9c44d..238f34b8c01b9 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -412,7 +412,7 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) { enc_ty(w, cx, fsig.output); } -pub fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @~[ty::param_bound]) { +fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @~[ty::param_bound]) { for vec::each(*bs) |bound| { match *bound { ty::bound_owned => w.write_char('S'), @@ -428,6 +428,12 @@ pub fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @~[ty::param_bound]) { w.write_char('.'); } +pub fn enc_type_param_def(w: @io::Writer, cx: @ctxt, v: &ty::TypeParameterDef) { + w.write_str((cx.ds)(v.def_id)); + w.write_char('|'); + enc_bounds(w, cx, v.bounds); +} + // // Local Variables: // mode: rust diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 20b72a19df794..68989b3142566 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -741,7 +741,9 @@ trait ebml_writer_helpers { fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t); fn emit_vstore(&self, ecx: @e::EncodeContext, vstore: ty::vstore); fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]); - fn emit_bounds(&self, ecx: @e::EncodeContext, bs: ty::param_bounds); + fn emit_type_param_def(&self, + ecx: @e::EncodeContext, + type_param_def: &ty::TypeParameterDef); fn emit_tpbt(&self, ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty); } @@ -771,9 +773,12 @@ impl ebml_writer_helpers for writer::Encoder { } } - fn emit_bounds(&self, ecx: @e::EncodeContext, bs: ty::param_bounds) { + fn emit_type_param_def(&self, + ecx: @e::EncodeContext, + type_param_def: &ty::TypeParameterDef) { do self.emit_opaque { - tyencode::enc_bounds(self.writer, ecx.ty_str_ctxt(), bs) + tyencode::enc_type_param_def(self.writer, ecx.ty_str_ctxt(), + type_param_def) } } @@ -782,9 +787,11 @@ impl ebml_writer_helpers for writer::Encoder { do self.emit_struct("ty_param_bounds_and_ty", 2) { do self.emit_field(~"generics", 0) { do self.emit_struct("Generics", 2) { - do self.emit_field(~"bounds", 0) { - do self.emit_from_vec(*tpbt.generics.bounds) |bs| { - self.emit_bounds(ecx, *bs); + do self.emit_field(~"type_param_defs", 0) { + do self.emit_from_vec(*tpbt.generics.type_param_defs) + |type_param_def| + { + self.emit_type_param_def(ecx, type_param_def); } } do self.emit_field(~"region_param", 1) { @@ -889,11 +896,11 @@ fn encode_side_tables_for_id(ecx: @e::EncodeContext, } } - for tcx.ty_param_bounds.find(&id).each |&pbs| { - do ebml_w.tag(c::tag_table_param_bounds) { + for tcx.ty_param_defs.find(&id).each |&type_param_def| { + do ebml_w.tag(c::tag_table_param_defs) { ebml_w.id(id); do ebml_w.tag(c::tag_table_val) { - ebml_w.emit_bounds(ecx, *pbs) + ebml_w.emit_type_param_def(ecx, type_param_def) } } } @@ -990,7 +997,7 @@ trait ebml_decoder_decoder_helpers { fn read_arg(&self, xcx: @ExtendedDecodeContext) -> ty::arg; fn read_ty(&self, xcx: @ExtendedDecodeContext) -> ty::t; fn read_tys(&self, xcx: @ExtendedDecodeContext) -> ~[ty::t]; - fn read_bounds(&self, xcx: @ExtendedDecodeContext) -> @~[ty::param_bound]; + fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef; fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) -> ty::ty_param_bounds_and_ty; fn convert_def_id(&self, xcx: @ExtendedDecodeContext, @@ -1038,10 +1045,9 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { self.read_to_vec(|| self.read_ty(xcx) ) } - fn read_bounds(&self, xcx: @ExtendedDecodeContext) - -> @~[ty::param_bound] { + fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef { do self.read_opaque |doc| { - tydecode::parse_bounds_data( + tydecode::parse_type_param_def_data( doc.data, doc.start, xcx.dcx.cdata.cnum, xcx.dcx.tcx, |s, a| self.convert_def_id(xcx, s, a)) } @@ -1054,8 +1060,8 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { ty::ty_param_bounds_and_ty { generics: do self.read_struct("Generics", 2) { ty::Generics { - bounds: self.read_field(~"bounds", 0, || { - @self.read_to_vec(|| self.read_bounds(xcx) ) + type_param_defs: self.read_field("type_param_defs", 0, || { + @self.read_to_vec(|| self.read_type_param_def(xcx)) }), region_param: self.read_field(~"region_param", 1, || { Decodable::decode(self) @@ -1134,9 +1140,9 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, let tpbt = val_dsr.read_ty_param_bounds_and_ty(xcx); let lid = ast::def_id { crate: ast::local_crate, node: id }; dcx.tcx.tcache.insert(lid, tpbt); - } else if tag == (c::tag_table_param_bounds as uint) { - let bounds = val_dsr.read_bounds(xcx); - dcx.tcx.ty_param_bounds.insert(id, bounds); + } else if tag == (c::tag_table_param_defs as uint) { + let bounds = val_dsr.read_type_param_def(xcx); + dcx.tcx.ty_param_defs.insert(id, bounds); } else if tag == (c::tag_table_last_use as uint) { let ids = val_dsr.read_to_vec(|| { xcx.tr_id(val_dsr.read_int()) diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs index 122e2c64b2133..233b1e191dc24 100644 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ b/src/librustc/middle/borrowck/gather_loans.rs @@ -29,7 +29,7 @@ use middle::pat_util; use middle::ty::{ty_region}; use middle::ty; use util::common::indenter; -use util::ppaux::{expr_repr, region_to_str}; +use util::ppaux::{Repr, region_to_str}; use core::hashmap::{HashSet, HashMap}; use core::vec; @@ -282,7 +282,7 @@ pub impl GatherLoanCtxt { expr: @ast::expr, adjustment: &ty::AutoAdjustment) { debug!("guarantee_adjustments(expr=%s, adjustment=%?)", - expr_repr(self.tcx(), expr), adjustment); + expr.repr(self.tcx()), adjustment); let _i = indenter(); match *adjustment { diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 96e8ef40770a2..e82b6ba5e7710 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -16,7 +16,7 @@ use middle::liveness; use middle::pat_util; use middle::ty; use middle::typeck; -use util::ppaux::{ty_to_str, tys_to_str}; +use util::ppaux::{Repr, ty_to_str, tys_to_str}; use syntax::ast::*; use syntax::attr::attrs_contains_name; @@ -91,7 +91,7 @@ fn check_struct_safe_for_destructor(cx: Context, span: span, struct_did: def_id) { let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did); - if struct_tpt.generics.bounds.len() == 0 { + if !struct_tpt.generics.has_type_params() { let struct_ty = ty::mk_struct(cx.tcx, struct_did, ty::substs { self_r: None, self_ty: None, @@ -276,10 +276,10 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt) { for cx.tcx.node_type_substs.find(&type_parameter_id).each |ts| { // FIXME(#5562): removing this copy causes a segfault before stage2 let ts = /*bad*/ copy **ts; - let bounds = match e.node { + let type_param_defs = match e.node { expr_path(_) => { let did = ast_util::def_id_of_def(*cx.tcx.def_map.get(&e.id)); - ty::lookup_item_type(cx.tcx, did).generics.bounds + ty::lookup_item_type(cx.tcx, did).generics.type_param_defs } _ => { // Type substitutions should only occur on paths and @@ -287,20 +287,20 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt) { // Even though the callee_id may have been the id with // node_type_substs, e.id is correct here. - ty::method_call_bounds(cx.tcx, cx.method_map, e.id).expect( + ty::method_call_type_param_defs(cx.tcx, cx.method_map, e.id).expect( ~"non path/method call expr has type substs??") } }; - if ts.len() != bounds.len() { + if ts.len() != type_param_defs.len() { // Fail earlier to make debugging easier fail!(fmt!("internal error: in kind::check_expr, length \ mismatch between actual and declared bounds: actual = \ - %s (%u tys), declared = %? (%u tys)", - tys_to_str(cx.tcx, ts), ts.len(), - *bounds, bounds.len())); + %s, declared = %s", + ts.repr(cx.tcx), + type_param_defs.repr(cx.tcx))); } - for vec::each2(ts, *bounds) |ty, bound| { - check_bounds(cx, type_parameter_id, e.span, *ty, *bound) + for vec::each2(ts, *type_param_defs) |&ty, type_param_def| { + check_bounds(cx, type_parameter_id, e.span, ty, type_param_def) } } @@ -340,9 +340,10 @@ fn check_ty(aty: @Ty, cx: Context, v: visit::vt) { // FIXME(#5562): removing this copy causes a segfault before stage2 let ts = /*bad*/ copy **ts; let did = ast_util::def_id_of_def(*cx.tcx.def_map.get(&id)); - let bounds = ty::lookup_item_type(cx.tcx, did).generics.bounds; - for vec::each2(ts, *bounds) |ty, bound| { - check_bounds(cx, aty.id, aty.span, *ty, *bound) + let type_param_defs = + ty::lookup_item_type(cx.tcx, did).generics.type_param_defs; + for vec::each2(ts, *type_param_defs) |&ty, type_param_def| { + check_bounds(cx, aty.id, aty.span, ty, type_param_def) } } } @@ -355,11 +356,11 @@ pub fn check_bounds(cx: Context, _type_parameter_id: node_id, sp: span, ty: ty::t, - bounds: ty::param_bounds) + type_param_def: &ty::TypeParameterDef) { let kind = ty::type_contents(cx.tcx, ty); let mut missing = ~[]; - for bounds.each |bound| { + for type_param_def.bounds.each |bound| { match *bound { ty::bound_trait(_) => { /* Not our job, checking in typeck */ diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs new file mode 100644 index 0000000000000..a754f93f01038 --- /dev/null +++ b/src/librustc/middle/subst.rs @@ -0,0 +1,177 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Type substitutions. + +use core::prelude::*; +use middle::ty; +use util::ppaux::Repr; + +/////////////////////////////////////////////////////////////////////////// +// Public trait `Subst` +// +// Just call `foo.subst(tcx, substs)` to perform a substitution across +// `foo`. + +pub trait Subst { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> Self; +} + +/////////////////////////////////////////////////////////////////////////// +// Substitution over types +// +// Because this is so common, we make a special optimization to avoid +// doing anything if `substs` is a no-op. I tried to generalize these +// to all subst methods but ran into trouble due to the limitations of +// our current method/trait matching algorithm. - Niko + +trait EffectfulSubst { + fn effectfulSubst(&self, tcx: ty::ctxt, substs: &ty::substs) -> Self; +} + +impl Subst for ty::t { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::t { + if ty::substs_is_noop(substs) { + return *self; + } else { + return self.effectfulSubst(tcx, substs); + } + } +} + +impl EffectfulSubst for ty::t { + fn effectfulSubst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::t { + if !ty::type_needs_subst(*self) { + return *self; + } + + match ty::get(*self).sty { + ty::ty_param(p) => { + substs.tps[p.idx] + } + ty::ty_self(_) => { + substs.self_ty.expect("ty_self not found in substs") + } + _ => { + ty::fold_regions_and_ty( + tcx, *self, + |r| match r { + ty::re_bound(ty::br_self) => { + match substs.self_r { + None => { + tcx.sess.bug( + fmt!("ty::subst: \ + Reference to self region when \ + given substs with no self region, \ + ty = %s", + self.repr(tcx))); + } + Some(self_r) => self_r + } + } + _ => r + }, + |t| t.effectfulSubst(tcx, substs), + |t| t.effectfulSubst(tcx, substs)) + } + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Other types + +impl Subst for ~[T] { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ~[T] { + self.map(|t| t.subst(tcx, substs)) + } +} + +impl Subst for @~[T] { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @~[T] { + @(**self).subst(tcx, substs) + } +} + +impl Subst for Option { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> Option { + self.map(|t| t.subst(tcx, substs)) + } +} + +impl Subst for ty::TraitRef { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::TraitRef { + ty::TraitRef { + def_id: self.def_id, + substs: self.substs.subst(tcx, substs) + } + } +} + +impl Subst for ty::substs { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::substs { + ty::substs { + self_r: self.self_r, + self_ty: self.self_ty.map(|typ| typ.subst(tcx, substs)), + tps: self.tps.map(|typ| typ.subst(tcx, substs)) + } + } +} + +impl Subst for ty::BareFnTy { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::BareFnTy { + ty::fold_bare_fn_ty(self, |t| t.subst(tcx, substs)) + } +} + +impl Subst for ty::param_bound { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::param_bound { + match self { + &ty::bound_copy | + &ty::bound_durable | + &ty::bound_owned | + &ty::bound_const => { + *self + } + + &ty::bound_trait(tref) => { + ty::bound_trait(@tref.subst(tcx, substs)) + } + } + } +} + +impl Subst for ty::TypeParameterDef { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::TypeParameterDef { + ty::TypeParameterDef { + def_id: self.def_id, + bounds: self.bounds.subst(tcx, substs) + } + } +} + +impl Subst for ty::Generics { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Generics { + ty::Generics { + type_param_defs: self.type_param_defs.subst(tcx, substs), + region_param: self.region_param + } + } +} + +impl Subst for ty::ty_param_bounds_and_ty { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::ty_param_bounds_and_ty { + ty::ty_param_bounds_and_ty { + generics: self.generics.subst(tcx, substs), + ty: self.ty.subst(tcx, substs) + } + } +} + diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index a8fe60ba68ee8..2eb7f8332ca92 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -63,7 +63,7 @@ use middle::trans::type_of; use middle::trans::type_of::*; use middle::ty; use util::common::indenter; -use util::ppaux::ty_to_str; +use util::ppaux::{Repr, ty_to_str}; use util::ppaux; use core::hash; @@ -1592,11 +1592,11 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext, for param_substs.each |p| { p.validate(); } debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \ - param_substs=%s", + param_substs=%s)", path_str(ccx.sess, path), id, impl_id, - opt_param_substs_to_str(ccx.tcx, ¶m_substs)); + param_substs.repr(ccx.tcx)); let llbbs = mk_standard_basic_blocks(llfndecl); return @mut fn_ctxt_ { @@ -1788,6 +1788,9 @@ pub fn trans_closure(ccx: @CrateContext, let _icx = ccx.insn_ctxt("trans_closure"); set_uwtable(llfndecl); + debug!("trans_closure(..., param_substs=%s)", + param_substs.repr(ccx.tcx)); + // Set up arguments to the function. let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, impl_id, param_substs, Some(body.span)); @@ -1849,7 +1852,9 @@ pub fn trans_fn(ccx: @CrateContext, let do_time = ccx.sess.trans_stats(); let start = if do_time { time::get_time() } else { time::Timespec::new(0, 0) }; - debug!("trans_fn(ty_self=%?)", ty_self); + debug!("trans_fn(ty_self=%?, param_substs=%s)", + ty_self, + param_substs.repr(ccx.tcx)); let _icx = ccx.insn_ctxt("trans_fn"); ccx.stats.n_fns += 1; let the_path_str = path_str(ccx.sess, path); diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index de14266573af9..20382676fed21 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -42,6 +42,7 @@ use middle::trans::type_of; use middle::ty; use middle::typeck; use util::common::indenter; +use util::ppaux::Repr; use syntax::ast; use syntax::ast_map; @@ -74,24 +75,13 @@ pub struct Callee { pub fn trans(bcx: block, expr: @ast::expr) -> Callee { let _icx = bcx.insn_ctxt("trans_callee"); + debug!("callee::trans(expr=%s)", expr.repr(bcx.tcx())); // pick out special kinds of expressions that can be called: match expr.node { ast::expr_path(_) => { return trans_def(bcx, bcx.def(expr.id), expr); } - ast::expr_field(base, _, _) => { - match bcx.ccx().maps.method_map.find(&expr.id) { - Some(origin) => { // An impl method - // FIXME(#5562): removing this copy causes a segfault - // before stage2 - let origin = /*bad*/ copy *origin; - return meth::trans_method_callee(bcx, expr.id, - base, origin); - } - None => {} // not a method, just a field - } - } _ => {} } @@ -178,11 +168,13 @@ pub fn trans_fn_ref(bcx: block, * with id `def_id` into a function pointer. This may require * monomorphization or inlining. */ - let _icx = bcx.insn_ctxt("trans_fn"); + let _icx = bcx.insn_ctxt("trans_fn_ref"); let type_params = node_id_type_params(bcx, ref_id); - let vtables = node_vtables(bcx, ref_id); + debug!("trans_fn_ref(def_id=%s, ref_id=%?, type_params=%s, vtables=%s)", + def_id.repr(bcx.tcx()), ref_id, type_params.repr(bcx.tcx()), + vtables.repr(bcx.tcx())); trans_fn_ref_with_vtables(bcx, def_id, ref_id, type_params, vtables) } @@ -224,12 +216,13 @@ pub fn trans_fn_ref_with_vtables( let ccx = bcx.ccx(); let tcx = ccx.tcx; - debug!("trans_fn_ref_with_vtables(bcx=%s, def_id=%?, ref_id=%?, \ - type_params=%?, vtables=%?)", - bcx.to_str(), def_id, ref_id, - type_params.map(|t| bcx.ty_to_str(*t)), - vtables); - let _indenter = indenter(); + debug!("trans_fn_ref_with_vtables(bcx=%s, def_id=%s, ref_id=%?, \ + type_params=%s, vtables=%s)", + bcx.to_str(), + def_id.repr(bcx.tcx()), + ref_id, + type_params.repr(bcx.tcx()), + vtables.repr(bcx.tcx())); assert!(type_params.all(|t| !ty::type_needs_infer(*t))); @@ -335,6 +328,9 @@ pub fn trans_method_call(in_cx: block, dest: expr::Dest) -> block { let _icx = in_cx.insn_ctxt("trans_method_call"); + debug!("trans_method_call(call_ex=%s, rcvr=%s)", + call_ex.repr(in_cx.tcx()), + rcvr.repr(in_cx.tcx())); trans_call_inner( in_cx, call_ex.info(), @@ -343,9 +339,14 @@ pub fn trans_method_call(in_cx: block, |cx| { match cx.ccx().maps.method_map.find(&call_ex.id) { Some(origin) => { + debug!("origin for %s: %s", + call_ex.repr(in_cx.tcx()), + origin.repr(in_cx.tcx())); + // FIXME(#5562): removing this copy causes a segfault // before stage2 let origin = /*bad*/ copy *origin; + meth::trans_method_callee(cx, call_ex.callee_id, rcvr, @@ -641,8 +642,9 @@ pub fn trans_arg_expr(bcx: block, debug!("trans_arg_expr(formal_ty=(%?,%s), arg_expr=%s, \ ret_flag=%?)", - formal_ty.mode, bcx.ty_to_str(formal_ty.ty), - bcx.expr_to_str(arg_expr), + formal_ty.mode, + formal_ty.ty.repr(bcx.tcx()), + arg_expr.repr(bcx.tcx()), ret_flag.map(|v| bcx.val_str(*v))); let _indenter = indenter(); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 593d37c2ff8d1..2cfd7a25d6823 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -41,7 +41,7 @@ use middle::trans::type_use; use middle::ty::substs; use middle::ty; use middle::typeck; -use util::ppaux::{expr_repr, ty_to_str}; +use util::ppaux::{Repr}; use core::cast; use core::hash; @@ -250,7 +250,7 @@ pub enum local_val { local_mem(ValueRef), local_imm(ValueRef), } pub struct param_substs { tys: ~[ty::t], vtables: Option, - bounds: @~[ty::param_bounds], + type_param_defs: @~[ty::TypeParameterDef], self_ty: Option } @@ -261,16 +261,25 @@ pub impl param_substs { } } -pub fn param_substs_to_str(tcx: ty::ctxt, substs: ¶m_substs) -> ~str { - fmt!("param_substs {tys:%?, vtables:%?, bounds:%?}", - substs.tys.map(|t| ty_to_str(tcx, *t)), - substs.vtables.map(|vs| vs.map(|v| v.to_str(tcx))), - substs.bounds.map(|b| ty::param_bounds_to_str(tcx, *b))) +fn param_substs_to_str(self: ¶m_substs, + tcx: ty::ctxt) -> ~str +{ + fmt!("param_substs {tys:%s, vtables:%s, type_param_defs:%s}", + self.tys.repr(tcx), + self.vtables.repr(tcx), + self.type_param_defs.repr(tcx)) } -pub fn opt_param_substs_to_str(tcx: ty::ctxt, - substs: &Option<@param_substs>) -> ~str { - substs.map_default(~"None", |&ps| param_substs_to_str(tcx, ps)) +impl Repr for param_substs { + fn repr(&self, tcx: ty::ctxt) -> ~str { + param_substs_to_str(self, tcx) + } +} + +impl Repr for @param_substs { + fn repr(&self, tcx: ty::ctxt) -> ~str { + param_substs_to_str(*self, tcx) + } } // Function context. Every LLVM function we create will have one of @@ -413,8 +422,9 @@ pub fn root_for_cleanup(bcx: block, v: ValueRef, t: ty::t) pub fn add_clean(bcx: block, val: ValueRef, t: ty::t) { if !ty::type_needs_drop(bcx.tcx(), t) { return; } debug!("add_clean(%s, %s, %s)", - bcx.to_str(), val_str(bcx.ccx().tn, val), - ty_to_str(bcx.ccx().tcx, t)); + bcx.to_str(), + val_str(bcx.ccx().tn, val), + t.repr(bcx.tcx())); let (root, rooted) = root_for_cleanup(bcx, val, t); let cleanup_type = cleanup_type(bcx.tcx(), t); do in_scope_cx(bcx) |scope_info| { @@ -429,7 +439,7 @@ pub fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) { if !ty::type_needs_drop(cx.tcx(), ty) { return; } debug!("add_clean_temp_immediate(%s, %s, %s)", cx.to_str(), val_str(cx.ccx().tn, val), - ty_to_str(cx.ccx().tcx, ty)); + ty.repr(cx.tcx())); let cleanup_type = cleanup_type(cx.tcx(), ty); do in_scope_cx(cx) |scope_info| { scope_info.cleanups.push( @@ -442,7 +452,7 @@ pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { if !ty::type_needs_drop(bcx.tcx(), t) { return; } debug!("add_clean_temp_mem(%s, %s, %s)", bcx.to_str(), val_str(bcx.ccx().tn, val), - ty_to_str(bcx.ccx().tcx, t)); + t.repr(bcx.tcx())); let (root, rooted) = root_for_cleanup(bcx, val, t); let cleanup_type = cleanup_type(bcx.tcx(), t); do in_scope_cx(bcx) |scope_info| { @@ -455,7 +465,7 @@ pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { pub fn add_clean_frozen_root(bcx: block, val: ValueRef, t: ty::t) { debug!("add_clean_frozen_root(%s, %s, %s)", bcx.to_str(), val_str(bcx.ccx().tn, val), - ty_to_str(bcx.ccx().tcx, t)); + t.repr(bcx.tcx())); let (root, rooted) = root_for_cleanup(bcx, val, t); let cleanup_type = cleanup_type(bcx.tcx(), t); do in_scope_cx(bcx) |scope_info| { @@ -703,7 +713,7 @@ pub impl block_ { } fn expr_to_str(@mut self, e: @ast::expr) -> ~str { - expr_repr(self.tcx(), e) + e.repr(self.tcx()) } fn expr_is_lval(@mut self, e: @ast::expr) -> bool { @@ -733,7 +743,7 @@ pub impl block_ { } fn ty_to_str(@mut self, t: ty::t) -> ~str { - ty_to_str(self.tcx(), t) + t.repr(self.tcx()) } fn to_str(@mut self) -> ~str { match self.node_info { @@ -1445,14 +1455,14 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, +vt: typeck::vtable_origin) pub fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, n_param: uint, n_bound: uint) -> typeck::vtable_origin { - debug!("find_vtable_in_fn_ctxt(n_param=%u, n_bound=%u, ps=%?)", - n_param, n_bound, param_substs_to_str(tcx, ps)); + debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)", + n_param, n_bound, ps.repr(tcx)); // Vtables are stored in a flat array, finding the right one is // somewhat awkward - let first_n_bounds = ps.bounds.slice(0, n_param); + let first_n_type_param_defs = ps.type_param_defs.slice(0, n_param); let vtables_to_skip = - ty::count_traits_and_supertraits(tcx, first_n_bounds); + ty::count_traits_and_supertraits(tcx, first_n_type_param_defs); let vtable_off = vtables_to_skip + n_bound; /*bad*/ copy ps.vtables.get()[vtable_off] } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 55e6b30439ba4..c5e708569dc25 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -25,7 +25,7 @@ use middle::trans::inline; use middle::trans::machine; use middle::trans::type_of; use middle::ty; -use util::ppaux::{expr_repr, ty_to_str}; +use util::ppaux::{Repr, ty_to_str}; use core::libc::c_uint; use syntax::{ast, ast_util, ast_map}; @@ -237,7 +237,7 @@ pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef { llvm::LLVMDumpValue(C_undef(llty)); } cx.sess.bug(fmt!("const %s of type %s has size %u instead of %u", - expr_repr(cx.tcx, e), ty_to_str(cx.tcx, ety), + e.repr(cx.tcx), ty_to_str(cx.tcx, ety), csize, tsize)); } llconst diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index 2ca19b9075423..15c2e8e3d9350 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -86,13 +86,11 @@ pub fn maybe_instantiate_inline(ccx: @CrateContext, fn_id: ast::def_id, csearch::found(ast::ii_method(impl_did, mth)) => { ccx.stats.n_inlines += 1; ccx.external.insert(fn_id, Some(mth.id)); - let ty::ty_param_bounds_and_ty { - generics: ty::Generics { bounds: impl_bnds, _ }, - ty: _ - } = ty::lookup_item_type(ccx.tcx, impl_did); - if translate && - impl_bnds.len() + mth.generics.ty_params.len() == 0u - { + 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(); + if translate && num_type_params == 0 { let llfn = get_item_val(ccx, mth.id); let path = vec::append( ty::item_path(ccx.tcx, impl_did), diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index bbf53480a56fb..c518605faf13a 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -30,7 +30,7 @@ use middle::ty; use middle::ty::arg; use middle::typeck; use util::common::indenter; -use util::ppaux::ty_to_str; +use util::ppaux::Repr; use syntax::ast_map::{path, path_mod, path_name}; use syntax::ast_util; @@ -61,7 +61,7 @@ pub fn trans_impl(ccx: @CrateContext, +path: path, name: ast::ident, param_substs_opt = Some(@param_substs { tys: ~[], vtables: None, - bounds: @~[], + type_param_defs: @~[], self_ty: Some(self_ty) }); } @@ -115,11 +115,8 @@ pub fn trans_method(ccx: @CrateContext, } }; debug!("calling trans_fn with base_self_ty %s, self_ty %s", - match base_self_ty { - None => ~"(none)", - Some(x) => ty_to_str(ccx.tcx, x), - }, - ty_to_str(ccx.tcx, self_ty)); + base_self_ty.repr(ccx.tcx), + self_ty.repr(ccx.tcx)); match method.self_ty.node { ast::sty_value => { impl_owned_self(self_ty) @@ -175,8 +172,9 @@ pub fn trans_method_callee(bcx: block, let _icx = bcx.insn_ctxt("impl::trans_method_callee"); let tcx = bcx.tcx(); - debug!("trans_method_callee(callee_id=%?, self=%s, mentry=%?)", - callee_id, bcx.expr_to_str(self), mentry); + debug!("trans_method_callee(callee_id=%?, self=%s, mentry=%s)", + callee_id, bcx.expr_to_str(self), + mentry.repr(bcx.tcx())); // Replace method_self with method_static here. let mut origin = mentry.origin; @@ -302,7 +300,8 @@ pub fn trans_static_method_callee(bcx: block, // one we are interested in. let bound_index = { let trait_def = ty::lookup_trait_def(bcx.tcx(), trait_id); - ty::count_traits_and_supertraits(bcx.tcx(), *trait_def.generics.bounds) + ty::count_traits_and_supertraits( + bcx.tcx(), *trait_def.generics.type_param_defs) }; let mname = if method_id.crate == ast::local_crate { @@ -552,14 +551,15 @@ pub fn combine_impl_and_methods_origins(bcx: block, let ccx = bcx.ccx(), tcx = bcx.tcx(); let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did); let ty::ty_param_bounds_and_ty { - generics: ty::Generics {bounds: r_m_bounds, _}, + generics: r_m_generics, _ } = ty::lookup_item_type(tcx, mth_did); - let n_r_m_tps = r_m_bounds.len(); // rcvr + method tps - let m_boundss = vec::slice(*r_m_bounds, n_r_m_tps - n_m_tps, n_r_m_tps); + let n_r_m_tps = r_m_generics.type_param_defs.len(); // rcvr + method tps + let m_type_param_defs = + vec::slice(*r_m_generics.type_param_defs, n_r_m_tps - n_m_tps, n_r_m_tps); // Flatten out to find the number of vtables the method expects. - let m_vtables = ty::count_traits_and_supertraits(tcx, m_boundss); + let m_vtables = ty::count_traits_and_supertraits(tcx, m_type_param_defs); // Find the vtables we computed at type check time and monomorphize them let r_m_origins = match node_vtables(bcx, callee_id) { @@ -787,12 +787,13 @@ pub fn make_impl_vtable(ccx: @CrateContext, // XXX: This should support multiple traits. let trt_id = ty::impl_trait_refs(tcx, impl_id)[0].def_id; - let has_tps = ty::lookup_item_type(ccx.tcx, impl_id).generics.bounds.len() > 0u; + let has_tps = + !ty::lookup_item_type(ccx.tcx, impl_id).generics.type_param_defs.is_empty(); make_vtable(ccx, ty::trait_method_def_ids(tcx, trt_id).map(|method_def_id| { let im = ty::method(tcx, *method_def_id); let fty = ty::subst_tps(tcx, substs, None, ty::mk_bare_fn(tcx, copy im.fty)); - if im.generics.bounds.len() > 0u || ty::type_has_self(fty) { + if im.generics.has_type_params() || ty::type_has_self(fty) { debug!("(making impl vtable) method has self or type params: %s", *tcx.sess.str_of(im.ident)); C_null(T_ptr(T_nil())) diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 319f57fb75ce0..97dc3fed780f0 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -30,7 +30,7 @@ use middle::trans::type_use; use middle::ty; use middle::ty::{FnSig}; use middle::typeck; -use util::ppaux::ty_to_str; +use util::ppaux::Repr; use core::vec; use syntax::ast; @@ -46,8 +46,21 @@ pub fn monomorphic_fn(ccx: @CrateContext, real_substs: &[ty::t], vtables: Option, impl_did_opt: Option, - ref_id: Option) -> - (ValueRef, bool) { + ref_id: Option) + -> (ValueRef, bool) +{ + debug!("monomorphic_fn(\ + fn_id=%s, \ + real_substs=%s, \ + vtables=%s, \ + impl_did_opt=%s, \ + ref_id=%?)", + fn_id.repr(ccx.tcx), + real_substs.repr(ccx.tcx), + vtables.repr(ccx.tcx), + impl_did_opt.repr(ccx.tcx), + ref_id); + assert!(real_substs.all(|t| !ty::type_needs_infer(*t))); let _icx = ccx.insn_ctxt("monomorphic_fn"); let mut must_cast = false; @@ -69,13 +82,15 @@ pub fn monomorphic_fn(ccx: @CrateContext, must_cast = true; } - debug!("monomorphic_fn(fn_id=%? (%s), vtables=%?, \ - real_substs=%?, substs=%?, \ - hash_id = %?", - fn_id, ty::item_path_str(ccx.tcx, fn_id), - vtables, - real_substs.map(|s| ty_to_str(ccx.tcx, *s)), - substs.map(|s| ty_to_str(ccx.tcx, *s)), hash_id); + debug!("monomorphic_fn(\ + fn_id=%s, \ + vtables=%s, \ + substs=%s, \ + hash_id=%?)", + fn_id.repr(ccx.tcx), + vtables.repr(ccx.tcx), + substs.repr(ccx.tcx), + hash_id); match ccx.monomorphized.find(&hash_id) { Some(&val) => { @@ -169,7 +184,7 @@ pub fn monomorphic_fn(ccx: @CrateContext, let psubsts = Some(@param_substs { tys: substs, vtables: vtables, - bounds: tpt.generics.bounds, + type_param_defs: tpt.generics.type_param_defs, self_ty: impl_ty_opt }); @@ -322,17 +337,19 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt, } } -pub fn make_mono_id(ccx: @CrateContext, item: ast::def_id, substs: &[ty::t], +pub fn make_mono_id(ccx: @CrateContext, + item: ast::def_id, + substs: &[ty::t], vtables: Option, impl_did_opt: Option, +param_uses: Option<~[type_use::type_uses]>) -> mono_id { let precise_param_ids = match vtables { Some(vts) => { - let bounds = ty::lookup_item_type(ccx.tcx, item).generics.bounds; + let item_ty = ty::lookup_item_type(ccx.tcx, item); let mut i = 0; - vec::map2(*bounds, substs, |bounds, subst| { + vec::map2(*item_ty.generics.type_param_defs, substs, |type_param_def, subst| { let mut v = ~[]; - for bounds.each |bound| { + for type_param_def.bounds.each |bound| { match *bound { ty::bound_trait(_) => { v.push(meth::vtable_id(ccx, /*bad*/copy vts[i])); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c29029de351e3..742153124346a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -20,12 +20,13 @@ use middle::lint; use middle::resolve::{Impl, MethodInfo}; use middle::resolve; use middle::ty; +use middle::subst::Subst; use middle::typeck; use middle; use util::ppaux::{note_and_explain_region, bound_region_to_str}; use util::ppaux::{region_to_str, vstore_to_str}; use util::ppaux::{trait_store_to_str, ty_to_str, tys_to_str}; -use util::ppaux::{trait_ref_to_str}; +use util::ppaux::Repr; use util::common::{indenter}; use core; @@ -277,7 +278,7 @@ struct ctxt_ { tc_cache: @mut HashMap, ast_ty_to_ty_cache: @mut HashMap, enum_var_cache: @mut HashMap, - ty_param_bounds: @mut HashMap, + ty_param_defs: @mut HashMap, inferred_modes: @mut HashMap, adjustments: @mut HashMap, normalized_cache: @mut HashMap, @@ -400,19 +401,12 @@ impl to_bytes::IterBytes for ClosureTy { } } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct param_ty { idx: uint, def_id: def_id } -impl to_bytes::IterBytes for param_ty { - fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - to_bytes::iter_bytes_2(&self.idx, &self.def_id, lsb0, f) - } -} - - /// Representation of regions: #[auto_encode] #[auto_decode] @@ -754,13 +748,24 @@ impl to_bytes::IterBytes for RegionVid { } } +pub struct TypeParameterDef { + def_id: ast::def_id, + bounds: param_bounds +} + /// Information about the type/lifetime parametesr associated with an item. /// Analogous to ast::Generics. pub struct Generics { - bounds: @~[param_bounds], + type_param_defs: @~[TypeParameterDef], region_param: Option, } +pub impl Generics { + fn has_type_params(&self) -> bool { + !self.type_param_defs.is_empty() + } +} + /// A polytype. /// /// - `bounds`: The list of bounds for each type parameter. The length of the @@ -853,7 +858,7 @@ pub fn mk_ctxt(s: session::Session, methods: @mut HashMap::new(), trait_method_def_ids: @mut HashMap::new(), trait_methods_cache: @mut HashMap::new(), - ty_param_bounds: @mut HashMap::new(), + ty_param_defs: @mut HashMap::new(), inferred_modes: @mut HashMap::new(), adjustments: @mut HashMap::new(), normalized_cache: new_ty_hash(), @@ -1227,6 +1232,12 @@ pub fn fold_sig(sig: &FnSig, fldop: &fn(t) -> t) -> FnSig { } } +pub fn fold_bare_fn_ty(fty: &BareFnTy, fldop: &fn(t) -> t) -> BareFnTy { + BareFnTy {sig: fold_sig(&fty.sig, fldop), + abis: fty.abis, + purity: fty.purity} +} + fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty { fn fold_substs(substs: &substs, fldop: &fn(t) -> t) -> substs { substs {self_r: substs.self_r, @@ -1261,8 +1272,7 @@ fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty { ty_tup(new_ts) } ty_bare_fn(ref f) => { - let sig = fold_sig(&f.sig, fldop); - ty_bare_fn(BareFnTy {sig: sig, abis: f.abis, purity: f.purity}) + ty_bare_fn(fold_bare_fn_ty(f, fldop)) } ty_closure(ref f) => { let sig = fold_sig(&f.sig, fldop); @@ -1409,94 +1419,22 @@ pub fn substs_is_noop(substs: &substs) -> bool { } pub fn substs_to_str(cx: ctxt, substs: &substs) -> ~str { - fmt!("substs(self_r=%s, self_ty=%s, tps=%?)", - substs.self_r.map_default(~"none", |r| region_to_str(cx, *r)), - substs.self_ty.map_default(~"none", - |t| ::util::ppaux::ty_to_str(cx, *t)), - tys_to_str(cx, substs.tps)) + substs.repr(cx) } pub fn param_bound_to_str(cx: ctxt, pb: ¶m_bound) -> ~str { - match *pb { - bound_copy => ~"copy", - bound_durable => ~"'static", - bound_owned => ~"owned", - bound_const => ~"const", - bound_trait(t) => ::util::ppaux::trait_ref_to_str(cx, t) - } + pb.repr(cx) } pub fn param_bounds_to_str(cx: ctxt, pbs: param_bounds) -> ~str { - fmt!("%?", pbs.map(|pb| param_bound_to_str(cx, pb))) + pbs.repr(cx) } pub fn subst(cx: ctxt, substs: &substs, typ: t) -> t { - debug!("subst(substs=%s, typ=%s)", - substs_to_str(cx, substs), - ::util::ppaux::ty_to_str(cx, typ)); - - if substs_is_noop(substs) { return typ; } - let r = do_subst(cx, substs, typ); - debug!(" r = %s", ::util::ppaux::ty_to_str(cx, r)); - return r; - - fn do_subst(cx: ctxt, - substs: &substs, - typ: t) -> t { - let tb = get(typ); - if !tbox_has_flag(tb, needs_subst) { return typ; } - match tb.sty { - ty_param(p) => substs.tps[p.idx], - ty_self(_) => substs.self_ty.get(), - _ => { - fold_regions_and_ty( - cx, typ, - |r| match r { - re_bound(br_self) => { - match substs.self_r { - None => { - cx.sess.bug( - fmt!("ty::subst: \ - Reference to self region when given substs \ - with no self region, ty = %s", - ::util::ppaux::ty_to_str(cx, typ))) - } - Some(self_r) => self_r - } - } - _ => r - }, - |t| do_subst(cx, substs, t), - |t| do_subst(cx, substs, t)) - } - } - } -} - -pub fn subst_in_trait_ref(cx: ctxt, - substs: &substs, - trait_ref: &ty::TraitRef) -> ty::TraitRef -{ - ty::TraitRef { - def_id: trait_ref.def_id, - substs: subst_in_substs(cx, substs, &trait_ref.substs) - } -} - -// Performs substitutions on a set of substitutions (result = sup(sub)) to -// yield a new set of substitutions. This is used in trait inheritance. -pub fn subst_in_substs(cx: ctxt, - substs: &substs, - in_substs: &substs) -> substs -{ - substs { - self_r: in_substs.self_r, - self_ty: in_substs.self_ty.map(|&typ| subst(cx, substs, typ)), - tps: in_substs.tps.map(|&typ| subst(cx, substs, typ)) - } + typ.subst(cx, substs) } // Type utilities @@ -1511,6 +1449,10 @@ pub fn type_is_error(ty: t) -> bool { (get(ty).flags & (has_ty_err as uint)) != 0 } +pub fn type_needs_subst(ty: t) -> bool { + tbox_has_flag(get(ty), needs_subst) +} + pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool { tref.substs.self_ty.any(|&t| type_is_error(t)) || tref.substs.tps.any(|&t| type_is_error(t)) @@ -2046,8 +1988,8 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { // def-id. assert!(p.def_id.crate == ast::local_crate); - param_bounds_to_contents( - cx, *cx.ty_param_bounds.get(&p.def_id.node)) + type_param_def_to_contents( + cx, cx.ty_param_defs.get(&p.def_id.node)) } ty_self(_) => { @@ -2141,13 +2083,13 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { st + rt + ot } - fn param_bounds_to_contents(cx: ctxt, - bounds: param_bounds) -> TypeContents + fn type_param_def_to_contents(cx: ctxt, + type_param_def: &TypeParameterDef) -> TypeContents { - debug!("param_bounds_to_contents()"); + debug!("type_param_def_to_contents(%s)", type_param_def.repr(cx)); let _i = indenter(); - let r = bounds.foldl(TC_ALL, |tc, bound| { + let r = type_param_def.bounds.foldl(TC_ALL, |tc, bound| { debug!("tc = %s, bound = %?", tc.to_str(), bound); match *bound { bound_copy => tc - TypeContents::nonimplicitly_copyable(cx), @@ -3042,16 +2984,18 @@ pub fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool { return node_id_has_type_params(cx, expr.id); } -pub fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map, - id: ast::node_id) - -> Option<@~[param_bounds]> { +pub fn method_call_type_param_defs( + tcx: ctxt, + method_map: typeck::method_map, + id: ast::node_id) -> Option<@~[TypeParameterDef]> +{ do method_map.find(&id).map |method| { match method.origin { typeck::method_static(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.bounds + ty::lookup_item_type(tcx, did).generics.type_param_defs } typeck::method_param(typeck::method_param { trait_id: trt_id, @@ -3062,9 +3006,11 @@ pub fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map, // ...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 trt_bounds = ty::lookup_trait_def(tcx, trt_id).generics.bounds; - @(vec::append(/*bad*/copy *trt_bounds, - *ty::trait_method(tcx, trt_id, n_mth).generics.bounds)) + let trait_type_param_defs = + ty::lookup_trait_def(tcx, trt_id).generics.type_param_defs; + @vec::append( + copy *trait_type_param_defs, + *ty::trait_method(tcx, trt_id, n_mth).generics.type_param_defs) } } } @@ -3614,6 +3560,12 @@ pub fn trait_supertraits(cx: ctxt, return result; } +pub fn trait_ref_supertraits(cx: ctxt, trait_ref: &ty::TraitRef) -> ~[@TraitRef] { + let supertrait_refs = trait_supertraits(cx, trait_ref.def_id); + supertrait_refs.map( + |supertrait_ref| @supertrait_ref.subst(cx, &trait_ref.substs)) +} + fn lookup_locally_or_in_crate_store( descr: &str, def_id: ast::def_id, @@ -4327,11 +4279,9 @@ pub fn determine_inherited_purity(parent_purity: ast::purity, // Here, the supertraits are the transitive closure of the supertrait // relation on the supertraits from each bounded trait's constraint // list. -pub fn iter_bound_traits_and_supertraits(tcx: ctxt, +pub fn each_bound_trait_and_supertraits(tcx: ctxt, bounds: param_bounds, f: &fn(&TraitRef) -> bool) { - let mut fin = false; - for bounds.each |bound| { let bound_trait_ref = match *bound { ty::bound_trait(bound_t) => bound_t, @@ -4343,51 +4293,46 @@ pub fn iter_bound_traits_and_supertraits(tcx: ctxt, }; let mut supertrait_set = HashMap::new(); - let mut seen_def_ids = ~[]; + let mut trait_refs = ~[]; let mut i = 0; - let trait_ty_id = bound_trait_ref.def_id; - let mut trait_ref = bound_trait_ref; - debug!("iter_bound_traits_and_supertraits: trait_ref = %s", - trait_ref_to_str(tcx, trait_ref)); + // Seed the worklist with the trait from the bound + supertrait_set.insert(bound_trait_ref.def_id, ()); + trait_refs.push(bound_trait_ref); // Add the given trait ty to the hash map - supertrait_set.insert(trait_ty_id, ()); - seen_def_ids.push(trait_ty_id); - - if f(trait_ref) { - // Add all the supertraits to the hash map, - // executing on each of them - while i < supertrait_set.len() && !fin { - let init_trait_id = seen_def_ids[i]; - i += 1; - - // Add supertraits to supertrait_set - let supertrait_refs = trait_supertraits(tcx, init_trait_id); - for supertrait_refs.each |&supertrait_ref| { - let d_id = supertrait_ref.def_id; - if !supertrait_set.contains_key(&d_id) { - // FIXME(#5527) Could have same trait multiple times - supertrait_set.insert(d_id, ()); - trait_ref = supertrait_ref; - seen_def_ids.push(d_id); - } - debug!("A super_t = %s", trait_ref_to_str(tcx, trait_ref)); - if !f(trait_ref) { - fin = true; - } + while i < trait_refs.len() { + debug!("each_bound_trait_and_supertraits(i=%?, trait_ref=%s)", + i, trait_refs[i].repr(tcx)); + + if !f(trait_refs[i]) { + return; + } + + // Add supertraits to supertrait_set + let supertrait_refs = trait_ref_supertraits(tcx, trait_refs[i]); + for supertrait_refs.each |&supertrait_ref| { + debug!("each_bound_trait_and_supertraits(supertrait_ref=%s)", + supertrait_ref.repr(tcx)); + + let d_id = supertrait_ref.def_id; + if !supertrait_set.contains_key(&d_id) { + // FIXME(#5527) Could have same trait multiple times + supertrait_set.insert(d_id, ()); + trait_refs.push(supertrait_ref); } } - }; - fin = false; + + i += 1; + } } } pub fn count_traits_and_supertraits(tcx: ctxt, - boundses: &[param_bounds]) -> uint { + type_param_defs: &[TypeParameterDef]) -> uint { let mut total = 0; - for boundses.each |bounds| { - for iter_bound_traits_and_supertraits(tcx, *bounds) |_trait_ty| { + for type_param_defs.each |type_param_def| { + for each_bound_trait_and_supertraits(tcx, type_param_def.bounds) |_| { total += 1; } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 209091ecd6643..bfc9d646dbb6c 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -135,6 +135,7 @@ fn ast_path_substs( rscope: &RS, def_id: ast::def_id, decl_generics: &ty::Generics, + self_ty: Option, path: @ast::path) -> ty::substs { /*! @@ -172,15 +173,15 @@ fn ast_path_substs( }; // Convert the type parameters supplied by the user. - if !vec::same_length(*decl_generics.bounds, path.types) { + if !vec::same_length(*decl_generics.type_param_defs, path.types) { self.tcx().sess.span_fatal( path.span, fmt!("wrong number of type arguments: expected %u but found %u", - decl_generics.bounds.len(), path.types.len())); + decl_generics.type_param_defs.len(), path.types.len())); } let tps = path.types.map(|a_t| ast_ty_to_ty(self, rscope, *a_t)); - substs {self_r:self_r, self_ty:None, tps:tps} + substs {self_r:self_r, self_ty:self_ty, tps:tps} } pub fn ast_path_to_substs_and_ty( @@ -195,7 +196,7 @@ pub fn ast_path_to_substs_and_ty( ty: decl_ty } = self.get_item_ty(did); - let substs = ast_path_substs(self, rscope, did, &generics, path); + let substs = ast_path_substs(self, rscope, did, &generics, None, path); let ty = ty::subst(tcx, &substs, decl_ty); ty_param_substs_and_ty { substs: substs, ty: ty } } @@ -204,14 +205,18 @@ pub fn ast_path_to_trait_ref( self: &AC, rscope: &RS, trait_def_id: ast::def_id, + self_ty: Option, path: @ast::path) -> @ty::TraitRef { let trait_def = self.get_trait_def(trait_def_id); let substs = ast_path_substs( - self, rscope, - trait_def.trait_ref.def_id, &trait_def.generics, + self, + rscope, + trait_def.trait_ref.def_id, + &trait_def.generics, + self_ty, path); let trait_ref = @ty::TraitRef {def_id: trait_def_id, @@ -280,7 +285,7 @@ pub fn ast_ty_to_ty( } Some(&ast::def_trait(trait_def_id)) => { let result = ast_path_to_trait_ref( - self, rscope, trait_def_id, path); + self, rscope, trait_def_id, None, path); let trait_store = match vst { ty::vstore_box => ty::BoxTraitStore, ty::vstore_uniq => ty::UniqTraitStore, diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 605caba74a380..aa2414eac6240 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -135,7 +135,9 @@ pub fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, ty::enum_variant_with_id(tcx, enm, var); let var_tpt = ty::lookup_item_type(tcx, var); vinfo.args.map(|t| { - if var_tpt.generics.bounds.len() == expected_substs.tps.len() { + if var_tpt.generics.type_param_defs.len() == + expected_substs.tps.len() + { ty::subst(tcx, expected_substs, *t) } else { diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index fa3cb43d9abe0..6a274e7f9eb07 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -94,7 +94,6 @@ use middle::typeck::{method_map_entry, method_origin, method_param}; use middle::typeck::{method_self, method_static, method_trait, method_super}; use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; use util::common::indenter; -use util::ppaux::expr_repr; use core::hashmap::HashSet; use core::result; @@ -149,8 +148,7 @@ pub fn lookup( autoderef_receiver: autoderef_receiver, }; let mme = lcx.do_lookup(self_ty); - debug!("method lookup for %s yielded %?", - expr_repr(fcx.tcx(), expr), mme); + debug!("method lookup for %s yielded %?", expr.repr(fcx.tcx()), mme); return mme; } @@ -197,9 +195,8 @@ pub impl<'self> LookupContext<'self> { debug!("do_lookup(self_ty=%s, expr=%s, self_expr=%s)", self.ty_to_str(self_ty), - expr_repr(self.tcx(), self.expr), - expr_repr(self.tcx(), self.self_expr)); - let _indenter = indenter(); + self.expr.repr(self.tcx()), + self.self_expr.repr(self.tcx())); // Prepare the list of candidates self.push_inherent_candidates(self_ty); @@ -379,105 +376,59 @@ pub impl<'self> LookupContext<'self> { let tcx = self.tcx(); let mut next_bound_idx = 0; // count only trait bounds - let bounds = tcx.ty_param_bounds.get(¶m_ty.def_id.node); - - for bounds.each |bound| { - let bound_trait_ref = match *bound { - ty::bound_trait(bound_t) => bound_t, + let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) { + Some(t) => t, + None => { + tcx.sess.span_bug( + self.expr.span, + fmt!("No param def for %?", param_ty)); + } + }; - ty::bound_copy | ty::bound_owned | - ty::bound_const | ty::bound_durable => { - loop; // skip non-trait bounds + for ty::each_bound_trait_and_supertraits(tcx, type_param_def.bounds) + |bound_trait_ref| + { + let this_bound_idx = next_bound_idx; + next_bound_idx += 1; + + let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); + let pos = { + match trait_methods.position(|m| { + m.self_ty != ast::sty_static && + m.ident == self.m_name }) + { + Some(pos) => pos, + None => { + debug!("trait doesn't contain method: %?", + bound_trait_ref.def_id); + loop; // check next trait or bound + } } }; + let method = trait_methods[pos]; - // Loop over the trait and all of its supertraits. - let mut worklist = ~[]; - - let init_trait_ref = bound_trait_ref; - - // Replace any appearance of `self` with the type of the - // generic parameter itself. Note that this is the only - // case where this replacement is necessary: in all other - // cases, we are either invoking a method directly from an - // impl or class (where the self type is not permitted), - // or from a trait type (in which case methods that refer - // to self are not permitted). - let init_substs = substs { - self_ty: Some(rcvr_ty), - ..copy bound_trait_ref.substs - }; - - worklist.push((init_trait_ref.def_id, init_substs)); - - let mut i = 0; - while i < worklist.len() { - let (init_trait_id, init_substs) = /*bad*/copy worklist[i]; - i += 1; - - // Add all the supertraits of this trait to the worklist. - let supertraits = ty::trait_supertraits(tcx, init_trait_id); - for supertraits.each |supertrait_ref| { - debug!("adding supertrait: %?", - supertrait_ref.def_id); - - let new_substs = ty::subst_in_substs( - tcx, - &init_substs, - &supertrait_ref.substs); - - // Again replacing the self type - let new_substs = substs { - self_ty: Some(rcvr_ty), - ..new_substs - }; - - worklist.push((supertrait_ref.def_id, new_substs)); - } - - - let this_bound_idx = next_bound_idx; - next_bound_idx += 1; - - let trait_methods = ty::trait_methods(tcx, init_trait_id); - let pos = { - match trait_methods.position(|m| { - m.self_ty != ast::sty_static && - m.ident == self.m_name }) - { - Some(pos) => pos, - None => { - debug!("trait doesn't contain method: %?", - init_trait_id); - loop; // check next trait or bound - } - } - }; - let method = trait_methods[pos]; - - let (rcvr_ty, rcvr_substs) = - self.create_rcvr_ty_and_substs_for_method( - method.self_ty, - rcvr_ty, - init_substs, - TransformTypeNormally); + let (rcvr_ty, rcvr_substs) = + self.create_rcvr_ty_and_substs_for_method( + method.self_ty, + rcvr_ty, + copy bound_trait_ref.substs, + TransformTypeNormally); - let cand = Candidate { - rcvr_ty: rcvr_ty, - rcvr_substs: rcvr_substs, - method_ty: method, - origin: method_param( - method_param { - trait_id: init_trait_id, - method_num: pos, - param_num: param_ty.idx, - bound_num: this_bound_idx, - }) - }; + let cand = Candidate { + rcvr_ty: rcvr_ty, + rcvr_substs: rcvr_substs, + method_ty: method, + origin: method_param( + method_param { + trait_id: bound_trait_ref.def_id, + method_num: pos, + param_num: param_ty.idx, + bound_num: this_bound_idx, + }) + }; - debug!("pushing inherent candidate for param: %?", cand); - self.inherent_candidates.push(cand); - } + debug!("pushing inherent candidate for param: %?", cand); + self.inherent_candidates.push(cand); } } @@ -499,7 +450,7 @@ pub impl<'self> LookupContext<'self> { }; let method = ms[index]; - /* FIXME(#3157) we should transform the vstore in accordance + /* FIXME(#5762) we should transform the vstore in accordance with the self type match method.self_type { @@ -517,6 +468,9 @@ pub impl<'self> LookupContext<'self> { // `trait_ty` for `self` here, because it allows the compiler // to soldier on. An error will be reported should this // candidate be selected if the method refers to `self`. + // + // NB: `confirm_candidate()` also relies upon this substitution + // for Self. let rcvr_substs = substs { self_ty: Some(self_ty), ../*bad*/copy *substs @@ -1075,7 +1029,7 @@ pub impl<'self> LookupContext<'self> { let fty = self.fn_ty_from_origin(&candidate.origin); debug!("confirm_candidate(expr=%s, candidate=%s, fty=%s)", - expr_repr(tcx, self.expr), + self.expr.repr(tcx), self.cand_to_str(candidate), self.ty_to_str(fty)); @@ -1101,7 +1055,7 @@ pub impl<'self> LookupContext<'self> { // If they were not explicitly supplied, just construct fresh // type variables. let num_supplied_tps = self.supplied_tps.len(); - let num_method_tps = candidate.method_ty.generics.bounds.len(); + let num_method_tps = candidate.method_ty.generics.type_param_defs.len(); let m_substs = { if num_supplied_tps == 0u { self.fcx.infcx().next_ty_vars(num_method_tps) @@ -1195,7 +1149,7 @@ pub impl<'self> LookupContext<'self> { self-type through a boxed trait"); } - if candidate.method_ty.generics.bounds.len() > 0 { + if candidate.method_ty.generics.has_type_params() { self.tcx().sess.span_err( self.expr.span, ~"cannot call a generic method through a boxed trait"); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index c3ec2d14d83d0..2455201907447 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -107,7 +107,7 @@ use middle::typeck::{isr_alist, lookup_def_ccx}; use middle::typeck::no_params; use middle::typeck::{require_same_types, method_map, vtable_map}; use util::common::{block_query, indenter, loop_query}; -use util::ppaux::{bound_region_to_str, expr_repr, pat_repr}; +use util::ppaux::{bound_region_to_str}; use util::ppaux; use core::hashmap::HashMap; @@ -610,7 +610,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { } else { for m.items.each |item| { let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id)); - if !tpt.generics.bounds.is_empty() { + if tpt.generics.has_type_params() { ccx.tcx.sess.span_err( item.span, fmt!("foreign items may not have type parameters")); @@ -761,11 +761,11 @@ pub impl FnCtxt { } fn expr_to_str(&self, expr: @ast::expr) -> ~str { - expr_repr(self.tcx(), expr) + expr.repr(self.tcx()) } fn pat_to_str(&self, pat: @ast::pat) -> ~str { - pat_repr(self.tcx(), pat) + pat.repr(self.tcx()) } fn expr_ty(&self, ex: @ast::expr) -> ty::t { @@ -1068,7 +1068,7 @@ pub fn impl_self_ty(vcx: &VtableContext, let (n_tps, region_param, raw_ty) = { let ity = ty::lookup_item_type(tcx, did); - (ity.generics.bounds.len(), ity.generics.region_param, ity.ty) + (ity.generics.type_param_defs.len(), ity.generics.region_param, ity.ty) }; let self_r = if region_param.is_some() { @@ -1893,7 +1893,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } else { let item_type = ty::lookup_item_type(tcx, class_id); - type_parameter_count = item_type.generics.bounds.len(); + type_parameter_count = item_type.generics.type_param_defs.len(); region_parameterized = item_type.generics.region_param; raw_type = item_type.ty; } @@ -1981,7 +1981,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } else { let item_type = ty::lookup_item_type(tcx, enum_id); - type_parameter_count = item_type.generics.bounds.len(); + type_parameter_count = item_type.generics.type_param_defs.len(); region_parameterized = item_type.generics.region_param; raw_type = item_type.ty; } @@ -3153,7 +3153,7 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, // extern functions are just u8 pointers return ty_param_bounds_and_ty { generics: ty::Generics { - bounds: @~[], + type_param_defs: @~[], region_param: None }, ty: ty::mk_ptr( @@ -3218,7 +3218,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt, region_lb: ty::Region) { debug!(">>> instantiate_path"); - let ty_param_count = tpt.generics.bounds.len(); + let ty_param_count = tpt.generics.type_param_defs.len(); let ty_substs_len = vec::len(pth.types); debug!("ty_param_count=%? ty_substs_len=%?", @@ -3692,7 +3692,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { output: output} }); let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); - let i_n_tps = i_ty.generics.bounds.len(); + let i_n_tps = i_ty.generics.type_param_defs.len(); if i_n_tps != n_tps { tcx.sess.span_err(it.span, fmt!("intrinsic has wrong number \ of type parameters: found %u, \ diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index c30765baf37b3..6ea668605fd4d 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -20,6 +20,7 @@ use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; use middle::typeck::infer; use middle::typeck::{CrateCtxt, vtable_origin, vtable_param, vtable_res}; use middle::typeck::vtable_static; +use middle::subst::Subst; use util::common::indenter; use util::ppaux::tys_to_str; use util::ppaux; @@ -27,7 +28,6 @@ use util::ppaux; use core::result::{Ok, Err}; use core::result; use core::uint; -use core::vec; use core::hashmap::HashSet; use syntax::ast; use syntax::ast_util; @@ -70,45 +70,43 @@ pub impl VtableContext { fn tcx(&const self) -> ty::ctxt { self.ccx.tcx } } -fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool { - vec::any(tps, |bs| { - bs.any(|b| { - match b { &ty::bound_trait(_) => true, _ => false } - }) - }) +fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool { + type_param_defs.any( + |type_param_def| type_param_def.bounds.any( + |bound| match bound { &ty::bound_trait(*) => true, _ => false })) } fn lookup_vtables(vcx: &VtableContext, location_info: &LocationInfo, - bounds: @~[ty::param_bounds], + type_param_defs: &[ty::TypeParameterDef], substs: &ty::substs, is_early: bool) -> vtable_res { - debug!("lookup_vtables(location_info=%?, - # bounds=%?, \ + debug!("lookup_vtables(location_info=%?, \ + type_param_defs=%s, \ substs=%s", location_info, - bounds.len(), - ty::substs_to_str(vcx.tcx(), substs)); + type_param_defs.repr(vcx.tcx()), + substs.repr(vcx.tcx())); let _i = indenter(); let tcx = vcx.tcx(); let mut result = ~[], i = 0u; for substs.tps.each |ty| { - for ty::iter_bound_traits_and_supertraits( - tcx, bounds[i]) |trait_ref| + // ty is the value supplied for the type parameter A... + + for ty::each_bound_trait_and_supertraits( + tcx, type_param_defs[i].bounds) |trait_ref| { - debug!("about to subst: %?, %?", - ppaux::trait_ref_to_str(tcx, trait_ref), - ty::substs_to_str(tcx, substs)); + // ...and here trait_ref is each bound that was declared on A, + // expressed in terms of the type parameters. + + debug!("about to subst: %s, %s", trait_ref.repr(tcx), substs.repr(tcx)); - let new_substs = substs { - self_ty: Some(*ty), - ../*bad*/copy *substs - }; - let trait_ref = ty::subst_in_trait_ref(tcx, &new_substs, trait_ref); + // Substitute the values of the type parameters that may + // appear in the bound. + let trait_ref = trait_ref.subst(tcx, substs); - debug!("after subst: %?", - vcx.infcx.trait_ref_to_str(&trait_ref)); + debug!("after subst: %s", trait_ref.repr(tcx)); match lookup_vtable(vcx, location_info, *ty, &trait_ref, is_early) { Some(vtable) => result.push(vtable), @@ -125,14 +123,14 @@ fn lookup_vtables(vcx: &VtableContext, i += 1u; } debug!("lookup_vtables result(\ - location_info=%?, - # bounds=%?, \ + location_info=%?, \ + type_param_defs=%s, \ substs=%s, \ - result=%?", + result=%s)", location_info, - bounds.len(), - ty::substs_to_str(vcx.tcx(), substs), - result); + type_param_defs.repr(vcx.tcx()), + substs.repr(vcx.tcx()), + result.repr(vcx.tcx())); @result } @@ -219,12 +217,11 @@ fn lookup_vtable(vcx: &VtableContext, match ty::get(ty).sty { ty::ty_param(param_ty {idx: n, def_id: did}) => { let mut n_bound = 0; - let bounds = *tcx.ty_param_bounds.get(&did.node); - for ty::iter_bound_traits_and_supertraits( - tcx, bounds) |bound_trait_ref| + let type_param_def = tcx.ty_param_defs.get(&did.node); + for ty::each_bound_trait_and_supertraits( + tcx, type_param_def.bounds) |bound_trait_ref| { - debug!("checking bounds trait %?", - vcx.infcx.trait_ref_to_str(bound_trait_ref)); + debug!("checking bounds trait %s", bound_trait_ref.repr(vcx.tcx())); if bound_trait_ref.def_id == trait_ref.def_id { relate_trait_refs(vcx, @@ -302,6 +299,8 @@ fn lookup_vtable(vcx: &VtableContext, // of the thing that we're trying to cast // to some_trait. If not, then we try the next // impl. + // + // FIXME(#5781) this should be mk_eqty not mk_subty let ty::ty_param_substs_and_ty { substs: substs, ty: for_ty @@ -341,8 +340,7 @@ fn lookup_vtable(vcx: &VtableContext, vcx.infcx.trait_ref_to_str(trait_ref), vcx.infcx.trait_ref_to_str(of_trait_ref)); - let of_trait_ref = - ty::subst_in_trait_ref(tcx, &substs, of_trait_ref); + let of_trait_ref = of_trait_ref.subst(tcx, &substs); relate_trait_refs( vcx, location_info, &of_trait_ref, trait_ref); @@ -387,15 +385,16 @@ fn lookup_vtable(vcx: &VtableContext, // to. connect_trait_tps requires these // lists of types to unify pairwise. - let im_bs = - ty::lookup_item_type(tcx, im.did).generics.bounds; + let im_generics = + ty::lookup_item_type(tcx, im.did).generics; connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did); let subres = lookup_vtables( - vcx, location_info, im_bs, &substs_f, + vcx, location_info, + *im_generics.type_param_defs, &substs_f, is_early); // Finally, we register that we found a @@ -460,15 +459,15 @@ fn connect_trait_tps(vcx: &VtableContext, // XXX: This should work for multiple traits. let impl_trait_ref = ty::impl_trait_refs(tcx, impl_did)[0]; - let impl_trait_ref = ty::subst_in_trait_ref(tcx, impl_substs, impl_trait_ref); - relate_trait_refs(vcx, location_info, trait_ref, &impl_trait_ref); + let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); + relate_trait_refs(vcx, location_info, &impl_trait_ref, trait_ref); } fn insert_vtables(fcx: @mut FnCtxt, callee_id: ast::node_id, vtables: vtable_res) { debug!("insert_vtables(callee_id=%d, vtables=%?)", - callee_id, vtables.map(|v| v.to_str(fcx.tcx()))); + callee_id, vtables.repr(fcx.tcx())); fcx.inh.vtable_map.insert(callee_id, vtables); } @@ -493,17 +492,15 @@ pub fn early_resolve_expr(ex: @ast::expr, let def = *cx.tcx.def_map.get(&ex.id); let did = ast_util::def_id_of_def(def); let item_ty = ty::lookup_item_type(cx.tcx, did); - debug!("early resolve expr: def %? %?, %?, %?", ex.id, did, def, + debug!("early resolve expr: def %? %?, %?, %s", ex.id, did, def, fcx.infcx().ty_to_str(item_ty.ty)); - if has_trait_bounds(/*bad*/copy *item_ty.generics.bounds) { - for item_ty.generics.bounds.each |bounds| { - debug!("early_resolve_expr: looking up vtables for bound \ - %s", - ty::param_bounds_to_str(fcx.tcx(), *bounds)); - } + if has_trait_bounds(*item_ty.generics.type_param_defs) { + debug!("early_resolve_expr: looking up vtables for type params %s", + item_ty.generics.type_param_defs.repr(fcx.tcx())); let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex), - item_ty.generics.bounds, substs, is_early); + *item_ty.generics.type_param_defs, + substs, is_early); if !is_early { insert_vtables(fcx, ex.id, vtbls); } @@ -519,9 +516,9 @@ pub fn early_resolve_expr(ex: @ast::expr, ast::expr_binary(*) | ast::expr_unary(*) | ast::expr_assign_op(*) | ast::expr_index(*) | ast::expr_method_call(*) => { - match ty::method_call_bounds(cx.tcx, fcx.inh.method_map, ex.id) { - Some(bounds) => { - if has_trait_bounds(/*bad*/copy *bounds) { + match ty::method_call_type_param_defs(cx.tcx, fcx.inh.method_map, ex.id) { + Some(type_param_defs) => { + if has_trait_bounds(*type_param_defs) { let callee_id = match ex.node { ast::expr_field(_, _, _) => ex.id, _ => ex.callee_id @@ -530,7 +527,7 @@ pub fn early_resolve_expr(ex: @ast::expr, let substs = fcx.node_ty_substs(callee_id); let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex), - bounds, &substs, is_early); + *type_param_defs, &substs, is_early); if !is_early { insert_vtables(fcx, callee_id, vtbls); } @@ -561,7 +558,11 @@ pub fn early_resolve_expr(ex: @ast::expr, }; let target_trait_ref = ty::TraitRef { def_id: target_def_id, - substs: copy *target_substs + substs: ty::substs { + tps: copy target_substs.tps, + self_r: target_substs.self_r, + self_ty: Some(mt.ty) + } }; let vtable_opt = lookup_vtable(&vcx, diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 31301db2a0a1b..3af4cb7f10cb4 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -91,7 +91,7 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { let vtable_map = fcx.ccx.vtable_map; vtable_map.insert(id, r_origins); debug!("writeback::resolve_vtable_map_entry(id=%d, vtables=%?)", - id, r_origins.map(|v| v.to_str(fcx.tcx()))); + id, r_origins.repr(fcx.tcx())); } } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index b0e5ecee01ebb..174a20dd7f4c7 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -32,6 +32,7 @@ use middle::ty::{ty_rptr, ty_self, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_type, ty_uint, ty_uniq, ty_bare_fn, ty_closure}; use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec}; use middle::ty::{type_is_ty_var}; +use middle::subst::Subst; use middle::ty; use middle::typeck::CrateCtxt; use middle::typeck::infer::combine::Combine; @@ -59,7 +60,7 @@ use core::uint; pub struct UniversalQuantificationResult { monotype: t, type_variables: ~[ty::t], - bounds: @~[param_bounds] + type_param_defs: @~[ty::TypeParameterDef] } pub fn get_base_type(inference_context: @mut InferCtxt, @@ -269,17 +270,16 @@ pub impl CoherenceChecker { // We only want to generate one Impl structure. When we generate one, // we store it here so that we don't recreate it. let mut implementation_opt = None; - for associated_traits.each |associated_trait| { - let trait_did = - self.trait_ref_to_trait_def_id(*associated_trait); - debug!("(checking implementation) adding impl for trait \ - '%s', item '%s'", - ast_map::node_id_to_str( - self.crate_context.tcx.items, trait_did.node, - self.crate_context.tcx.sess.parse_sess.interner), - *self.crate_context.tcx.sess.str_of(item.ident)); - - self.instantiate_default_methods(item.id, trait_did); + for associated_traits.each |&associated_trait| { + let trait_ref = + ty::node_id_to_trait_ref( + self.crate_context.tcx, + associated_trait.ref_id); + debug!("(checking implementation) adding impl for trait '%s', item '%s'", + trait_ref.repr(self.crate_context.tcx), + *self.crate_context.tcx.sess.str_of(item.ident)); + + self.instantiate_default_methods(item.id, trait_ref); let implementation; if implementation_opt.is_none() { @@ -287,7 +287,7 @@ pub impl CoherenceChecker { implementation_opt = Some(implementation); } - self.add_trait_method(trait_did, implementation_opt.get()); + self.add_trait_method(trait_ref.def_id, implementation_opt.get()); } // Add the implementation to the mapping from implementation to base @@ -325,22 +325,48 @@ pub impl CoherenceChecker { // 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: ast::node_id, - trait_did: ast::def_id) { - for self.each_provided_trait_method(trait_did) |trait_method| { + fn instantiate_default_methods(&self, + impl_id: ast::node_id, + trait_ref: &ty::TraitRef) { + let tcx = self.crate_context.tcx; + debug!("instantiate_default_methods(impl_id=%?, trait_ref=%s)", + impl_id, trait_ref.repr(tcx)); + + let impl_poly_type = ty::lookup_item_type(tcx, local_def(impl_id)); + + for self.each_provided_trait_method(trait_ref.def_id) |trait_method| { // Synthesize an ID. - let tcx = self.crate_context.tcx; let new_id = parse::next_node_id(tcx.sess.parse_sess); let new_did = local_def(new_id); - let new_method_ty = @ty::method { - def_id: new_did, - ..copy *trait_method + debug!("new_did=%? trait_method=%s", new_did, trait_method.repr(tcx)); + + // Create substitutions for the various trait parameters. + let new_method_ty = + @subst_receiver_types_in_method_ty( + tcx, + impl_id, + trait_ref, + new_did, + trait_method); + + debug!("new_method_ty=%s", new_method_ty.repr(tcx)); + + // construct the polytype for the method based on the method_ty + let new_generics = ty::Generics { + type_param_defs: + @vec::append( + copy *impl_poly_type.generics.type_param_defs, + *new_method_ty.generics.type_param_defs), + region_param: + impl_poly_type.generics.region_param + }; + let new_polytype = ty::ty_param_bounds_and_ty { + generics: new_generics, + ty: ty::mk_bare_fn(tcx, copy new_method_ty.fty) }; + debug!("new_polytype=%s", new_polytype.repr(tcx)); - // XXX: Perform substitutions. - let new_polytype = ty::lookup_item_type(tcx, - trait_method.def_id); tcx.tcache.insert(new_did, new_polytype); tcx.methods.insert(new_did, new_method_ty); @@ -358,7 +384,7 @@ pub impl CoherenceChecker { @ProvidedMethodInfo { method_info: @MethodInfo { did: new_did, - n_tps: trait_method.generics.bounds.len(), + n_tps: trait_method.generics.type_param_defs.len(), ident: trait_method.ident, self_type: trait_method.self_ty }, @@ -545,9 +571,8 @@ pub impl CoherenceChecker { polytype.generics.region_param.map( |_r| self.inference_context.next_region_var_nb(dummy_sp())); - let bounds_count = polytype.generics.bounds.len(); - let type_parameters = - self.inference_context.next_ty_vars(bounds_count); + let bounds_count = polytype.generics.type_param_defs.len(); + let type_parameters = self.inference_context.next_ty_vars(bounds_count); let substitutions = substs { self_r: self_region, @@ -565,7 +590,7 @@ pub impl CoherenceChecker { UniversalQuantificationResult { monotype: monotype, type_variables: type_parameters, - bounds: polytype.generics.bounds + type_param_defs: polytype.generics.type_param_defs } } @@ -582,13 +607,13 @@ pub impl CoherenceChecker { // Check to ensure that each parameter binding respected its // kind bounds. for [ a, b ].each |result| { - for vec::each2(result.type_variables, *result.bounds) - |ty_var, bounds| { + for vec::each2(result.type_variables, *result.type_param_defs) + |ty_var, type_param_def| { match resolve_type(self.inference_context, *ty_var, resolve_nested_tvar) { Ok(resolved_ty) => { - for bounds.each |bound| { + for type_param_def.bounds.each |bound| { match *bound { bound_copy => { if !ty::type_is_copyable( @@ -914,7 +939,7 @@ pub impl CoherenceChecker { @ProvidedMethodInfo { method_info: @MethodInfo { did: new_did, - n_tps: trait_method_info.ty.generics.bounds.len(), + n_tps: trait_method_info.ty.generics.type_param_defs.len(), ident: trait_method_info.ty.ident, self_type: trait_method_info.ty.self_ty }, @@ -1010,6 +1035,70 @@ pub impl CoherenceChecker { } } +fn subst_receiver_types_in_method_ty( + tcx: ty::ctxt, + impl_id: ast::node_id, + trait_ref: &ty::TraitRef, + new_def_id: ast::def_id, + method: &ty::method) -> ty::method +{ + /*! + * 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. + */ + + // determine how many type parameters were declared on the impl + let num_impl_type_parameters = { + let impl_polytype = ty::lookup_item_type(tcx, local_def(impl_id)); + impl_polytype.generics.type_param_defs.len() + }; + + // determine how many type parameters appear on the trait + let num_trait_type_parameters = trait_ref.substs.tps.len(); + + // the current method type has the type parameters from the trait + method + let num_method_type_parameters = + num_trait_type_parameters + method.generics.type_param_defs.len(); + + // the new method type will have the type parameters from the impl + method + let combined_tps = vec::from_fn(num_method_type_parameters, |i| { + if i < num_trait_type_parameters { + // replace type parameters that come from trait with new value + trait_ref.substs.tps[i] + } else { + // replace type parameters that belong to method with another + // type parameter, this time with the index adjusted + let method_index = i - num_trait_type_parameters; + let type_param_def = &method.generics.type_param_defs[method_index]; + let new_index = num_impl_type_parameters + method_index; + ty::mk_param(tcx, new_index, type_param_def.def_id) + } + }); + + let combined_substs = ty::substs { + self_r: trait_ref.substs.self_r, + self_ty: trait_ref.substs.self_ty, + tps: combined_tps + }; + + ty::method { + ident: method.ident, + + // method tps cannot appear in the self_ty, so use `substs` from trait ref + transformed_self_ty: method.transformed_self_ty.subst(tcx, &trait_ref.substs), + + // method types *can* appear in the generic bounds or the fty + generics: method.generics.subst(tcx, &combined_substs), + fty: method.fty.subst(tcx, &combined_substs), + self_ty: method.self_ty, + vis: method.vis, + def_id: new_def_id + } +} + pub fn check_coherence(crate_context: @mut CrateCtxt, crate: @crate) { let coherence_checker = @CoherenceChecker(crate_context); coherence_checker.check_coherence(crate); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index a9d54716cd8a8..a3296f6c20985 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -35,6 +35,7 @@ use core::prelude::*; use metadata::csearch; use middle::ty::{substs, ty_param_bounds_and_ty}; use middle::ty; +use middle::subst::Subst; use middle::typeck::astconv::{AstConv, ty_of_arg}; use middle::typeck::astconv::{ast_ty_to_ty}; use middle::typeck::astconv; @@ -186,7 +187,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, ast::struct_variant_kind(struct_def) => { let tpt = ty_param_bounds_and_ty { - generics: ty_generics(ccx, rp, generics), + generics: ty_generics(ccx, rp, generics, 0), ty: enum_ty }; @@ -207,7 +208,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, None => {} Some(result_ty) => { let tpt = ty_param_bounds_and_ty { - generics: ty_generics(ccx, rp, generics), + generics: ty_generics(ccx, rp, generics, 0), ty: result_ty }; tcx.tcache.insert(local_def(variant.node.id), tpt); @@ -227,7 +228,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, node: ast::item_trait(ref generics, _, ref ms), _ }, _) => { - let trait_ty_generics = ty_generics(ccx, region_paramd, generics); + let trait_ty_generics = ty_generics(ccx, region_paramd, generics, 0); // For each method, construct a suitable ty::method and // store it into the `tcx.methods` table: @@ -274,48 +275,99 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::node_id, m: &ty::method, trait_ty_generics: &ty::Generics) { - // We need to create a typaram that replaces self. This param goes - // *in between* the typarams from the trait and those from the - // method (since its bound can depend on the trait? or - // something like that). + // If declaration is + // + // trait { + // fn foo(...) -> Self; + // } + // + // and we will create a function like + // + // fn foo(...) -> 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. + // + // 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::def_id {crate: 0, node: 0}; - let num_trait_bounds = trait_ty_generics.bounds.len(); + // Represents [A',B',C'] + let num_trait_bounds = trait_ty_generics.type_param_defs.len(); let non_shifted_trait_tps = do vec::from_fn(num_trait_bounds) |i| { - ty::mk_param(ccx.tcx, i, dummy_defid) + ty::mk_param(tcx, i, dummy_defid) }; - let self_param = ty::mk_param(ccx.tcx, num_trait_bounds, + + // Represents [D'] + let self_param = ty::mk_param(tcx, num_trait_bounds, dummy_defid); - let shifted_method_tps = do vec::from_fn(m.generics.bounds.len()) |i| { - ty::mk_param(ccx.tcx, i + 1, dummy_defid) + + // Represents [E',F',G'] + let num_method_bounds = m.generics.type_param_defs.len(); + let shifted_method_tps = do vec::from_fn(num_method_bounds) |i| { + ty::mk_param(tcx, i + 1, dummy_defid) }; + // build up the substitution from + // A,B,C => A',B',C' + // Self => D' + // D,E,F => E',F',G' let substs = substs { self_r: None, self_ty: Some(self_param), tps: non_shifted_trait_tps + shifted_method_tps }; - let ty = ty::subst(ccx.tcx, + + // create the type of `foo`, applying the substitution above + let ty = ty::subst(tcx, &substs, - ty::mk_bare_fn(ccx.tcx, copy m.fty)); - let trait_def = get_trait_def(ccx, local_def(trait_id)); - let trait_ref = trait_def.trait_ref; - let mut new_bounds = ~[]; - new_bounds.push_all(*trait_ty_generics.bounds); - new_bounds.push(@~[ty::bound_trait(trait_ref)]); - new_bounds.push_all(*m.generics.bounds); - ccx.tcx.tcache.insert(m.def_id, - ty_param_bounds_and_ty { - generics: ty::Generics { - bounds: @new_bounds, - region_param: trait_ty_generics.region_param - }, - ty: ty - }); + ty::mk_bare_fn(tcx, copy m.fty)); + + // 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 = ~[]; + let substd_type_param_defs = + trait_ty_generics.type_param_defs.subst(tcx, &substs); + new_type_param_defs.push_all(*substd_type_param_defs); + + // 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 { + def_id: dummy_defid, + bounds: @~[ty::bound_trait(self_trait_ref)] + }); + + // 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); + + debug!("static method %s type_param_defs=%s substs=%s", + m.def_id.repr(tcx), + new_type_param_defs.repr(tcx), + substs.repr(tcx)); + + tcx.tcache.insert(m.def_id, + ty_param_bounds_and_ty { + generics: ty::Generics { + type_param_defs: @new_type_param_defs, + region_param: trait_ty_generics.region_param + }, + ty: ty + }); } fn ty_method_of_trait_method(self: &CrateCtxt, @@ -334,9 +386,10 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, let (transformed_self_ty, fty) = astconv::ty_of_method(self, &rscope, *m_purity, &m_generics.lifetimes, trait_self_ty, *m_self_ty, m_decl); + let num_trait_type_params = trait_generics.ty_params.len(); ty::method { ident: *m_ident, - generics: ty_generics(self, None, m_generics), + generics: ty_generics(self, None, m_generics, num_trait_type_params), transformed_self_ty: transformed_self_ty, fty: fty, self_ty: m_self_ty.node, @@ -357,9 +410,11 @@ pub fn ensure_supertraits(ccx: &CrateCtxt, let tcx = ccx.tcx; if tcx.supertraits.contains_key(&local_def(id)) { return; } + let self_ty = ty::mk_self(ccx.tcx, local_def(id)); let mut ty_trait_refs: ~[@ty::TraitRef] = ~[]; for ast_trait_refs.each |&ast_trait_ref| { - let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, rp, generics); + let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, rp, + generics, self_ty); // FIXME(#5527) Could have same trait multiple times if ty_trait_refs.any(|other_trait| other_trait.def_id == trait_ref.def_id) { @@ -426,15 +481,18 @@ pub fn compare_impl_method(tcx: ty::ctxt, } } - if impl_m.generics.bounds.len() != trait_m.generics.bounds.len() { + 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(); + if num_impl_m_type_params != num_trait_m_type_params { tcx.sess.span_err( cm.span, fmt!("method `%s` has %u type %s, but its trait \ declaration has %u type %s", - *tcx.sess.str_of(trait_m.ident), impl_m.generics.bounds.len(), - pluralize(impl_m.generics.bounds.len(), ~"parameter"), - trait_m.generics.bounds.len(), - pluralize(trait_m.generics.bounds.len(), ~"parameter"))); + *tcx.sess.str_of(trait_m.ident), + num_impl_m_type_params, + pluralize(num_impl_m_type_params, ~"parameter"), + num_trait_m_type_params, + pluralize(num_trait_m_type_params, ~"parameter"))); return; } @@ -452,23 +510,23 @@ pub fn compare_impl_method(tcx: ty::ctxt, // FIXME(#2687)---we should be checking that the bounds of the // trait imply the bounds of the subtype, but it appears // we are...not checking this. - for trait_m.generics.bounds.eachi() |i, trait_param_bounds| { + for trait_m.generics.type_param_defs.eachi |i, trait_param_def| { // For each of the corresponding impl ty param's bounds... - let impl_param_bounds = impl_m.generics.bounds[i]; + let impl_param_def = &impl_m.generics.type_param_defs[i]; // Make sure the bounds lists have the same length // Would be nice to use the ty param names in the error message, // but we don't have easy access to them here - if impl_param_bounds.len() != trait_param_bounds.len() { + if impl_param_def.bounds.len() != trait_param_def.bounds.len() { tcx.sess.span_err( cm.span, fmt!("in method `%s`, \ type parameter %u has %u %s, but the same type \ parameter in its trait declaration has %u %s", *tcx.sess.str_of(trait_m.ident), - i, impl_param_bounds.len(), - pluralize(impl_param_bounds.len(), ~"bound"), - trait_param_bounds.len(), - pluralize(trait_param_bounds.len(), ~"bound"))); + i, impl_param_def.bounds.len(), + pluralize(impl_param_def.bounds.len(), ~"bound"), + trait_param_def.bounds.len(), + pluralize(trait_param_def.bounds.len(), ~"bound"))); return; } } @@ -492,12 +550,12 @@ pub fn compare_impl_method(tcx: ty::ctxt, debug!("impl_fty (pre-subst): %s", ppaux::ty_to_str(tcx, impl_fty)); replace_bound_self(tcx, impl_fty, dummy_self_r) }; - debug!("impl_fty: %s", ppaux::ty_to_str(tcx, impl_fty)); + debug!("impl_fty (post-subst): %s", ppaux::ty_to_str(tcx, impl_fty)); let trait_fty = { - let dummy_tps = do vec::from_fn(trait_m.generics.bounds.len()) |i| { - // hack: we don't know the def id of the impl tp, but it - // is not important for unification - ty::mk_param(tcx, i + impl_tps, ast::def_id {crate: 0, node: 0}) + let num_trait_m_type_params = trait_m.generics.type_param_defs.len(); + let dummy_tps = do vec::from_fn(num_trait_m_type_params) |i| { + ty::mk_param(tcx, i + impl_tps, + impl_m.generics.type_param_defs[i].def_id) }; let trait_tps = trait_substs.tps.map( |t| replace_bound_self(tcx, *t, dummy_self_r)); @@ -507,9 +565,11 @@ pub fn compare_impl_method(tcx: ty::ctxt, tps: vec::append(trait_tps, dummy_tps) }; let trait_fty = ty::mk_bare_fn(tcx, copy trait_m.fty); - debug!("trait_fty (pre-subst): %s", ppaux::ty_to_str(tcx, trait_fty)); + debug!("trait_fty (pre-subst): %s substs=%s", + trait_fty.repr(tcx), substs.repr(tcx)); ty::subst(tcx, &substs, trait_fty) }; + debug!("trait_fty (post-subst): %s", trait_fty.repr(tcx)); let infcx = infer::new_infer_ctxt(tcx); match infer::mk_subty(infcx, false, cm.span, impl_fty, trait_fty) { @@ -542,7 +602,8 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, impl_ms: &[ConvertedMethod]) { let tcx = ccx.tcx; - let trait_ref = instantiate_trait_ref(ccx, a_trait_ty, rp, generics); + let trait_ref = instantiate_trait_ref(ccx, a_trait_ty, rp, + generics, selfty); if trait_ref.def_id.crate == ast::local_crate { ensure_trait_methods(ccx, trait_ref.def_id.node); @@ -574,7 +635,7 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, pub fn convert_field(ccx: &CrateCtxt, rp: Option, - bounds: @~[ty::param_bounds], + type_param_defs: @~[ty::TypeParameterDef], v: @ast::struct_field, generics: &ast::Generics) { let region_parameterization = @@ -585,7 +646,7 @@ pub fn convert_field(ccx: &CrateCtxt, ccx.tcx.tcache.insert(local_def(v.node.id), ty::ty_param_bounds_and_ty { generics: ty::Generics { - bounds: bounds, + type_param_defs: type_param_defs, region_param: rp }, ty: tt @@ -609,8 +670,10 @@ pub fn convert_methods(ccx: &CrateCtxt, { let tcx = ccx.tcx; return vec::map(ms, |m| { + let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs.len(); let m_ty_generics = - ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics); + ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics, + num_rcvr_ty_params); let mty = @ty_of_method(ccx, *m, rcvr_ty_generics.region_param, untransformed_rcvr_ty, @@ -625,8 +688,9 @@ pub fn convert_methods(ccx: &CrateCtxt, // the tps on the receiver and those on the method itself ty_param_bounds_and_ty { generics: ty::Generics { - bounds: @(vec::append(copy *rcvr_ty_generics.bounds, - *m_ty_generics.bounds)), + type_param_defs: @vec::append( + copy *rcvr_ty_generics.type_param_defs, + *m_ty_generics.type_param_defs), region_param: rcvr_ty_generics.region_param }, ty: fty @@ -660,9 +724,10 @@ pub 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(); ty::method { ident: m.ident, - generics: ty_generics(ccx, None, &m.generics), + generics: ty_generics(ccx, None, &m.generics, num_rcvr_type_params), transformed_self_ty: transformed_self_ty, fty: fty, self_ty: m.self_ty.node, @@ -705,7 +770,7 @@ pub fn convert(ccx: &CrateCtxt, it: @ast::item) { rp); } ast::item_impl(ref generics, opt_trait_ref, selfty, ref ms) => { - let i_ty_generics = ty_generics(ccx, rp, generics); + let i_ty_generics = ty_generics(ccx, rp, generics, 0); let region_parameterization = RegionParameterization::from_variance_and_generics(rp, generics); let selfty = ccx.to_ty(&type_rscope(region_parameterization), selfty); @@ -741,8 +806,9 @@ pub fn convert(ccx: &CrateCtxt, it: @ast::item) { let (_, provided_methods) = split_trait_methods(*trait_methods); - let (ty_generics, _) = mk_substs(ccx, generics, rp); let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id)); + let (ty_generics, _) = mk_item_substs(ccx, generics, rp, + Some(untransformed_rcvr_ty)); let _ = convert_methods(ccx, provided_methods, untransformed_rcvr_ty, &ty_generics, generics, @@ -799,7 +865,7 @@ pub fn convert_struct(ccx: &CrateCtxt, tcx.tcache.insert(local_def(dtor.node.id), ty_param_bounds_and_ty { generics: ty::Generics { - bounds: tpt.generics.bounds, + type_param_defs: tpt.generics.type_param_defs, region_param: rp }, ty: t_dtor}); @@ -807,9 +873,9 @@ pub fn convert_struct(ccx: &CrateCtxt, // Write the type of each of the members for struct_def.fields.each |f| { - convert_field(ccx, rp, tpt.generics.bounds, *f, generics); + convert_field(ccx, rp, tpt.generics.type_param_defs, *f, generics); } - let (_, substs) = mk_substs(ccx, generics, rp); + let (_, substs) = mk_item_substs(ccx, generics, rp, None); let selfty = ty::mk_struct(tcx, local_def(id), substs); // If this struct is enum-like or tuple-like, create the type of its @@ -850,7 +916,8 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: @ast::foreign_item) { pub fn instantiate_trait_ref(ccx: &CrateCtxt, ast_trait_ref: @ast::trait_ref, rp: Option, - generics: &ast::Generics) -> @ty::TraitRef + generics: &ast::Generics, + self_ty: ty::t) -> @ty::TraitRef { /*! * Instantiates the path for the given trait reference, assuming that @@ -866,7 +933,7 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt, ast::def_trait(trait_did) => { let trait_ref = astconv::ast_path_to_trait_ref( - ccx, &rscope, trait_did, ast_trait_ref.path); + ccx, &rscope, trait_did, Some(self_ty), ast_trait_ref.path); ccx.tcx.trait_refs.insert( ast_trait_ref.ref_id, trait_ref); return trait_ref; @@ -903,7 +970,9 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: @ast::item) -> @ty::TraitDef { let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); match it.node { ast::item_trait(ref generics, _, _) => { - let (ty_generics, substs) = mk_substs(ccx, generics, rp); + let self_ty = ty::mk_self(tcx, def_id); + let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, + Some(self_ty)); let trait_ref = @ty::TraitRef {def_id: def_id, substs: substs}; let trait_def = @ty::TraitDef {generics: ty_generics, @@ -937,7 +1006,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) } ast::item_fn(ref decl, purity, _, ref generics, _) => { assert!(rp.is_none()); - let ty_generics = ty_generics(ccx, None, generics); + let ty_generics = ty_generics(ccx, None, generics, 0); let tofd = astconv::ty_of_bare_fn(ccx, &empty_rscope, purity, @@ -946,7 +1015,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) decl); let tpt = ty_param_bounds_and_ty { generics: ty::Generics { - bounds: ty_generics.bounds, + type_param_defs: ty_generics.type_param_defs, region_param: None }, ty: ty::mk_bare_fn(ccx.tcx, tofd) @@ -979,7 +1048,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) } }; ty_param_bounds_and_ty { - generics: ty_generics(ccx, rp, generics), + generics: ty_generics(ccx, rp, generics, 0), ty: ty } }; @@ -989,7 +1058,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) } ast::item_enum(_, ref generics) => { // Create a new generic polytype. - let (ty_generics, substs) = mk_substs(ccx, generics, rp); + let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None); let t = ty::mk_enum(tcx, local_def(it.id), substs); let tpt = ty_param_bounds_and_ty { generics: ty_generics, @@ -1004,7 +1073,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) fmt!("Invoked ty_of_item on trait")); } ast::item_struct(_, ref generics) => { - let (ty_generics, substs) = mk_substs(ccx, generics, rp); + let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None); let t = ty::mk_struct(tcx, local_def(it.id), substs); let tpt = ty_param_bounds_and_ty { generics: ty_generics, @@ -1031,7 +1100,7 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, it: @ast::foreign_item) ast::foreign_item_const(t) => { ty::ty_param_bounds_and_ty { generics: ty::Generics { - bounds: @~[], + type_param_defs: @~[], region_param: None, }, ty: ast_ty_to_ty(ccx, &empty_rscope, t) @@ -1042,16 +1111,25 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, it: @ast::foreign_item) pub fn ty_generics(ccx: &CrateCtxt, rp: Option, - generics: &ast::Generics) -> ty::Generics { + generics: &ast::Generics, + base_index: uint) -> ty::Generics { return ty::Generics { region_param: rp, - bounds: @generics.ty_params.map_to_vec(|param| { - match ccx.tcx.ty_param_bounds.find(¶m.id) { - Some(&bs) => bs, + type_param_defs: @generics.ty_params.mapi_to_vec(|offset, param| { + match ccx.tcx.ty_param_defs.find(¶m.id) { + Some(&def) => def, None => { - let bounds = compute_bounds(ccx, rp, generics, param.bounds); - ccx.tcx.ty_param_bounds.insert(param.id, bounds); - bounds + let param_ty = ty::param_ty {idx: base_index + offset, + def_id: local_def(param.id)}; + let bounds = compute_bounds(ccx, rp, generics, + param_ty, param.bounds); + let def = ty::TypeParameterDef { + def_id: local_def(param.id), + bounds: bounds + }; + debug!("def for param: %s", def.repr(ccx.tcx)); + ccx.tcx.ty_param_defs.insert(param.id, def); + def } } }) @@ -1061,6 +1139,7 @@ pub fn ty_generics(ccx: &CrateCtxt, ccx: &CrateCtxt, rp: Option, generics: &ast::Generics, + param_ty: ty::param_ty, ast_bounds: @OptVec) -> ty::param_bounds { /*! @@ -1076,7 +1155,8 @@ pub fn ty_generics(ccx: &CrateCtxt, match b { &TraitTyParamBound(b) => { let li = &ccx.tcx.lang_items; - let trait_ref = instantiate_trait_ref(ccx, b, rp, generics); + let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id); + let trait_ref = instantiate_trait_ref(ccx, b, rp, generics, ty); if trait_ref.def_id == li.owned_trait() { ~[ty::bound_owned] } else if trait_ref.def_id == li.copy_trait() { @@ -1104,7 +1184,7 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, def_id: ast::def_id, ast_generics: &ast::Generics) -> ty::ty_param_bounds_and_ty { - let ty_generics = ty_generics(ccx, None, ast_generics); + let ty_generics = ty_generics(ccx, None, ast_generics, 0); let region_param_names = RegionParamNames::from_generics(ast_generics); let rb = in_binding_rscope(&empty_rscope, region_param_names); let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, &rb, *a, None) ); @@ -1127,17 +1207,18 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, return tpt; } -pub fn mk_substs(ccx: &CrateCtxt, - ast_generics: &ast::Generics, - rp: Option) -> (ty::Generics, ty::substs) +pub fn mk_item_substs(ccx: &CrateCtxt, + ast_generics: &ast::Generics, + rp: Option, + self_ty: Option) -> (ty::Generics, ty::substs) { let mut i = 0; - let ty_generics = ty_generics(ccx, rp, ast_generics); + let ty_generics = ty_generics(ccx, rp, ast_generics, 0); let params = ast_generics.ty_params.map_to_vec(|atp| { let t = ty::mk_param(ccx.tcx, i, local_def(atp.id)); i += 1u; t }); let self_r = rscope::bound_self_region(rp); - (ty_generics, substs {self_r: self_r, self_ty: None, tps: params}) + (ty_generics, substs {self_r: self_r, self_ty: self_ty, tps: params}) } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 69c7b1d616b0a..be1d291cfe5c9 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -274,15 +274,14 @@ pub fn super_tps( pub fn super_self_tys( self: &C, a: Option, b: Option) -> cres> { - // Note: the self type parameter is (currently) always treated as - // *invariant* (otherwise the type system would be unsound). - match (a, b) { (None, None) => { Ok(None) } (Some(a), Some(b)) => { - eq_tys(self, a, b).then(|| Ok(Some(a)) ) + // FIXME(#5781) this should be eq_tys + // eq_tys(self, a, b).then(|| Ok(Some(a)) ) + self.contratys(a, b).chain(|t| Ok(Some(t))) } (None, Some(_)) | (Some(_), None) => { diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index d3502adb33ab8..fdb8049d79be9 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -53,6 +53,7 @@ use core::prelude::*; use middle::resolve; use middle::ty; use util::common::time; +use util::ppaux::Repr; use util::ppaux; use core::hashmap::HashMap; @@ -153,14 +154,15 @@ pub enum vtable_origin { vtable_param(uint, uint) } -pub impl vtable_origin { - fn to_str(&self, tcx: ty::ctxt) -> ~str { +impl Repr for vtable_origin { + fn repr(&self, tcx: ty::ctxt) -> ~str { match *self { vtable_static(def_id, ref tys, ref vtable_res) => { - fmt!("vtable_static(%?:%s, %?, %?)", - def_id, ty::item_path_str(tcx, def_id), - tys, - vtable_res.map(|o| o.to_str(tcx))) + fmt!("vtable_static(%?:%s, %s, %s)", + def_id, + ty::item_path_str(tcx, def_id), + tys.repr(tcx), + vtable_res.repr(tcx)) } vtable_param(x, y) => { @@ -222,7 +224,7 @@ pub fn lookup_def_ccx(ccx: @mut CrateCtxt, sp: span, id: ast::node_id) pub fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty { - generics: ty::Generics {bounds: @~[], + generics: ty::Generics {type_param_defs: @~[], region_param: None}, ty: t } diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 3a974fcdaae80..94fcb85d1d84c 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -83,6 +83,7 @@ pub mod middle { pub mod asm; } pub mod ty; + pub mod subst; pub mod resolve; #[path = "typeck/mod.rs"] pub mod typeck; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 3b3c42d5d8b2e..f26eeeca446c1 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -11,6 +11,7 @@ use core::prelude::*; use middle::ty; +use middle::typeck; use middle::ty::canon_mode; use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid, br_fresh}; @@ -35,6 +36,10 @@ use syntax::abi::AbiSet; use core::str; use core::vec; +pub trait Repr { + fn repr(&self, tcx: ctxt) -> ~str; +} + pub fn note_and_explain_region(cx: ctxt, prefix: ~str, region: ty::Region, @@ -257,18 +262,6 @@ pub fn vstore_ty_to_str(cx: ctxt, ty: ~str, vs: ty::vstore) -> ~str { } } -pub fn expr_repr(cx: ctxt, expr: @ast::expr) -> ~str { - fmt!("expr(%d: %s)", - expr.id, - pprust::expr_to_str(expr, cx.sess.intr())) -} - -pub fn pat_repr(cx: ctxt, pat: @ast::pat) -> ~str { - fmt!("pat(%d: %s)", - pat.id, - pprust::pat_to_str(pat, cx.sess.intr())) -} - pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str { let tstrs = ts.map(|t| ty_to_str(cx, *t)); fmt!("(%s)", str::connect(tstrs, ", ")) @@ -287,7 +280,13 @@ pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str { pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str { let path = ty::item_path(cx, trait_ref.def_id); let base = ast_map::path_to_str(path, cx.sess.intr()); - parameterized(cx, base, trait_ref.substs.self_r, trait_ref.substs.tps) + if cx.sess.verbose() && trait_ref.substs.self_ty.is_some() { + let mut all_tps = copy trait_ref.substs.tps; + for trait_ref.substs.self_ty.each |&t| { all_tps.push(t); } + parameterized(cx, base, trait_ref.substs.self_r, all_tps) + } else { + parameterized(cx, base, trait_ref.substs.self_r, trait_ref.substs.tps) + } } pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { @@ -497,10 +496,261 @@ pub fn ty_to_short_str(cx: ctxt, typ: t) -> ~str { return s; } +impl Repr for Option { + fn repr(&self, tcx: ctxt) -> ~str { + match self { + &None => ~"None", + &Some(ref t) => fmt!("Some(%s)", t.repr(tcx)) + } + } +} + +/* +Annoyingly, these conflict with @ast::expr. + +impl Repr for @T { + fn repr(&self, tcx: ctxt) -> ~str { + (&**self).repr(tcx) + } +} + +impl Repr for ~T { + fn repr(&self, tcx: ctxt) -> ~str { + (&**self).repr(tcx) + } +} +*/ + +fn repr_vec(tcx: ctxt, v: &[T]) -> ~str { + fmt!("[%s]", str::connect(v.map(|t| t.repr(tcx)), ",")) +} + +impl<'self, T:Repr> Repr for &'self [T] { + fn repr(&self, tcx: ctxt) -> ~str { + repr_vec(tcx, *self) + } +} + +// This is necessary to handle types like Option<@~[T]>, for which +// autoderef cannot convert the &[T] handler +impl Repr for @~[T] { + fn repr(&self, tcx: ctxt) -> ~str { + repr_vec(tcx, **self) + } +} + +impl Repr for ty::TypeParameterDef { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("TypeParameterDef {%?, bounds: %s}", + self.def_id, self.bounds.repr(tcx)) + } +} + +impl Repr for ty::t { + fn repr(&self, tcx: ctxt) -> ~str { + ty_to_str(tcx, *self) + } +} + +impl Repr for ty::substs { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("substs(self_r=%s, self_ty=%s, tps=%s)", + self.self_r.repr(tcx), + self.self_ty.repr(tcx), + self.tps.repr(tcx)) + } +} + +impl Repr for ty::param_bound { + fn repr(&self, tcx: ctxt) -> ~str { + match *self { + ty::bound_copy => ~"copy", + ty::bound_durable => ~"'static", + ty::bound_owned => ~"owned", + ty::bound_const => ~"const", + ty::bound_trait(ref t) => t.repr(tcx) + } + } +} + +impl Repr for ty::TraitRef { + fn repr(&self, tcx: ctxt) -> ~str { + trait_ref_to_str(tcx, self) + } +} + +impl Repr for @ast::expr { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("expr(%d: %s)", + self.id, + pprust::expr_to_str(*self, tcx.sess.intr())) + } +} + +impl Repr for @ast::pat { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("pat(%d: %s)", + self.id, + pprust::pat_to_str(*self, tcx.sess.intr())) + } +} + +impl Repr for ty::Region { + fn repr(&self, tcx: ctxt) -> ~str { + region_to_str(tcx, *self) + } +} + +impl Repr for ast::def_id { + fn repr(&self, tcx: ctxt) -> ~str { + // Unfortunately, there seems to be no way to attempt to print + // a path for a def-id, so I'll just make a best effort for now + // and otherwise fallback to just printing the crate/node pair + if self.crate == ast::local_crate { + match tcx.items.find(&self.node) { + Some(&ast_map::node_item(*)) | + Some(&ast_map::node_foreign_item(*)) | + Some(&ast_map::node_method(*)) | + Some(&ast_map::node_trait_method(*)) | + Some(&ast_map::node_variant(*)) | + Some(&ast_map::node_struct_ctor(*)) => { + return fmt!("%?:%s", *self, ty::item_path_str(tcx, *self)); + } + _ => {} + } + } + return fmt!("%?", *self); + } +} + +impl Repr for ty::ty_param_bounds_and_ty { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("ty_param_bounds_and_ty {generics: %s, ty: %s}", + self.generics.repr(tcx), + self.ty.repr(tcx)) + } +} + +impl Repr for ty::Generics { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("Generics {type_param_defs: %s, region_param: %?}", + self.type_param_defs.repr(tcx), + self.region_param) + } +} + +impl Repr for ty::method { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("method {ident: %s, generics: %s, transformed_self_ty: %s, \ + fty: %s, self_ty: %s, vis: %s, def_id: %s}", + self.ident.repr(tcx), + self.generics.repr(tcx), + self.transformed_self_ty.repr(tcx), + self.fty.repr(tcx), + self.self_ty.repr(tcx), + self.vis.repr(tcx), + self.def_id.repr(tcx)) + } +} + +impl Repr for ast::ident { + fn repr(&self, tcx: ctxt) -> ~str { + copy *tcx.sess.intr().get(*self) + } +} + +impl Repr for ast::self_ty_ { + fn repr(&self, _tcx: ctxt) -> ~str { + fmt!("%?", *self) + } +} + +impl Repr for ast::visibility { + fn repr(&self, _tcx: ctxt) -> ~str { + fmt!("%?", *self) + } +} + +impl Repr for ty::BareFnTy { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("BareFnTy {purity: %?, abis: %s, sig: %s}", + self.purity, + self.abis.to_str(), + self.sig.repr(tcx)) + } +} + +impl Repr for ty::FnSig { + fn repr(&self, tcx: ctxt) -> ~str { + fn_sig_to_str(tcx, self) + } +} + +impl Repr for typeck::method_map_entry { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("method_map_entry {self_arg: %s, \ + explicit_self: %s, \ + origin: %s}", + self.self_arg.repr(tcx), + self.explicit_self.repr(tcx), + self.origin.repr(tcx)) + } +} + +impl Repr for ty::arg { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("%?(%s)", self.mode, self.ty.repr(tcx)) + } +} + +impl Repr for typeck::method_origin { + fn repr(&self, tcx: ctxt) -> ~str { + match self { + &typeck::method_super(def_id, n) => { + fmt!("method_super(%s, %?)", + def_id.repr(tcx), n) + } + &typeck::method_static(def_id) => { + fmt!("method_static(%s)", def_id.repr(tcx)) + } + &typeck::method_param(ref p) => { + p.repr(tcx) + } + &typeck::method_trait(def_id, n, st) => { + fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n, + st.repr(tcx)) + } + &typeck::method_self(def_id, n) => { + fmt!("method_self(%s, %?)", def_id.repr(tcx), n) + } + } + } +} + +impl Repr for typeck::method_param { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("method_param(%s,%?,%?,%?)", + self.trait_id.repr(tcx), + self.method_num, + self.param_num, + self.bound_num) + } +} + +impl Repr for ty::TraitStore { + fn repr(&self, tcx: ctxt) -> ~str { + match self { + &ty::BoxTraitStore => ~"@Trait", + &ty::UniqTraitStore => ~"~Trait", + &ty::RegionTraitStore(r) => fmt!("&%s Trait", r.repr(tcx)) + } + } +} + // Local Variables: // mode: rust // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix -// End: +// End diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 67c3d19dd0fb7..fd54746f3dc51 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -102,6 +102,16 @@ impl OptVec { self.push(copy *e); } } + + #[inline(always)] + fn mapi_to_vec(&self, op: &fn(uint, &T) -> B) -> ~[B] { + let mut index = 0; + iter::map_to_vec(self, |a| { + let i = index; + index += 1; + op(i, a) + }) + } } impl Eq for OptVec { diff --git a/src/test/run-pass/trait-inheritance-self-in-supertype.rs b/src/test/run-pass/trait-inheritance-self-in-supertype.rs new file mode 100644 index 0000000000000..8105cf23d8004 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-self-in-supertype.rs @@ -0,0 +1,61 @@ +// Test for issue #4183: use of Self in supertraits. + +pub static FUZZY_EPSILON: float = 0.1; + +pub trait FuzzyEq { + fn fuzzy_eq(&self, other: &Self) -> bool; + fn fuzzy_eq_eps(&self, other: &Self, epsilon: &Eps) -> bool; +} + +trait Float: FuzzyEq { + fn two_pi() -> Self; +} + +impl FuzzyEq for f32 { + fn fuzzy_eq(&self, other: &f32) -> bool { + self.fuzzy_eq_eps(other, &(FUZZY_EPSILON as f32)) + } + + fn fuzzy_eq_eps(&self, other: &f32, epsilon: &f32) -> bool { + f32::abs(*self - *other) < *epsilon + } +} + +impl Float for f32 { + fn two_pi() -> f32 { 6.28318530717958647692528676655900576_f32 } +} + +impl FuzzyEq for f64 { + fn fuzzy_eq(&self, other: &f64) -> bool { + self.fuzzy_eq_eps(other, &(FUZZY_EPSILON as f64)) + } + + fn fuzzy_eq_eps(&self, other: &f64, epsilon: &f64) -> bool { + f64::abs(*self - *other) < *epsilon + } +} + +impl Float for f64 { + fn two_pi() -> f64 { 6.28318530717958647692528676655900576_f64 } +} + +fn compare(f1: F) -> bool { + let f2 = Float::two_pi(); + f1.fuzzy_eq(&f2) +} + +pub fn main() { + assert!(compare::(6.28318530717958647692528676655900576)); + assert!(compare::(6.29)); + assert!(compare::(6.3)); + assert!(compare::(6.19)); + assert!(!compare::(7.28318530717958647692528676655900576)); + assert!(!compare::(6.18)); + + assert!(compare::(6.28318530717958647692528676655900576)); + assert!(compare::(6.29)); + assert!(compare::(6.3)); + assert!(compare::(6.19)); + assert!(!compare::(7.28318530717958647692528676655900576)); + assert!(!compare::(6.18)); +} \ No newline at end of file