auto merge of #5802 : nikomatsakis/rust/issue-4183-trait-substs, r=nikomatsakis

Cleanup substitutions and treatment of generics around traits in a number of ways

- In a TraitRef, use the self type consistently to refer to the Self type:
  - trait ref in `impl Trait<A,B,C> for S` has a self type of `S`.
  - trait ref in `A:Trait` has the self type `A`
  - trait ref associated with a trait decl has self type `Self`
  - trait ref associated with a supertype has self type `Self`
  - trait ref in an object type `@Trait` has no self type

- Rewrite `each_bound_traits_and_supertraits` to perform
  substitutions as it goes, and thus yield a series of trait refs
  that are always in the same 'namespace' as the type parameter
  bound given as input.  Before, we left this to the caller, but
  this doesn't work because the caller lacks adequare information
  to perform the type substitutions correctly.

- For provided methods, substitute the generics involved in the provided
  method correctly.

- Introduce TypeParameterDef, which tracks the bounds declared on a type
  parameter and brings them together with the def_id and (in the future)
  other information (maybe even the parameter's name!).

- Introduce Subst trait, which helps to cleanup a lot of the
  repetitive code involved with doing type substitution.

- Introduce Repr trait, which makes debug printouts far more convenient.

Fixes #4183.  Needed for #5656.

r? @catamorphism
This commit is contained in:
bors 2013-04-09 17:12:58 -07:00
commit 92e265cdea
32 changed files with 1258 additions and 625 deletions

View File

@ -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,

View File

@ -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
}

View File

@ -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,

View File

@ -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<TyParam>) {
let ty_param_bounds =
@params.map_to_vec(|param| *ecx.tcx.ty_param_bounds.get(&param.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(&param.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);
}

View File

@ -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] {

View File

@ -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

View File

@ -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())

View File

@ -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 {

View File

@ -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<Context>) {
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<Context>) {
// 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<Context>) {
// 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 */

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T:Subst> Subst for ~[T] {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ~[T] {
self.map(|t| t.subst(tcx, substs))
}
}
impl<T:Subst> Subst for @~[T] {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @~[T] {
@(**self).subst(tcx, substs)
}
}
impl<T:Subst> Subst for Option<T> {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> Option<T> {
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)
}
}
}

View File

@ -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, &param_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);

View File

@ -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();

View File

@ -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<typeck::vtable_res>,
bounds: @~[ty::param_bounds],
type_param_defs: @~[ty::TypeParameterDef],
self_ty: Option<ty::t>
}
@ -261,16 +261,25 @@ pub impl param_substs {
}
}
pub fn param_substs_to_str(tcx: ty::ctxt, substs: &param_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: &param_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: &param_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]
}

View File

@ -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

View File

@ -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),

View File

@ -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()))

View File

@ -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<typeck::vtable_res>,
impl_did_opt: Option<ast::def_id>,
ref_id: Option<ast::node_id>) ->
(ValueRef, bool) {
ref_id: Option<ast::node_id>)
-> (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<typeck::vtable_res>,
impl_did_opt: Option<ast::def_id>,
+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]));

View File

@ -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<uint, TypeContents>,
ast_ty_to_ty_cache: @mut HashMap<node_id, ast_ty_to_ty_cache_entry>,
enum_var_cache: @mut HashMap<def_id, @~[VariantInfo]>,
ty_param_bounds: @mut HashMap<ast::node_id, param_bounds>,
ty_param_defs: @mut HashMap<ast::node_id, TypeParameterDef>,
inferred_modes: @mut HashMap<ast::node_id, ast::mode>,
adjustments: @mut HashMap<ast::node_id, @AutoAdjustment>,
normalized_cache: @mut HashMap<t, t>,
@ -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<region_variance>,
}
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: &param_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<V:Copy>(
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);
while i < trait_refs.len() {
debug!("each_bound_trait_and_supertraits(i=%?, trait_ref=%s)",
i, trait_refs[i].repr(tcx));
if f(trait_ref) {
// Add all the supertraits to the hash map,
// executing <f> on each of them
while i < supertrait_set.len() && !fin {
let init_trait_id = seen_def_ids[i];
i += 1;
if !f(trait_refs[i]) {
return;
}
// 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;
}
// 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;
}
}

View File

@ -135,6 +135,7 @@ fn ast_path_substs<AC:AstConv,RS:region_scope + Copy + Durable>(
rscope: &RS,
def_id: ast::def_id,
decl_generics: &ty::Generics,
self_ty: Option<ty::t>,
path: @ast::path) -> ty::substs
{
/*!
@ -172,15 +173,15 @@ fn ast_path_substs<AC:AstConv,RS:region_scope + Copy + Durable>(
};
// 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<AC:AstConv,RS:region_scope + Copy + Durable>(
@ -195,7 +196,7 @@ pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
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<AC:AstConv,RS:region_scope + Copy + Durable>(
self: &AC,
rscope: &RS,
trait_def_id: ast::def_id,
self_ty: Option<ty::t>,
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<AC:AstConv, RS:region_scope + Copy + Durable>(
}
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,

View File

@ -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 {

View File

@ -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(&param_ty.def_id.node);
for bounds.each |bound| {
let bound_trait_ref = match *bound {
ty::bound_trait(bound_t) => bound_t,
ty::bound_copy | ty::bound_owned |
ty::bound_const | ty::bound_durable => {
loop; // skip non-trait bounds
}
};
// 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 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,
})
};
debug!("pushing inherent candidate for param: %?", cand);
self.inherent_candidates.push(cand);
let type_param_def = match tcx.ty_param_defs.find(&param_ty.def_id.node) {
Some(t) => t,
None => {
tcx.sess.span_bug(
self.expr.span,
fmt!("No param def for %?", param_ty));
}
};
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];
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: 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);
}
}
@ -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");

View File

@ -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, \

View File

@ -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.
let new_substs = substs {
self_ty: Some(*ty),
../*bad*/copy *substs
};
let trait_ref = ty::subst_in_trait_ref(tcx, &new_substs, trait_ref);
debug!("about to subst: %s, %s", trait_ref.repr(tcx), substs.repr(tcx));
debug!("after subst: %?",
vcx.infcx.trait_ref_to_str(&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: %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,

View File

@ -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()));
}
}

View File

@ -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));
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_did);
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);

View File

@ -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<A,B,C> {
// fn foo<D,E,F>(...) -> Self;
// }
//
// and we will create a function like
//
// fn foo<A',B',C',D',E',F',G'>(...) -> D' {}
//
// Note that `Self` is replaced with an explicit type
// parameter D' that is sandwiched in between the trait params
// 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)
};
let self_param = ty::mk_param(ccx.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)
ty::mk_param(tcx, i, dummy_defid)
};
// Represents [D']
let self_param = ty::mk_param(tcx, num_trait_bounds,
dummy_defid);
// Represents [E',F',G']
let num_method_bounds = m.generics.type_param_defs.len();
let shifted_method_tps = 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<ty::region_variance>,
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<ty::region_variance>,
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<ty::region_variance>,
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(&param.id) {
Some(&bs) => bs,
type_param_defs: @generics.ty_params.mapi_to_vec(|offset, param| {
match ccx.tcx.ty_param_defs.find(&param.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<ty::region_variance>,
generics: &ast::Generics,
param_ty: ty::param_ty,
ast_bounds: @OptVec<ast::TyParamBound>) -> 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::region_variance>) -> (ty::Generics, ty::substs)
pub fn mk_item_substs(ccx: &CrateCtxt,
ast_generics: &ast::Generics,
rp: Option<ty::region_variance>,
self_ty: Option<ty::t>) -> (ty::Generics, ty::substs)
{
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})
}

View File

@ -274,15 +274,14 @@ pub fn super_tps<C:Combine>(
pub fn super_self_tys<C:Combine>(
self: &C, a: Option<ty::t>, b: Option<ty::t>) -> cres<Option<ty::t>> {
// 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) => {

View File

@ -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
}

View File

@ -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;

View File

@ -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<T:Repr> Repr for Option<T> {
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<T:Repr> Repr for @T {
fn repr(&self, tcx: ctxt) -> ~str {
(&**self).repr(tcx)
}
}
impl<T:Repr> Repr for ~T {
fn repr(&self, tcx: ctxt) -> ~str {
(&**self).repr(tcx)
}
}
*/
fn repr_vec<T:Repr>(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<T:Repr> 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

View File

@ -102,6 +102,16 @@ impl<T:Copy> OptVec<T> {
self.push(copy *e);
}
}
#[inline(always)]
fn mapi_to_vec<B>(&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<A:Eq> Eq for OptVec<A> {

View File

@ -0,0 +1,61 @@
// Test for issue #4183: use of Self in supertraits.
pub static FUZZY_EPSILON: float = 0.1;
pub trait FuzzyEq<Eps> {
fn fuzzy_eq(&self, other: &Self) -> bool;
fn fuzzy_eq_eps(&self, other: &Self, epsilon: &Eps) -> bool;
}
trait Float: FuzzyEq<Self> {
fn two_pi() -> Self;
}
impl FuzzyEq<f32> 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<f64> 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<F:Float>(f1: F) -> bool {
let f2 = Float::two_pi();
f1.fuzzy_eq(&f2)
}
pub fn main() {
assert!(compare::<f32>(6.28318530717958647692528676655900576));
assert!(compare::<f32>(6.29));
assert!(compare::<f32>(6.3));
assert!(compare::<f32>(6.19));
assert!(!compare::<f32>(7.28318530717958647692528676655900576));
assert!(!compare::<f32>(6.18));
assert!(compare::<f64>(6.28318530717958647692528676655900576));
assert!(compare::<f64>(6.29));
assert!(compare::<f64>(6.3));
assert!(compare::<f64>(6.19));
assert!(!compare::<f64>(7.28318530717958647692528676655900576));
assert!(!compare::<f64>(6.18));
}