Refactor representation of bounds to separate out BuiltinBounds into

its own type. Use a bitset to represent built-in bounds. There
are several places in the language where only builtin bounds (aka kinds)
will be accepted, e.g. on closures, destructor type parameters perhaps,
and on trait types.
This commit is contained in:
Niko Matsakis 2013-05-07 17:30:21 -04:00
parent ca95e7f94e
commit dc2ca9d883
14 changed files with 370 additions and 213 deletions

View File

@ -555,18 +555,34 @@ fn parse_type_param_def(st: @mut PState, conv: conv_did) -> ty::TypeParameterDef
bounds: parse_bounds(st, conv)}
}
fn parse_bounds(st: @mut PState, conv: conv_did) -> @~[ty::param_bound] {
let mut bounds = ~[];
fn parse_bounds(st: @mut PState, conv: conv_did) -> @ty::ParamBounds {
let mut param_bounds = ty::ParamBounds {
builtin_bounds: ty::EmptyBuiltinBounds(),
trait_bounds: ~[]
};
loop {
bounds.push(match next(st) {
'S' => ty::bound_owned,
'C' => ty::bound_copy,
'K' => ty::bound_const,
'O' => ty::bound_durable,
'I' => ty::bound_trait(@parse_trait_ref(st, conv)),
'.' => break,
_ => fail!(~"parse_bounds: bad bounds")
});
match next(st) {
'S' => {
param_bounds.builtin_bounds.add(ty::BoundOwned);
}
'C' => {
param_bounds.builtin_bounds.add(ty::BoundCopy);
}
'K' => {
param_bounds.builtin_bounds.add(ty::BoundConst);
}
'O' => {
param_bounds.builtin_bounds.add(ty::BoundStatic);
}
'I' => {
param_bounds.trait_bounds.push(@parse_trait_ref(st, conv));
}
'.' => {
return @param_bounds;
}
_ => {
fail!(~"parse_bounds: bad bounds")
}
}
}
@bounds
}

View File

@ -396,19 +396,21 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) {
enc_ty(w, cx, fsig.output);
}
fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @~[ty::param_bound]) {
for (*bs).each |bound| {
match *bound {
ty::bound_owned => w.write_char('S'),
ty::bound_copy => w.write_char('C'),
ty::bound_const => w.write_char('K'),
ty::bound_durable => w.write_char('O'),
ty::bound_trait(tp) => {
w.write_char('I');
enc_trait_ref(w, cx, tp);
}
fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @ty::ParamBounds) {
for bs.builtin_bounds.each |bound| {
match bound {
ty::BoundOwned => w.write_char('S'),
ty::BoundCopy => w.write_char('C'),
ty::BoundConst => w.write_char('K'),
ty::BoundStatic => w.write_char('O'),
}
}
for bs.trait_bounds.each |&tp| {
w.write_char('I');
enc_trait_ref(w, cx, tp);
}
w.write_char('.');
}

View File

@ -14,6 +14,7 @@ use middle::pat_util;
use middle::ty;
use middle::typeck;
use util::ppaux::{Repr, ty_to_str};
use util::ppaux::UserString;
use syntax::ast::*;
use syntax::attr::attrs_contains_name;
@ -338,46 +339,19 @@ pub fn check_bounds(cx: Context,
type_param_def: &ty::TypeParameterDef)
{
let kind = ty::type_contents(cx.tcx, ty);
let mut missing = ~[];
for type_param_def.bounds.each |bound| {
match *bound {
ty::bound_trait(_) => {
/* Not our job, checking in typeck */
}
ty::bound_copy => {
if !kind.is_copy(cx.tcx) {
missing.push("Copy");
}
}
ty::bound_durable => {
if !kind.is_durable(cx.tcx) {
missing.push("'static");
}
}
ty::bound_owned => {
if !kind.is_owned(cx.tcx) {
missing.push("Owned");
}
}
ty::bound_const => {
if !kind.is_const(cx.tcx) {
missing.push("Const");
}
}
let mut missing = ty::EmptyBuiltinBounds();
for type_param_def.bounds.builtin_bounds.each |bound| {
if !kind.meets_bound(cx.tcx, bound) {
missing.add(bound);
}
}
if !missing.is_empty() {
cx.tcx.sess.span_err(
sp,
fmt!("instantiating a type parameter with an incompatible type \
`%s`, which does not fulfill `%s`",
ty_to_str(cx.tcx, ty),
str::connect_slices(missing, " ")));
missing.user_string(cx.tcx)));
}
}
@ -440,7 +414,7 @@ pub fn check_owned(cx: Context, ty: ty::t, sp: span) -> bool {
// note: also used from middle::typeck::regionck!
pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool {
if !ty::type_is_durable(tcx, ty) {
if !ty::type_is_static(tcx, ty) {
match ty::get(ty).sty {
ty::ty_param(*) => {
tcx.sess.span_err(sp, "value may contain borrowed \

View File

@ -78,9 +78,11 @@ impl<T:Subst> Subst for ~[T] {
}
}
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 @T {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @T {
match self {
&@ref t => @t.subst(tcx, substs)
}
}
}
@ -115,19 +117,11 @@ impl Subst for ty::BareFnTy {
}
}
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::ParamBounds {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::ParamBounds {
ty::ParamBounds {
builtin_bounds: self.builtin_bounds,
trait_bounds: self.trait_bounds.subst(tcx, substs)
}
}
}

View File

@ -348,14 +348,9 @@ pub fn make_mono_id(ccx: @CrateContext,
let mut i = 0;
vec::map_zip(*item_ty.generics.type_param_defs, substs, |type_param_def, subst| {
let mut v = ~[];
for type_param_def.bounds.each |bound| {
match *bound {
ty::bound_trait(_) => {
v.push(meth::vtable_id(ccx, /*bad*/copy vts[i]));
i += 1;
}
_ => ()
}
for type_param_def.bounds.trait_bounds.each |_bound| {
v.push(meth::vtable_id(ccx, /*bad*/copy vts[i]));
i += 1;
}
(*subst, if !v.is_empty() { Some(v) } else { None })
})

View File

@ -26,6 +26,7 @@ use util::ppaux::{note_and_explain_region, bound_region_to_str};
use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
use util::ppaux::Repr;
use util::common::{indenter};
use util::enum_set::{EnumSet, CLike};
use core;
use core::ptr::to_unsafe_ptr;
@ -58,8 +59,6 @@ pub struct field {
mt: mt
}
pub type param_bounds = @~[param_bound];
pub struct method {
ident: ast::ident,
generics: ty::Generics,
@ -655,12 +654,32 @@ pub enum type_err {
}
#[deriving(Eq, IterBytes)]
pub enum param_bound {
bound_copy,
bound_durable,
bound_owned,
bound_const,
bound_trait(@TraitRef),
pub struct ParamBounds {
builtin_bounds: BuiltinBounds,
trait_bounds: ~[@TraitRef]
}
pub type BuiltinBounds = EnumSet<BuiltinBound>;
#[deriving(Eq, IterBytes)]
pub enum BuiltinBound {
BoundCopy,
BoundStatic,
BoundOwned,
BoundConst,
}
pub fn EmptyBuiltinBounds() -> BuiltinBounds {
EnumSet::empty()
}
impl CLike for BuiltinBound {
pub fn to_uint(&self) -> uint {
*self as uint
}
pub fn from_uint(v: uint) -> BuiltinBound {
unsafe { cast::transmute(v) }
}
}
#[deriving(Eq)]
@ -817,7 +836,7 @@ impl to_bytes::IterBytes for RegionVid {
pub struct TypeParameterDef {
def_id: ast::def_id,
bounds: param_bounds
bounds: @ParamBounds
}
/// Information about the type/lifetime parametesr associated with an item.
@ -1497,14 +1516,6 @@ pub fn substs_to_str(cx: ctxt, substs: &substs) -> ~str {
substs.repr(cx)
}
pub fn param_bound_to_str(cx: ctxt, pb: &param_bound) -> ~str {
pb.repr(cx)
}
pub fn param_bounds_to_str(cx: ctxt, pbs: param_bounds) -> ~str {
pbs.repr(cx)
}
pub fn subst(cx: ctxt,
substs: &substs,
typ: t)
@ -1795,6 +1806,19 @@ pub struct TypeContents {
}
pub impl TypeContents {
fn meets_bounds(&self, cx: ctxt, bbs: BuiltinBounds) -> bool {
iter::all(|bb| self.meets_bound(cx, bb), |f| bbs.each(f))
}
fn meets_bound(&self, cx: ctxt, bb: BuiltinBound) -> bool {
match bb {
BoundCopy => self.is_copy(cx),
BoundStatic => self.is_static(cx),
BoundConst => self.is_const(cx),
BoundOwned => self.is_owned(cx)
}
}
fn intersects(&self, tc: TypeContents) -> bool {
(self.bits & tc.bits) != 0
}
@ -1808,11 +1832,11 @@ pub impl TypeContents {
TC_EMPTY_ENUM
}
fn is_durable(&self, cx: ctxt) -> bool {
!self.intersects(TypeContents::nondurable(cx))
fn is_static(&self, cx: ctxt) -> bool {
!self.intersects(TypeContents::nonstatic(cx))
}
fn nondurable(_cx: ctxt) -> TypeContents {
fn nonstatic(_cx: ctxt) -> TypeContents {
TC_BORROWED_POINTER
}
@ -1917,8 +1941,8 @@ pub fn type_is_copyable(cx: ctxt, t: ty::t) -> bool {
type_contents(cx, t).is_copy(cx)
}
pub fn type_is_durable(cx: ctxt, t: ty::t) -> bool {
type_contents(cx, t).is_durable(cx)
pub fn type_is_static(cx: ctxt, t: ty::t) -> bool {
type_contents(cx, t).is_static(cx)
}
pub fn type_is_owned(cx: ctxt, t: ty::t) -> bool {
@ -2198,19 +2222,19 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
debug!("type_param_def_to_contents(%s)", type_param_def.repr(cx));
let _i = indenter();
let r = type_param_def.bounds.foldl(TC_ALL, |tc, bound| {
let mut tc = TC_ALL;
for type_param_def.bounds.builtin_bounds.each |bound| {
debug!("tc = %s, bound = %?", tc.to_str(), bound);
match *bound {
bound_copy => tc - TypeContents::nonimplicitly_copyable(cx),
bound_durable => tc - TypeContents::nondurable(cx),
bound_owned => tc - TypeContents::nonowned(cx),
bound_const => tc - TypeContents::nonconst(cx),
bound_trait(_) => *tc
}
});
tc = tc - match bound {
BoundCopy => TypeContents::nonimplicitly_copyable(cx),
BoundStatic => TypeContents::nonstatic(cx),
BoundOwned => TypeContents::nonowned(cx),
BoundConst => TypeContents::nonconst(cx),
};
}
debug!("result = %s", r.to_str());
return r;
debug!("result = %s", tc.to_str());
return tc;
}
}
@ -3577,7 +3601,7 @@ pub fn trait_supertraits(cx: ctxt,
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))
|supertrait_ref| supertrait_ref.subst(cx, &trait_ref.substs))
}
fn lookup_locally_or_in_crate_store<V:Copy>(
@ -4261,18 +4285,9 @@ pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id),
// relation on the supertraits from each bounded trait's constraint
// list.
pub fn each_bound_trait_and_supertraits(tcx: ctxt,
bounds: param_bounds,
f: &fn(&TraitRef) -> bool) {
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
}
};
bounds: &ParamBounds,
f: &fn(@TraitRef) -> bool) {
for bounds.trait_bounds.each |&bound_trait_ref| {
let mut supertrait_set = HashMap::new();
let mut trait_refs = ~[];
let mut i = 0;

View File

@ -67,8 +67,7 @@ pub impl VtableContext {
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 }))
|type_param_def| !type_param_def.bounds.trait_bounds.is_empty())
}
fn lookup_vtables(vcx: &VtableContext,
@ -99,7 +98,7 @@ fn lookup_vtables(vcx: &VtableContext,
// Substitute the values of the type parameters that may
// appear in the bound.
let trait_ref = trait_ref.subst(tcx, substs);
let trait_ref = (*trait_ref).subst(tcx, substs);
debug!("after subst: %s", trait_ref.repr(tcx));
@ -339,7 +338,8 @@ 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 = of_trait_ref.subst(tcx, &substs);
let of_trait_ref =
(*of_trait_ref).subst(tcx, &substs);
relate_trait_refs(
vcx, location_info,
&of_trait_ref, trait_ref);
@ -458,7 +458,7 @@ 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 = impl_trait_ref.subst(tcx, impl_substs);
let impl_trait_ref = (*impl_trait_ref).subst(tcx, impl_substs);
relate_trait_refs(vcx, location_info, &impl_trait_ref, trait_ref);
}

View File

@ -22,7 +22,7 @@ use metadata::csearch;
use metadata::cstore::{CStore, iter_crate_data};
use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::resolve::{Impl, MethodInfo};
use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, bound_copy, get};
use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, get};
use middle::ty::{lookup_item_type, subst};
use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err};
use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil};
@ -603,34 +603,28 @@ 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.type_param_defs)
|ty_var, type_param_def| {
match resolve_type(self.inference_context,
*ty_var,
resolve_nested_tvar) {
Ok(resolved_ty) => {
for type_param_def.bounds.each |bound| {
match *bound {
bound_copy => {
if !ty::type_is_copyable(
self.inference_context.tcx,
resolved_ty)
{
might_unify = false;
break;
}
}
// XXX: We could be smarter here.
// Check to see whether owned, send,
// const, trait param bounds could
// possibly unify.
_ => {}
for vec::each2(result.type_variables,
*result.type_param_defs)
|ty_var, type_param_def|
{
if type_param_def.bounds.builtin_bounds.contains_elem(
ty::BoundCopy)
{
match resolve_type(self.inference_context,
*ty_var,
resolve_nested_tvar) {
Ok(resolved_ty) => {
if !ty::type_is_copyable(
self.inference_context.tcx,
resolved_ty)
{
might_unify = false;
break;
}
}
}
Err(*) => {
// Conservatively assume it might unify.
Err(*) => {
// Conservatively assume it might unify.
}
}
}
}

View File

@ -41,8 +41,9 @@ use middle::typeck::infer;
use middle::typeck::rscope::*;
use middle::typeck::rscope;
use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
use util::common::{indenter, pluralize};
use util::common::pluralize;
use util::ppaux;
use util::ppaux::UserString;
use syntax::abi::AbiSet;
use syntax::ast::{RegionTyParamBound, TraitTyParamBound};
@ -341,10 +342,13 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
// 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);
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)]
bounds: @ty::ParamBounds {
builtin_bounds: ty::EmptyBuiltinBounds(),
trait_bounds: ~[self_trait_ref]
}
});
// add in the type parameters from the method
@ -444,7 +448,7 @@ pub fn compare_impl_method(tcx: ty::ctxt,
trait_substs: &ty::substs,
self_ty: ty::t) {
debug!("compare_impl_method()");
let _indenter = indenter();
let infcx = infer::new_infer_ctxt(tcx);
let impl_m = &cm.mty;
@ -507,28 +511,50 @@ pub fn compare_impl_method(tcx: ty::ctxt,
return;
}
// 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.type_param_defs.eachi |i, trait_param_def| {
// For each of the corresponding impl ty param's bounds...
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_def.bounds.len() != trait_param_def.bounds.len() {
// Check that the impl does not require any builtin-bounds
// that the trait does not guarantee:
let extra_bounds =
impl_param_def.bounds.builtin_bounds -
trait_param_def.bounds.builtin_bounds;
if !extra_bounds.is_empty() {
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",
type parameter %u requires `%s`, \
which is not required by \
the corresponding type parameter \
in the trait declaration",
*tcx.sess.str_of(trait_m.ident),
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")));
i,
extra_bounds.user_string(tcx)));
return;
}
// 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.
if impl_param_def.bounds.trait_bounds.len() !=
trait_param_def.bounds.trait_bounds.len()
{
tcx.sess.span_err(
cm.span,
fmt!("in method `%s`, \
type parameter %u has %u trait %s, but the \
corresponding type parameter in \
the trait declaration has %u trait %s",
*tcx.sess.str_of(trait_m.ident),
i, impl_param_def.bounds.trait_bounds.len(),
pluralize(impl_param_def.bounds.trait_bounds.len(),
~"bound"),
trait_param_def.bounds.trait_bounds.len(),
pluralize(trait_param_def.bounds.trait_bounds.len(),
~"bound")));
return;
}
}
// Replace any references to the self region in the self type with
@ -619,7 +645,6 @@ pub fn compare_impl_method(tcx: ty::ctxt,
};
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) {
result::Ok(()) => {}
result::Err(ref terr) => {
@ -1152,8 +1177,8 @@ pub fn ty_generics(ccx: &CrateCtxt,
None => {
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 bounds = @compute_bounds(ccx, rp, generics,
param_ty, param.bounds);
let def = ty::TypeParameterDef {
def_id: local_def(param.id),
bounds: bounds
@ -1171,7 +1196,7 @@ pub fn ty_generics(ccx: &CrateCtxt,
rp: Option<ty::region_variance>,
generics: &ast::Generics,
param_ty: ty::param_ty,
ast_bounds: @OptVec<ast::TyParamBound>) -> ty::param_bounds
ast_bounds: @OptVec<ast::TyParamBound>) -> ty::ParamBounds
{
/*!
*
@ -1182,29 +1207,35 @@ pub fn ty_generics(ccx: &CrateCtxt,
* as kinds): Const, Copy, and Send.
*/
@ast_bounds.flat_map_to_vec(|b| {
let mut param_bounds = ty::ParamBounds {
builtin_bounds: ty::EmptyBuiltinBounds(),
trait_bounds: ~[]
};
for ast_bounds.each |b| {
match b {
&TraitTyParamBound(b) => {
let li = &ccx.tcx.lang_items;
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]
param_bounds.builtin_bounds.add(ty::BoundOwned);
} else if trait_ref.def_id == li.copy_trait() {
~[ty::bound_copy]
param_bounds.builtin_bounds.add(ty::BoundCopy);
} else if trait_ref.def_id == li.const_trait() {
~[ty::bound_const]
param_bounds.builtin_bounds.add(ty::BoundConst);
} else {
// Must be a user-defined trait
~[ty::bound_trait(trait_ref)]
param_bounds.trait_bounds.push(trait_ref);
}
}
&RegionTyParamBound => {
~[ty::bound_durable]
param_bounds.builtin_bounds.add(ty::BoundStatic);
}
}
})
}
param_bounds
}
}

View File

@ -131,6 +131,7 @@ pub mod driver;
pub mod util {
pub mod common;
pub mod ppaux;
pub mod enum_set;
}
pub mod lib {

View File

@ -0,0 +1,88 @@
// 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.
use core;
#[deriving(Eq, IterBytes)]
pub struct EnumSet<E> {
bits: uint
}
pub trait CLike {
pub fn to_uint(&self) -> uint;
pub fn from_uint(uint) -> Self;
}
fn bit<E:CLike>(e: E) -> uint {
1 << e.to_uint()
}
pub impl<E:CLike> EnumSet<E> {
fn empty() -> EnumSet<E> {
EnumSet {bits: 0}
}
fn is_empty(&self) -> bool {
self.bits == 0
}
fn intersects(&self, e: EnumSet<E>) -> bool {
(self.bits & e.bits) != 0
}
fn contains(&self, e: EnumSet<E>) -> bool {
(self.bits & e.bits) == e.bits
}
fn add(&mut self, e: E) {
self.bits |= bit(e);
}
fn plus(&self, e: E) -> EnumSet<E> {
EnumSet {bits: self.bits | bit(e)}
}
fn contains_elem(&self, e: E) -> bool {
(self.bits & bit(e)) != 0
}
fn each(&self, f: &fn(E) -> bool) {
let mut bits = self.bits;
let mut index = 0;
while bits != 0 {
if (bits & 1) != 0 {
let e = CLike::from_uint(index);
if !f(e) {
return;
}
}
index += 1;
bits >>= 1;
}
}
}
impl<E:CLike> core::Sub<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
fn sub(&self, e: &EnumSet<E>) -> EnumSet<E> {
EnumSet {bits: self.bits & !e.bits}
}
}
impl<E:CLike> core::BitOr<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
fn bitor(&self, e: &EnumSet<E>) -> EnumSet<E> {
EnumSet {bits: self.bits | e.bits}
}
}
impl<E:CLike> core::BitAnd<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
fn bitand(&self, e: &EnumSet<E>) -> EnumSet<E> {
EnumSet {bits: self.bits & e.bits}
}
}

View File

@ -12,7 +12,7 @@ use metadata::encoder;
use middle::ty::{ReSkolemized, ReVar};
use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid};
use middle::ty::{br_fresh, ctxt, field, method};
use middle::ty::{mt, t, param_bound, param_ty};
use middle::ty::{mt, t, param_ty};
use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region,
re_empty};
use middle::ty::{ty_bool, ty_bot, ty_box, ty_struct, ty_enum};
@ -29,10 +29,16 @@ use syntax::codemap::span;
use syntax::print::pprust;
use syntax::{ast, ast_util};
/// Produces a string suitable for debugging output.
pub trait Repr {
fn repr(&self, tcx: ctxt) -> ~str;
}
/// Produces a string suitable for showing to the user.
pub trait UserString {
fn user_string(&self, tcx: ctxt) -> ~str;
}
pub fn note_and_explain_region(cx: ctxt,
prefix: &str,
region: ty::Region,
@ -273,10 +279,6 @@ pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str {
fmt!("(%s)", str::connect(tstrs, ", "))
}
pub fn bound_to_str(cx: ctxt, b: param_bound) -> ~str {
ty::param_bound_to_str(cx, &b)
}
pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str {
fmt!("fn%s -> %s",
tys_to_str(cx, typ.inputs.map(|a| a.ty)),
@ -284,15 +286,7 @@ 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());
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)
}
trait_ref.user_string(cx)
}
pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
@ -555,15 +549,21 @@ impl Repr for ty::substs {
}
}
impl Repr for ty::param_bound {
impl Repr for ty::ParamBounds {
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)
let mut res = ~[];
for self.builtin_bounds.each |b| {
res.push(match b {
ty::BoundCopy => ~"Copy",
ty::BoundStatic => ~"'static",
ty::BoundOwned => ~"Owned",
ty::BoundConst => ~"Const",
});
}
for self.trait_bounds.each |t| {
res.push(t.repr(tcx));
}
str::connect(res, "+")
}
}
@ -755,3 +755,53 @@ impl Repr for ast_map::path_elt {
}
}
}
impl Repr for ty::BuiltinBound {
fn repr(&self, _tcx: ctxt) -> ~str {
fmt!("%?", *self)
}
}
impl UserString for ty::BuiltinBound {
fn user_string(&self, _tcx: ctxt) -> ~str {
match *self {
ty::BoundCopy => ~"Copy",
ty::BoundStatic => ~"'static",
ty::BoundOwned => ~"Owned",
ty::BoundConst => ~"Const"
}
}
}
impl Repr for ty::BuiltinBounds {
fn repr(&self, tcx: ctxt) -> ~str {
self.user_string(tcx)
}
}
impl UserString for ty::BuiltinBounds {
fn user_string(&self, tcx: ctxt) -> ~str {
if self.is_empty() { ~"<no-bounds>" } else {
let mut result = ~[];
for self.each |bb| {
result.push(bb.user_string(tcx));
}
str::connect(result, "+")
}
}
}
impl UserString for ty::TraitRef {
fn user_string(&self, tcx: ctxt) -> ~str {
let path = ty::item_path(tcx, self.def_id);
let base = ast_map::path_to_str(path, tcx.sess.intr());
if tcx.sess.verbose() && self.substs.self_ty.is_some() {
let mut all_tps = copy self.substs.tps;
for self.substs.self_ty.each |&t| { all_tps.push(t); }
parameterized(tcx, base, self.substs.self_r, all_tps)
} else {
parameterized(tcx, base, self.substs.self_r,
self.substs.tps)
}
}
}

View File

@ -20,7 +20,7 @@ struct E {
}
impl A for E {
fn b<F:Copy + Const,G>(_x: F) -> F { fail!() } //~ ERROR in method `b`, type parameter 0 has 2 bounds, but
fn b<F:Copy + Const,G>(_x: F) -> F { fail!() } //~ ERROR type parameter 0 requires `Const`
}
fn main() {}

View File

@ -8,11 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Tests that impl methods are matched to traits exactly:
// we might be tempted to think matching is contravariant, but if
// we let an impl method can have more permissive bounds than the trait
// method it's implementing, the return type might be less specific than
// needed. Just punt and make it invariant.
// Tests that impls are allowed to have looser, more permissive bounds
// than the traits require.
trait A {
fn b<C:Copy + Const,D>(x: C) -> C;