auto merge of #7314 : bblum/rust/trait-bounds2, r=nikomatsakis

Fixed a merge conflict, some tests, some bitrotting, etc., from #7248.
This commit is contained in:
bors 2013-06-23 14:58:58 -07:00
commit f82756180b
56 changed files with 583 additions and 180 deletions

View File

@ -2,7 +2,7 @@
" Language: Rust
" Maintainer: Patrick Walton <pcwalton@mozilla.com>
" Maintainer: Ben Blum <bblum@cs.cmu.edu>
" Last Change: 2012 Dec 25
" Last Change: 2012 Jun 14
if version < 600
syntax clear
@ -13,13 +13,16 @@ endif
syn keyword rustConditional match if else
syn keyword rustOperator as
syn match rustAssert "\<assert\(\w\)*!"
syn match rustFail "\<fail\(\w\)*!"
syn keyword rustKeyword break copy do drop extern
syn keyword rustKeyword for if impl let log
syn keyword rustKeyword copy do extern
syn keyword rustKeyword for impl let log
syn keyword rustKeyword loop mod once priv pub
syn keyword rustKeyword return
syn keyword rustKeyword unsafe use while
syn keyword rustKeyword unsafe while
syn keyword rustKeyword use nextgroup=rustModPath skipwhite
" FIXME: Scoped impl's name is also fallen in this category
syn keyword rustKeyword mod trait struct enum type nextgroup=rustIdentifier skipwhite
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite
@ -45,7 +48,8 @@ syn keyword rustType c_longlong c_ulonglong intptr_t uintptr_t
syn keyword rustType off_t dev_t ino_t pid_t mode_t ssize_t
syn keyword rustTrait Const Copy Send Owned Sized " inherent traits
syn keyword rustTrait Eq Ord Num Ptr
syn keyword rustTrait Clone Decodable Encodable IterBytes Rand ToStr
syn keyword rustTrait Eq Ord TotalEq TotalOrd Num Ptr
syn keyword rustTrait Drop Add Sub Mul Quot Rem Neg BitAnd BitOr
syn keyword rustTrait BitXor Shl Shr Index
@ -72,19 +76,21 @@ syn keyword rustConstant STDIN_FILENO STDOUT_FILENO STDERR_FILENO
" If foo::bar changes to foo.bar, change this ("::" to "\.").
" If foo::bar changes to Foo::bar, change this (first "\w" to "\u").
syn match rustModPath "\w\(\w\)*::[^<]"he=e-3,me=e-3
syn match rustModPath "\w\(\w\)*" contained " only for 'use path;'
syn match rustModPathSep "::"
syn match rustFuncCall "\w\(\w\)*("he=e-1,me=e-1
syn match rustFuncCall "\w\(\w\)*::<"he=e-3,me=e-3 " foo::<T>();
syn match rustMacro '\w\(\w\)*!'
syn match rustMacro '#\w\(\w\)*'
syn match rustMacro '\w\(\w\)*!' contains=rustAssert,rustFail
syn match rustMacro '#\w\(\w\)*' contains=rustAssert,rustFail
syn match rustFormat display "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlLjzt]\|ll\|hh\)\=\([aAbdiuoxXDOUfFeEgGcCsSpn?]\|\[\^\=.[^]]*\]\)" contained
syn match rustFormat display "%%" contained
syn region rustString start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=rustTodo,rustFormat
syn region rustAttribute start="#\[" end="\]" contains=rustString
syn region rustAttribute start="#\[" end="\]" contains=rustString,rustDeriving
syn region rustDeriving start="deriving(" end=")" contains=rustTrait
" Number literals
syn match rustNumber display "\<[0-9][0-9_]*\>"
@ -143,11 +149,17 @@ hi def link rustMacro Macro
hi def link rustType Type
hi def link rustTodo Todo
hi def link rustAttribute PreProc
hi def link rustDeriving PreProc
hi def link rustStorage StorageClass
hi def link rustLifetime Special
" Other Suggestions:
" hi rustAttribute ctermfg=cyan
" hi rustDeriving ctermfg=cyan
" hi rustAssert ctermfg=yellow
" hi rustFail ctermfg=red
" hi rustMacro ctermfg=magenta
" hi rustModPathSep ctermfg=grey
syn sync minlines=200
syn sync maxlines=500

View File

@ -954,7 +954,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs);
match ty.node {
ast::ty_path(path, _) if path.idents.len() == 1 => {
ast::ty_path(path, bounds, _) if path.idents.len() == 1 => {
assert!(bounds.is_empty());
encode_impl_type_basename(ecx, ebml_w,
ast_util::path_to_ident(path));
}

View File

@ -311,8 +311,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
let substs = parse_substs(st, conv);
let store = parse_trait_store(st);
let mt = parse_mutability(st);
let bounds = parse_bounds(st, conv);
assert_eq!(next(st), ']');
return ty::mk_trait(st.tcx, def, substs, store, mt);
return ty::mk_trait(st.tcx, def, substs, store, mt, bounds.builtin_bounds);
}
'p' => {
let did = parse_def(st, TypeParameter, conv);

View File

@ -261,13 +261,16 @@ fn enc_sty(w: @io::Writer, cx: @ctxt, st: ty::sty) {
enc_substs(w, cx, substs);
w.write_char(']');
}
ty::ty_trait(def, ref substs, store, mt) => {
ty::ty_trait(def, ref substs, store, mt, bounds) => {
w.write_str(&"x[");
w.write_str((cx.ds)(def));
w.write_char('|');
enc_substs(w, cx, substs);
enc_trait_store(w, cx, store);
enc_mutability(w, mt);
let bounds = ty::ParamBounds {builtin_bounds: bounds,
trait_bounds: ~[]};
enc_bounds(w, cx, &bounds);
w.write_char(']');
}
ty::ty_tup(ts) => {

View File

@ -81,8 +81,6 @@ pub fn check_crate(tcx: ty::ctxt,
tcx.sess.abort_if_errors();
}
type check_fn = @fn(Context, @freevar_entry);
fn check_struct_safe_for_destructor(cx: Context,
span: span,
struct_did: def_id) {
@ -129,7 +127,8 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
if cx.tcx.lang_items.drop_trait() == trait_def_id {
// Yes, it's a destructor.
match self_type.node {
ty_path(_, path_node_id) => {
ty_path(_, bounds, path_node_id) => {
assert!(bounds.is_empty());
let struct_def = cx.tcx.def_map.get_copy(
&path_node_id);
let struct_did =
@ -162,30 +161,43 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
// Yields the appropriate function to check the kind of closed over
// variables. `id` is the node_id for some expression that creates the
// closure.
fn with_appropriate_checker(cx: Context, id: node_id, b: &fn(check_fn)) {
fn check_for_uniq(cx: Context, fv: @freevar_entry) {
fn with_appropriate_checker(cx: Context, id: node_id,
b: &fn(checker: &fn(Context, @freevar_entry))) {
fn check_for_uniq(cx: Context, fv: @freevar_entry, bounds: ty::BuiltinBounds) {
// all captured data must be owned, regardless of whether it is
// moved in or copied in.
let id = ast_util::def_id_of_def(fv.def).node;
let var_t = ty::node_id_to_type(cx.tcx, id);
// FIXME(#3569): Once closure capabilities are restricted based on their
// incoming bounds, make this check conditional based on the bounds.
if !check_owned(cx, var_t, fv.span) { return; }
// check that only immutable variables are implicitly copied in
check_imm_free_var(cx, fv.def, fv.span);
check_freevar_bounds(cx, fv.span, var_t, bounds);
}
fn check_for_box(cx: Context, fv: @freevar_entry) {
fn check_for_box(cx: Context, fv: @freevar_entry, bounds: ty::BuiltinBounds) {
// all captured data must be owned
let id = ast_util::def_id_of_def(fv.def).node;
let var_t = ty::node_id_to_type(cx.tcx, id);
// FIXME(#3569): Once closure capabilities are restricted based on their
// incoming bounds, make this check conditional based on the bounds.
if !check_durable(cx.tcx, var_t, fv.span) { return; }
// check that only immutable variables are implicitly copied in
check_imm_free_var(cx, fv.def, fv.span);
check_freevar_bounds(cx, fv.span, var_t, bounds);
}
fn check_for_block(_cx: Context, _fv: @freevar_entry) {
// no restrictions
fn check_for_block(cx: Context, fv: @freevar_entry, bounds: ty::BuiltinBounds) {
let id = ast_util::def_id_of_def(fv.def).node;
let var_t = ty::node_id_to_type(cx.tcx, id);
check_freevar_bounds(cx, fv.span, var_t, bounds);
}
fn check_for_bare(cx: Context, fv: @freevar_entry) {
@ -196,14 +208,14 @@ fn with_appropriate_checker(cx: Context, id: node_id, b: &fn(check_fn)) {
let fty = ty::node_id_to_type(cx.tcx, id);
match ty::get(fty).sty {
ty::ty_closure(ty::ClosureTy {sigil: OwnedSigil, _}) => {
b(check_for_uniq)
ty::ty_closure(ty::ClosureTy {sigil: OwnedSigil, bounds: bounds, _}) => {
b(|cx, fv| check_for_uniq(cx, fv, bounds))
}
ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, _}) => {
b(check_for_box)
ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, bounds: bounds, _}) => {
b(|cx, fv| check_for_box(cx, fv, bounds))
}
ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, _}) => {
b(check_for_block)
ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, bounds: bounds, _}) => {
b(|cx, fv| check_for_block(cx, fv, bounds))
}
ty::ty_bare_fn(_) => {
b(check_for_bare)
@ -271,7 +283,7 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
type_param_defs.repr(cx.tcx));
}
for ts.iter().zip(type_param_defs.iter()).advance |(&ty, type_param_def)| {
check_bounds(cx, type_parameter_id, e.span, ty, type_param_def)
check_typaram_bounds(cx, type_parameter_id, e.span, ty, type_param_def)
}
}
}
@ -279,7 +291,13 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
match e.node {
expr_cast(source, _) => {
check_cast_for_escaping_regions(cx, source, e);
check_kind_bounds_of_cast(cx, source, e);
match ty::get(ty::expr_ty(cx.tcx, e)).sty {
ty::ty_trait(_, _, store, _, bounds) => {
let source_ty = ty::expr_ty(cx.tcx, source);
check_trait_cast_bounds(cx, e.span, source_ty, bounds, store)
}
_ => { }
}
}
expr_copy(expr) => {
// Note: This is the only place where we must check whether the
@ -307,14 +325,14 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) {
match aty.node {
ty_path(_, id) => {
ty_path(_, _, id) => {
let r = cx.tcx.node_type_substs.find(&id);
for r.iter().advance |ts| {
let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&id));
let type_param_defs =
ty::lookup_item_type(cx.tcx, did).generics.type_param_defs;
for ts.iter().zip(type_param_defs.iter()).advance |(&ty, type_param_def)| {
check_bounds(cx, aty.id, aty.span, ty, type_param_def)
check_typaram_bounds(cx, aty.id, aty.span, ty, type_param_def)
}
}
}
@ -323,20 +341,29 @@ fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) {
visit::visit_ty(aty, (cx, v));
}
pub fn check_bounds(cx: Context,
_type_parameter_id: node_id,
sp: span,
ty: ty::t,
type_param_def: &ty::TypeParameterDef)
// Calls "any_missing" if any bounds were missing.
pub fn check_builtin_bounds(cx: Context, ty: ty::t, bounds: ty::BuiltinBounds,
any_missing: &fn(ty::BuiltinBounds))
{
let kind = ty::type_contents(cx.tcx, ty);
let mut missing = ty::EmptyBuiltinBounds();
for type_param_def.bounds.builtin_bounds.each |bound| {
for bounds.each |bound| {
if !kind.meets_bound(cx.tcx, bound) {
missing.add(bound);
}
}
if !missing.is_empty() {
any_missing(missing);
}
}
pub fn check_typaram_bounds(cx: Context,
_type_parameter_id: node_id,
sp: span,
ty: ty::t,
type_param_def: &ty::TypeParameterDef)
{
do check_builtin_bounds(cx, ty, type_param_def.bounds.builtin_bounds) |missing| {
cx.tcx.sess.span_err(
sp,
fmt!("instantiating a type parameter with an incompatible type \
@ -346,6 +373,38 @@ pub fn check_bounds(cx: Context,
}
}
pub fn check_freevar_bounds(cx: Context, sp: span, ty: ty::t,
bounds: ty::BuiltinBounds)
{
do check_builtin_bounds(cx, ty, bounds) |missing| {
cx.tcx.sess.span_err(
sp,
fmt!("cannot capture variable of type `%s`, which does not fulfill \
`%s`, in a bounded closure",
ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx)));
cx.tcx.sess.span_note(
sp,
fmt!("this closure's environment must satisfy `%s`",
bounds.user_string(cx.tcx)));
}
}
pub fn check_trait_cast_bounds(cx: Context, sp: span, ty: ty::t,
bounds: ty::BuiltinBounds, store: ty::TraitStore) {
do check_builtin_bounds(cx, ty, bounds) |missing| {
cx.tcx.sess.span_err(sp,
fmt!("cannot pack type `%s`, which does not fulfill \
`%s`, as a trait bounded by %s",
ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx),
bounds.user_string(cx.tcx)));
}
// FIXME(#3569): Remove this check when the corresponding restriction
// is made with type contents.
if store == ty::UniqTraitStore && !ty::type_is_owned(cx.tcx, ty) {
cx.tcx.sess.span_err(sp, "uniquely-owned trait objects must be sendable");
}
}
fn is_nullary_variant(cx: Context, ex: @expr) -> bool {
match ex.node {
expr_path(_) => {
@ -528,19 +587,3 @@ pub fn check_cast_for_escaping_regions(
cx.tcx.region_maps.is_subregion_of(r_sub, r_sup)
}
}
/// Ensures that values placed into a ~Trait are copyable and sendable.
pub fn check_kind_bounds_of_cast(cx: Context, source: @expr, target: @expr) {
let target_ty = ty::expr_ty(cx.tcx, target);
match ty::get(target_ty).sty {
ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
let source_ty = ty::expr_ty(cx.tcx, source);
if !ty::type_is_owned(cx.tcx, source_ty) {
cx.tcx.sess.span_err(
target.span,
"uniquely-owned trait objects must be sendable");
}
}
_ => {} // Nothing to do.
}
}

View File

@ -714,7 +714,7 @@ fn check_item_ctypes(cx: &Context, it: @ast::item) {
let tys = vec::map(decl.inputs, |a| a.ty );
for vec::each(vec::append_one(tys, decl.output)) |ty| {
match ty.node {
ast::ty_path(_, id) => {
ast::ty_path(_, _, id) => {
match cx.tcx.def_map.get_copy(&id) {
ast::def_prim_ty(ast::ty_int(ast::ty_i)) => {
cx.span_lint(ctypes, ty.span,

View File

@ -804,7 +804,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
// then check whether it is region-parameterized and consider
// that as a direct dependency.
match ty.node {
ast::ty_path(path, id) => {
ast::ty_path(path, _bounds, id) => {
match cx.def_map.find(&id) {
Some(&ast::def_ty(did)) |
Some(&ast::def_trait(did)) |
@ -840,7 +840,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
visit_mt(mt, (cx, visitor));
}
ast::ty_path(path, _) => {
ast::ty_path(path, _bounds, _) => {
// type parameters are---for now, anyway---always invariant
do cx.with_ambient_variance(rv_invariant) {
for path.types.iter().advance |tp| {

View File

@ -1250,7 +1250,7 @@ impl Resolver {
// If there are static methods, then create the module
// and add them.
match (trait_ref_opt, ty) {
(None, @Ty { node: ty_path(path, _), _ }) if
(None, @Ty { node: ty_path(path, _, _), _ }) if
has_static_methods && path.idents.len() == 1 => {
let name = path_to_ident(path);
@ -4120,7 +4120,7 @@ impl Resolver {
// Like path expressions, the interpretation of path types depends
// on whether the path has multiple elements in it or not.
ty_path(path, path_id) => {
ty_path(path, bounds, path_id) => {
// This is a path in the type namespace. Walk through scopes
// scopes looking for it.
let mut result_def = None;
@ -4179,6 +4179,10 @@ impl Resolver {
self.idents_to_str(path.idents)));
}
}
for bounds.each |bound| {
self.resolve_type_parameter_bound(bound, visitor);
}
}
ty_closure(c) => {

View File

@ -561,7 +561,7 @@ fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType {
cx.sess.span_note(span, "debuginfo for closure NYI");
create_unimpl_ty(cx, t)
},
ty::ty_trait(_did, ref _substs, ref _vstore, _) => {
ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => {
cx.sess.span_note(span, "debuginfo for trait NYI");
create_unimpl_ty(cx, t)
},

View File

@ -683,7 +683,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
}
ast::expr_cast(val, _) => {
match ty::get(node_id_type(bcx, expr.id)).sty {
ty::ty_trait(_, _, store, _) => {
ty::ty_trait(_, _, store, _, _) => {
return meth::trans_trait_cast(bcx, val, expr.id, dest,
store);
}

View File

@ -486,13 +486,13 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
ty::ty_closure(_) => {
closure::make_closure_glue(bcx, v0, t, drop_ty)
}
ty::ty_trait(_, _, ty::BoxTraitStore, _) => {
ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]);
let llbox = Load(bcx, llbox_ptr);
decr_refcnt_maybe_free(bcx, llbox, Some(llbox_ptr),
ty::mk_opaque_box(ccx.tcx))
}
ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
// Only drop the value when it is non-null
do with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue))) |bcx| {
@ -571,12 +571,12 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
ty::ty_closure(_) => {
closure::make_closure_glue(bcx, v, t, take_ty)
}
ty::ty_trait(_, _, ty::BoxTraitStore, _) => {
ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
incr_refcnt_of_boxed(bcx, llbox);
bcx
}
ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]);
let llvtable = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_vtable]));

View File

@ -293,7 +293,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt,
ty::ty_closure(ref fty) => {
Some(normalized_closure_ty(tcx, fty.sigil))
}
ty::ty_trait(_, _, ref store, _) => {
ty::ty_trait(_, _, ref store, _, _) => {
let sigil = match *store {
ty::UniqTraitStore => ast::OwnedSigil,
ty::BoxTraitStore => ast::ManagedSigil,

View File

@ -160,7 +160,7 @@ fn traverse_ty<'a>(ty: @Ty, (cx, v): (@mut ctx<'a>, visit::vt<@mut ctx<'a>>)) {
}
match ty.node {
ty_path(p, p_id) => {
ty_path(p, _bounds, p_id) => {
match cx.tcx.def_map.find(&p_id) {
// Kind of a hack to check this here, but I'm not sure what else
// to do

View File

@ -335,7 +335,7 @@ impl Reflector {
}
// Miscallaneous extra types
ty::ty_trait(_, _, _, _) => self.leaf(~"trait"),
ty::ty_trait(_, _, _, _, _) => self.leaf(~"trait"),
ty::ty_infer(_) => self.leaf(~"infer"),
ty::ty_err => self.leaf(~"err"),
ty::ty_param(ref p) => {

View File

@ -140,7 +140,7 @@ pub fn sizing_type_of(cx: &mut CrateContext, t: ty::t) -> Type {
ty::ty_bare_fn(*) => Type::i8p(),
ty::ty_closure(*) => Type::struct_([Type::i8p(), Type::i8p()], false),
ty::ty_trait(_, _, store, _) => Type::opaque_trait(cx, store),
ty::ty_trait(_, _, store, _, _) => Type::opaque_trait(cx, store),
ty::ty_estr(ty::vstore_fixed(size)) => Type::array(&Type::i8(), size as u64),
ty::ty_evec(mt, ty::vstore_fixed(size)) => {
@ -271,7 +271,7 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type {
let ty = type_of_fn_from_ty(cx, t);
Type::func_pair(cx, &ty)
}
ty::ty_trait(_, _, store, _) => Type::opaque_trait(cx, store),
ty::ty_trait(_, _, store, _, _) => Type::opaque_trait(cx, store),
ty::ty_type => cx.tydesc_type.ptr_to(),
ty::ty_tup(*) => {
let repr = adt::represent_type(cx, t);

View File

@ -208,7 +208,7 @@ pub fn type_needs_inner(cx: Context,
ty::ty_bare_fn(*) |
ty::ty_ptr(_) |
ty::ty_rptr(_, _) |
ty::ty_trait(_, _, _, _) => false,
ty::ty_trait(*) => false,
ty::ty_enum(did, ref substs) => {
if list::find(enums_seen, |id| *id == did).is_none() {

View File

@ -419,7 +419,8 @@ impl to_bytes::IterBytes for ClosureTy {
self.sigil.iter_bytes(lsb0, f) &&
self.onceness.iter_bytes(lsb0, f) &&
self.region.iter_bytes(lsb0, f) &&
self.sig.iter_bytes(lsb0, f)
self.sig.iter_bytes(lsb0, f) &&
self.bounds.iter_bytes(lsb0, f)
}
}
@ -600,7 +601,7 @@ pub enum sty {
ty_rptr(Region, mt),
ty_bare_fn(BareFnTy),
ty_closure(ClosureTy),
ty_trait(def_id, substs, TraitStore, ast::mutability),
ty_trait(def_id, substs, TraitStore, ast::mutability, BuiltinBounds),
ty_struct(def_id, substs),
ty_tup(~[t]),
@ -1046,7 +1047,7 @@ fn mk_t(cx: ctxt, st: sty) -> t {
&ty_infer(_) => flags |= needs_infer as uint,
&ty_self(_) => flags |= has_self as uint,
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) |
&ty_trait(_, ref substs, _, _) => {
&ty_trait(_, ref substs, _, _, _) => {
flags |= sflags(substs);
}
&ty_box(ref m) | &ty_uniq(ref m) | &ty_evec(ref m, _) |
@ -1268,10 +1269,11 @@ pub fn mk_trait(cx: ctxt,
did: ast::def_id,
substs: substs,
store: TraitStore,
mutability: ast::mutability)
mutability: ast::mutability,
bounds: BuiltinBounds)
-> t {
// take a copy of substs so that we own the vectors inside
mk_t(cx, ty_trait(did, substs, store, mutability))
mk_t(cx, ty_trait(did, substs, store, mutability, bounds))
}
pub fn mk_struct(cx: ctxt, struct_id: ast::def_id, substs: substs) -> t {
@ -1319,7 +1321,7 @@ pub fn maybe_walk_ty(ty: t, f: &fn(t) -> bool) {
maybe_walk_ty(tm.ty, f);
}
ty_enum(_, ref substs) | ty_struct(_, ref substs) |
ty_trait(_, ref substs, _, _) => {
ty_trait(_, ref substs, _, _, _) => {
for (*substs).tps.iter().advance |subty| { maybe_walk_ty(*subty, f); }
}
ty_tup(ref ts) => { for ts.iter().advance |tt| { maybe_walk_ty(*tt, f); } }
@ -1380,8 +1382,8 @@ fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty {
ty_enum(tid, ref substs) => {
ty_enum(tid, fold_substs(substs, fldop))
}
ty_trait(did, ref substs, st, mutbl) => {
ty_trait(did, fold_substs(substs, fldop), st, mutbl)
ty_trait(did, ref substs, st, mutbl, bounds) => {
ty_trait(did, fold_substs(substs, fldop), st, mutbl, bounds)
}
ty_tup(ref ts) => {
let new_ts = ts.map(|tt| fldop(*tt));
@ -1470,8 +1472,12 @@ pub fn fold_regions_and_ty(
ty_struct(def_id, ref substs) => {
ty::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt))
}
ty_trait(def_id, ref substs, st, mutbl) => {
ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl)
ty_trait(def_id, ref substs, st, mutbl, bounds) => {
let st = match st {
RegionTraitStore(region) => RegionTraitStore(fldr(region)),
st => st,
};
ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl, bounds)
}
ty_bare_fn(ref f) => {
ty::mk_bare_fn(cx, BareFnTy {sig: fold_sig(&f.sig, fldfnt),
@ -1850,7 +1856,7 @@ impl TypeContents {
}
pub fn noncopyable(_cx: ctxt) -> TypeContents {
TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_OWNED_CLOSURE +
TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_NONCOPY_TRAIT +
TC_EMPTY_ENUM
}
@ -1899,13 +1905,19 @@ impl TypeContents {
}
pub fn needs_drop(&self, cx: ctxt) -> bool {
if self.intersects(TC_NONCOPY_TRAIT) {
// Currently all noncopyable existentials are 2nd-class types
// behind owned pointers. With dynamically-sized types, remove
// this assertion.
assert!(self.intersects(TC_OWNED_POINTER));
}
let tc = TC_MANAGED + TC_DTOR + TypeContents::owned(cx);
self.intersects(tc)
}
pub fn owned(_cx: ctxt) -> TypeContents {
//! Any kind of owned contents.
TC_OWNED_CLOSURE + TC_OWNED_POINTER + TC_OWNED_VEC
TC_OWNED_POINTER + TC_OWNED_VEC
}
}
@ -1939,8 +1951,8 @@ static TC_OWNED_POINTER: TypeContents = TypeContents{bits: 0b0000_0000_0010};
/// Contains an owned vector ~[] or owned string ~str
static TC_OWNED_VEC: TypeContents = TypeContents{bits: 0b0000_0000_0100};
/// Contains a ~fn() or a ~Trait, which is non-copyable.
static TC_OWNED_CLOSURE: TypeContents = TypeContents{bits: 0b0000_0000_1000};
/// Contains a non-copyable ~fn() or a ~Trait (NOT a ~fn:Copy() or ~Trait:Copy).
static TC_NONCOPY_TRAIT: TypeContents = TypeContents{bits: 0b0000_0000_1000};
/// Type with a destructor
static TC_DTOR: TypeContents = TypeContents{bits: 0b0000_0001_0000};
@ -2054,18 +2066,19 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache)))
}
ty_trait(_, _, UniqTraitStore, _) => {
TC_OWNED_CLOSURE
ty_trait(_, _, UniqTraitStore, _, _bounds) => {
// FIXME(#3569): Make this conditional on the trait's bounds.
TC_NONCOPY_TRAIT + TC_OWNED_POINTER
}
ty_trait(_, _, BoxTraitStore, mutbl) => {
ty_trait(_, _, BoxTraitStore, mutbl, _bounds) => {
match mutbl {
ast::m_mutbl => TC_MANAGED + TC_MUTABLE,
_ => TC_MANAGED
}
}
ty_trait(_, _, RegionTraitStore(r), mutbl) => {
ty_trait(_, _, RegionTraitStore(r), mutbl, _bounds) => {
borrowed_contents(r, mutbl)
}
@ -2178,7 +2191,9 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
match sigil {
ast::BorrowedSigil => TC_BORROWED_POINTER,
ast::ManagedSigil => TC_MANAGED,
ast::OwnedSigil => TC_OWNED_CLOSURE
// FIXME(#3569): Looks like noncopyability should depend
// on the bounds, but I don't think this case ever comes up.
ast::OwnedSigil => TC_NONCOPY_TRAIT + TC_OWNED_POINTER,
}
}
@ -2252,7 +2267,11 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
let st = match cty.sigil {
ast::BorrowedSigil => TC_BORROWED_POINTER,
ast::ManagedSigil => TC_MANAGED,
ast::OwnedSigil => TC_OWNED_CLOSURE
ast::OwnedSigil => if cty.bounds.contains_elem(BoundCopy) {
TC_OWNED_POINTER
} else {
TC_OWNED_POINTER + TC_NONCOPY_TRAIT
}
};
let rt = borrowed_contents(cty.region, m_imm);
let ot = match cty.onceness {
@ -2347,7 +2366,7 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
false // unsafe ptrs can always be NULL
}
ty_trait(_, _, _, _) => {
ty_trait(_, _, _, _, _) => {
false
}
@ -2500,7 +2519,7 @@ pub fn type_is_pod(cx: ctxt, ty: t) -> bool {
ty_box(_) | ty_uniq(_) | ty_closure(_) |
ty_estr(vstore_uniq) | ty_estr(vstore_box) |
ty_evec(_, vstore_uniq) | ty_evec(_, vstore_box) |
ty_trait(_, _, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false,
ty_trait(_, _, _, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false,
// Structural types
ty_enum(did, ref substs) => {
let variants = enum_variants(cx, did);
@ -2791,12 +2810,13 @@ impl to_bytes::IterBytes for sty {
ty_uniq(ref mt) => 19u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f),
ty_trait(ref did, ref substs, ref v, ref mutbl) => {
ty_trait(ref did, ref substs, ref v, ref mutbl, bounds) => {
20u8.iter_bytes(lsb0, f) &&
did.iter_bytes(lsb0, f) &&
substs.iter_bytes(lsb0, f) &&
v.iter_bytes(lsb0, f) &&
mutbl.iter_bytes(lsb0, f)
mutbl.iter_bytes(lsb0, f) &&
bounds.iter_bytes(lsb0, f)
}
ty_opaque_closure_ptr(ref ck) => 21u8.iter_bytes(lsb0, f) && ck.iter_bytes(lsb0, f),
@ -3440,7 +3460,7 @@ pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
ty_rptr(_, _) => ~"&-ptr",
ty_bare_fn(_) => ~"extern fn",
ty_closure(_) => ~"fn",
ty_trait(id, _, _, _) => fmt!("trait %s", item_path_str(cx, id)),
ty_trait(id, _, _, _, _) => fmt!("trait %s", item_path_str(cx, id)),
ty_struct(id, _) => fmt!("struct %s", item_path_str(cx, id)),
ty_tup(_) => ~"tuple",
ty_infer(TyVar(_)) => ~"inferred type",
@ -3774,7 +3794,7 @@ pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> {
pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> {
match get(ty).sty {
ty_trait(id, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id),
ty_trait(id, _, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id),
_ => None
}
}
@ -4454,5 +4474,6 @@ pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) {
assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name));
let trait_ref = tcx.intrinsic_traits.get_copy(&ty_visitor_name);
(trait_ref,
mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore, ast::m_imm))
mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs,
BoxTraitStore, ast::m_imm, EmptyBuiltinBounds()))
}

View File

@ -277,7 +277,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
}
return ty::mk_evec(tcx, mt, vst);
}
ast::ty_path(path, id) => {
ast::ty_path(path, bounds, id) => {
// Note that the "bounds must be empty if path is not a trait"
// restriction is enforced in the below case for ty_path, which
// will run after this as long as the path isn't a trait.
match tcx.def_map.find(&id) {
Some(&ast::def_prim_ty(ast::ty_str)) if a_seq_ty.mutbl == ast::m_imm => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
@ -300,11 +303,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
ty::BoxTraitStore
}
};
let bounds = conv_builtin_bounds(this.tcx(), bounds);
return ty::mk_trait(tcx,
result.def_id,
copy result.substs,
trait_store,
a_seq_ty.mutbl);
a_seq_ty.mutbl,
bounds);
}
_ => {}
}
@ -395,13 +400,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
ast_ty.span);
ty::mk_closure(tcx, fn_decl)
}
ast::ty_path(path, id) => {
ast::ty_path(path, bounds, id) => {
let a_def = match tcx.def_map.find(&id) {
None => tcx.sess.span_fatal(
ast_ty.span, fmt!("unbound path %s",
path_to_str(path, tcx.sess.intr()))),
Some(&d) => d
};
// Kind bounds on path types are only supported for traits.
match a_def {
// But don't emit the error if the user meant to do a trait anyway.
ast::def_trait(*) => { },
_ if !bounds.is_empty() =>
tcx.sess.span_err(ast_ty.span,
"kind bounds can only be used on trait types"),
_ => { },
}
match a_def {
ast::def_trait(_) => {
let path_str = path_to_str(path, tcx.sess.intr());

View File

@ -292,7 +292,7 @@ impl<'self> LookupContext<'self> {
ty_param(p) => {
self.push_inherent_candidates_from_param(self_ty, p);
}
ty_trait(did, ref substs, store, _) => {
ty_trait(did, ref substs, store, _, _) => {
self.push_inherent_candidates_from_trait(
self_ty, did, substs, store);
self.push_inherent_impl_candidates_for_type(did);

View File

@ -360,7 +360,7 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
// explaining how it goes about doing that.
let target_ty = rcx.resolve_node_type(expr.id);
match ty::get(target_ty).sty {
ty::ty_trait(_, _, ty::RegionTraitStore(trait_region), _) => {
ty::ty_trait(_, _, ty::RegionTraitStore(trait_region), _, _) => {
let source_ty = rcx.fcx.expr_ty(source);
constrain_regions_in_type(rcx, trait_region,
expr.span, source_ty);

View File

@ -139,10 +139,11 @@ fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo,
let t = ty::mk_trait(tcx,
id, substs,
ty::RegionTraitStore(ty::re_static),
ast::m_imm);
ast::m_imm,
ty::EmptyBuiltinBounds());
do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
match ty::get(*t_f).sty {
ty::ty_trait(_, ref substs_f, _, _) => (/*bad*/copy *substs_f),
ty::ty_trait(_, ref substs_f, _, _, _) => (/*bad*/copy *substs_f),
_ => fail!("t_f should be a trait")
}
}
@ -530,7 +531,9 @@ pub fn early_resolve_expr(ex: @ast::expr,
debug!("vtable resolution on expr %s", ex.repr(fcx.tcx()));
let target_ty = fcx.expr_ty(ex);
match ty::get(target_ty).sty {
ty::ty_trait(target_def_id, ref target_substs, store, target_mutbl) => {
// Bounds of type's contents are not checked here, but in kind.rs.
ty::ty_trait(target_def_id, ref target_substs, store,
target_mutbl, _bounds) => {
fn mutability_allowed(a_mutbl: ast::mutability,
b_mutbl: ast::mutability) -> bool {
a_mutbl == b_mutbl ||

View File

@ -114,7 +114,7 @@ pub fn type_is_defined_in_local_crate(original_type: t) -> bool {
do ty::walk_ty(original_type) |t| {
match get(t).sty {
ty_enum(def_id, _) |
ty_trait(def_id, _, _, _) |
ty_trait(def_id, _, _, _, _) |
ty_struct(def_id, _) => {
if def_id.crate == ast::local_crate {
found_nominal = true;
@ -140,7 +140,7 @@ pub fn get_base_type_def_id(inference_context: @mut InferCtxt,
match get(base_type).sty {
ty_enum(def_id, _) |
ty_struct(def_id, _) |
ty_trait(def_id, _, _, _) => {
ty_trait(def_id, _, _, _, _) => {
return Some(def_id);
}
_ => {
@ -753,7 +753,7 @@ impl CoherenceChecker {
pub fn ast_type_is_defined_in_local_crate(&self, original_type: @ast::Ty)
-> bool {
match original_type.node {
ty_path(_, path_id) => {
ty_path(_, _, path_id) => {
match self.crate_context.tcx.def_map.get_copy(&path_id) {
def_ty(def_id) | def_struct(def_id) => {
if def_id.crate != local_crate {

View File

@ -508,13 +508,15 @@ pub fn super_tys<C:Combine>(
}
}
(&ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl),
&ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl))
(&ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl, a_bounds),
&ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl, b_bounds))
if a_id == b_id && a_mutbl == b_mutbl => {
let trait_def = ty::lookup_trait_def(tcx, a_id);
do this.substs(&trait_def.generics, a_substs, b_substs).chain |substs| {
do this.trait_stores(ty::terr_trait, a_store, b_store).chain |s| {
Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s, a_mutbl))
do this.bounds(a_bounds, b_bounds).chain |bounds| {
Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s, a_mutbl, bounds))
}
}
}
}

View File

@ -717,10 +717,11 @@ impl InferCtxt {
trait_ref.def_id,
copy trait_ref.substs,
ty::UniqTraitStore,
ast::m_imm);
ast::m_imm,
ty::EmptyBuiltinBounds());
let dummy1 = self.resolve_type_vars_if_possible(dummy0);
match ty::get(dummy1).sty {
ty::ty_trait(ref def_id, ref substs, _, _) => {
ty::ty_trait(ref def_id, ref substs, _, _, _) => {
ty::TraitRef {def_id: *def_id,
substs: copy *substs}
}

View File

@ -365,6 +365,11 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
s.push_str("fn");
if !cty.bounds.is_empty() {
s.push_str(":");
}
s.push_str(cty.bounds.repr(cx));
push_sig_to_str(cx, &mut s, &cty.sig);
return s;
@ -451,11 +456,14 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
let base = ast_map::path_to_str(path, cx.sess.intr());
parameterized(cx, base, substs.self_r, substs.tps)
}
ty_trait(did, ref substs, s, mutbl) => {
ty_trait(did, ref substs, s, mutbl, ref bounds) => {
let path = ty::item_path(cx, did);
let base = ast_map::path_to_str(path, cx.sess.intr());
let ty = parameterized(cx, base, substs.self_r, substs.tps);
fmt!("%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty)
let bound_sep = if bounds.is_empty() { "" } else { ":" };
let bound_str = bounds.repr(cx);
fmt!("%s%s%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty,
bound_sep, bound_str)
}
ty_evec(ref mt, vs) => {
vstore_ty_to_str(cx, mt, vs)

View File

@ -797,7 +797,7 @@ pub enum ty_ {
ty_closure(@TyClosure),
ty_bare_fn(@TyBareFn),
ty_tup(~[@Ty]),
ty_path(@Path, node_id),
ty_path(@Path, @OptVec<TyParamBound>, node_id),
ty_mac(mac),
// ty_infer means the type should be inferred instead of it having been
// specified. This should only appear at the "top level" of a type and not

View File

@ -473,7 +473,7 @@ pub fn id_visitor<T: Copy>(vfn: @fn(node_id, T)) -> visit::vt<T> {
visit_ty: |ty, (t, vt)| {
match ty.node {
ty_path(_, id) => vfn(id, copy t),
ty_path(_, _, id) => vfn(id, copy t),
_ => { /* fall through */ }
}
visit::visit_ty(ty, (t, vt));

View File

@ -48,7 +48,7 @@ pub trait AstBuilder {
fn ty_mt(&self, ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt;
fn ty(&self, span: span, ty: ast::ty_) -> @ast::Ty;
fn ty_path(&self, @ast::Path) -> @ast::Ty;
fn ty_path(&self, @ast::Path, @OptVec<ast::TyParamBound>) -> @ast::Ty;
fn ty_ident(&self, span: span, idents: ast::ident) -> @ast::Ty;
fn ty_rptr(&self, span: span,
@ -267,14 +267,17 @@ impl AstBuilder for @ExtCtxt {
}
}
fn ty_path(&self, path: @ast::Path) -> @ast::Ty {
fn ty_path(&self, path: @ast::Path, bounds: @OptVec<ast::TyParamBound>)
-> @ast::Ty {
self.ty(path.span,
ast::ty_path(path, self.next_id()))
ast::ty_path(path, bounds, self.next_id()))
}
// Might need to take bounds as an argument in the future, if you ever want
// to generate a bounded existential trait type.
fn ty_ident(&self, span: span, ident: ast::ident)
-> @ast::Ty {
self.ty_path(self.path_ident(span, ident))
self.ty_path(self.path_ident(span, ident), @opt_vec::Empty)
}
fn ty_rptr(&self,
@ -304,7 +307,8 @@ impl AstBuilder for @ExtCtxt {
self.ident_of("Option")
],
None,
~[ ty ]))
~[ ty ]),
@opt_vec::Empty)
}
fn ty_field_imm(&self, span: span, name: ident, ty: @ast::Ty) -> ast::ty_field {
@ -342,7 +346,7 @@ impl AstBuilder for @ExtCtxt {
fn ty_vars_global(&self, ty_params: &OptVec<ast::TyParam>) -> ~[@ast::Ty] {
opt_vec::take_vec(
ty_params.map(|p| self.ty_path(
self.path_global(dummy_sp(), ~[p.ident]))))
self.path_global(dummy_sp(), ~[p.ident]), @opt_vec::Empty)))
}
fn strip_bounds(&self, generics: &Generics) -> Generics {

View File

@ -358,7 +358,8 @@ impl<'self> TraitDef<'self> {
// Create the type of `self`.
let self_type = cx.ty_path(cx.path_all(span, false, ~[ type_ident ], self_lifetime,
opt_vec::take_vec(self_ty_params)));
opt_vec::take_vec(self_ty_params)),
@opt_vec::Empty);
let doc_attr = cx.attribute(
span,

View File

@ -65,7 +65,7 @@ impl<'self> Path<'self> {
self_generics: &Generics)
-> @ast::Ty {
cx.ty_path(self.to_path(cx, span,
self_ty, self_generics))
self_ty, self_generics), @opt_vec::Empty)
}
pub fn to_path(&self,
cx: @ExtCtxt,
@ -144,7 +144,8 @@ impl<'self> Ty<'self> {
}
Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) }
Self => {
cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
cx.ty_path(self.to_path(cx, span, self_ty, self_generics),
@opt_vec::Empty)
}
Tuple(ref fields) => {
let ty = if fields.is_empty() {

View File

@ -61,7 +61,7 @@ impl gen_send for message {
let pipe_ty = cx.ty_path(
path(~[this.data_name()], span)
.add_tys(cx.ty_vars(&this.generics.ty_params)));
.add_tys(cx.ty_vars(&this.generics.ty_params)), @opt_vec::Empty);
let args_ast = vec::append(
~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)],
args_ast);
@ -117,7 +117,7 @@ impl gen_send for message {
let mut rty = cx.ty_path(path(~[next.data_name()],
span)
.add_tys(copy next_state.tys));
.add_tys(copy next_state.tys), @opt_vec::Empty);
if try {
rty = cx.ty_option(rty);
}
@ -146,7 +146,7 @@ impl gen_send for message {
cx.ty_path(
path(~[this.data_name()], span)
.add_tys(cx.ty_vars(
&this.generics.ty_params))))],
&this.generics.ty_params)), @opt_vec::Empty))],
args_ast);
let message_args = if arg_names.len() == 0 {
@ -192,7 +192,7 @@ impl gen_send for message {
fn to_ty(&mut self, cx: @ExtCtxt) -> @ast::Ty {
cx.ty_path(path(~[cx.ident_of(self.name())], self.span())
.add_tys(cx.ty_vars(&self.get_generics().ty_params)))
.add_tys(cx.ty_vars(&self.get_generics().ty_params)), @opt_vec::Empty)
}
}
@ -226,7 +226,7 @@ impl to_type_decls for state {
cx.ty_path(
path(~[cx.ident_of(dir),
cx.ident_of(next_name)], span)
.add_tys(copy next_state.tys)))
.add_tys(copy next_state.tys), @opt_vec::Empty))
}
None => tys
};
@ -279,7 +279,8 @@ impl to_type_decls for state {
self.data_name()],
dummy_sp())
.add_tys(cx.ty_vars(
&self.generics.ty_params))))),
&self.generics.ty_params)), @opt_vec::Empty)),
@opt_vec::Empty),
cx.strip_bounds(&self.generics)));
}
else {
@ -298,8 +299,8 @@ impl to_type_decls for state {
self.data_name()],
dummy_sp())
.add_tys(cx.ty_vars_global(
&self.generics.ty_params))),
self.proto.buffer_ty_path(cx)])),
&self.generics.ty_params)), @opt_vec::Empty),
self.proto.buffer_ty_path(cx)]), @opt_vec::Empty),
cx.strip_bounds(&self.generics)));
};
items
@ -384,7 +385,7 @@ impl gen_init for protocol {
cx.ty_path(path(~[cx.ident_of("super"),
cx.ident_of("__Buffer")],
copy self.span)
.add_tys(cx.ty_vars_global(&params)))
.add_tys(cx.ty_vars_global(&params)), @opt_vec::Empty)
}
fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item {

View File

@ -15,6 +15,7 @@ use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::pipes::ast_builder::{append_types, path};
use opt_vec;
#[deriving(Eq)]
pub enum direction { send, recv }
@ -101,7 +102,7 @@ impl state_ {
pub fn to_ty(&self, cx: @ExtCtxt) -> @ast::Ty {
cx.ty_path
(path(~[cx.ident_of(self.name)],self.span).add_tys(
cx.ty_vars(&self.generics.ty_params)))
cx.ty_vars(&self.generics.ty_params)), @opt_vec::Empty)
}
/// Iterate over the states that can be reached in one message

View File

@ -680,7 +680,9 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
})
}
ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(*ty))),
ty_path(path, id) => ty_path(fld.fold_path(path), fld.new_id(id)),
ty_path(path, bounds, id) =>
ty_path(fld.fold_path(path),
@bounds.map(|x| fold_ty_param_bound(x, fld)), fld.new_id(id)),
ty_fixed_length_vec(ref mt, e) => {
ty_fixed_length_vec(
fold_mt(mt, fld),

View File

@ -494,7 +494,7 @@ mod test {
idents:~[str_to_ident("int")],
rp: None,
types: ~[]},
2),
@opt_vec::Empty, 2),
span:sp(4,7)},
pat: @ast::pat{id:1,
node: ast::pat_ident(ast::bind_infer,
@ -530,7 +530,7 @@ mod test {
idents:~[str_to_ident("int")],
rp: None,
types: ~[]},
2),
@opt_vec::Empty, 2),
span:sp(10,13)},
pat: @ast::pat{id:1, // fixme
node: ast::pat_ident(

View File

@ -46,7 +46,6 @@ pub enum ObsoleteSyntax {
ObsoleteUnsafeBlock,
ObsoleteUnenforcedBound,
ObsoleteImplSyntax,
ObsoleteTraitBoundSeparator,
ObsoleteMutOwnedPointer,
ObsoleteMutVector,
ObsoleteImplVisibility,
@ -143,10 +142,6 @@ impl Parser {
"colon-separated impl syntax",
"write `impl Trait for Type`"
),
ObsoleteTraitBoundSeparator => (
"space-separated trait bounds",
"write `+` between trait bounds"
),
ObsoleteMutOwnedPointer => (
"const or mutable owned pointer",
"mutability inherits through `~` pointers; place the `~` box

View File

@ -75,7 +75,7 @@ use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator};
use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap};
use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
use parse::obsolete::{ObsoleteMutOwnedPointer};
use parse::obsolete::{ObsoleteMutVector, ObsoleteImplVisibility};
use parse::obsolete::{ObsoleteRecordType, ObsoleteRecordPattern};
use parse::obsolete::{ObsoletePostFnTySigil};
@ -710,8 +710,8 @@ impl Parser {
} else if *self.token == token::MOD_SEP
|| is_ident_or_path(self.token) {
// NAMED TYPE
let path = self.parse_path_with_tps(false);
ty_path(path, self.get_id())
let (path, bounds) = self.parse_type_path();
ty_path(path, @bounds, self.get_id())
} else {
self.fatal(fmt!("expected type, found token %?",
*self.token));
@ -974,10 +974,8 @@ impl Parser {
types: ~[] }
}
// parse a path optionally with type parameters. If 'colons'
// is true, then type parameters must be preceded by colons,
// as in a::t::<t1,t2>
pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
pub fn parse_bounded_path_with_tps(&self, colons: bool,
before_tps: Option<&fn()>) -> @ast::Path {
debug!("parse_path_with_tps(colons=%b)", colons);
maybe_whole!(self, nt_path);
@ -987,6 +985,10 @@ impl Parser {
return path;
}
// If the path might have bounds on it, they should be parsed before
// the parameters, e.g. module::TraitName:B1+B2<T>
before_tps.map_consume(|callback| callback());
// Parse the (obsolete) trailing region parameter, if any, which will
// be written "foo/&x"
let rp_slash = {
@ -1038,6 +1040,25 @@ impl Parser {
.. copy *path }
}
// parse a path optionally with type parameters. If 'colons'
// is true, then type parameters must be preceded by colons,
// as in a::t::<t1,t2>
pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
self.parse_bounded_path_with_tps(colons, None)
}
// Like the above, but can also parse kind bounds in the case of a
// path to be used as a type that might be a trait.
pub fn parse_type_path(&self) -> (@ast::Path, OptVec<TyParamBound>) {
let mut bounds = opt_vec::Empty;
let path = self.parse_bounded_path_with_tps(false, Some(|| {
// Note: this closure might not even get called in the case of a
// macro-generated path. But that's the macro parser's job.
bounds = self.parse_optional_ty_param_bounds();
}));
(path, bounds)
}
/// parses 0 or 1 lifetime
pub fn parse_opt_lifetime(&self) -> Option<@ast::Lifetime> {
match *self.token {
@ -2847,16 +2868,6 @@ impl Parser {
spanned(lo, hi, bloc)
}
fn mk_ty_path(&self, i: ident) -> @Ty {
@Ty {
id: self.get_id(),
node: ty_path(
ident_to_path(*self.last_span, i),
self.get_id()),
span: *self.last_span,
}
}
fn parse_optional_purity(&self) -> ast::purity {
if self.eat_keyword(keywords::Pure) {
self.obsolete(*self.last_span, ObsoletePurity);
@ -2921,13 +2932,8 @@ impl Parser {
_ => break,
}
if self.eat(&token::BINOP(token::PLUS)) {
loop;
}
if is_ident_or_path(self.token) {
self.obsolete(*self.span,
ObsoleteTraitBoundSeparator);
if !self.eat(&token::BINOP(token::PLUS)) {
break;
}
}
@ -3284,14 +3290,19 @@ impl Parser {
let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) {
// New-style trait. Reinterpret the type as a trait.
let opt_trait_ref = match ty.node {
ty_path(path, node_id) => {
ty_path(path, @opt_vec::Empty, node_id) => {
Some(@trait_ref {
path: path,
ref_id: node_id
})
}
ty_path(*) => {
self.span_err(ty.span,
"bounded traits are only valid in type position");
None
}
_ => {
self.span_err(*self.span, "not a trait");
self.span_err(ty.span, "not a trait");
None
}
};

View File

@ -422,7 +422,7 @@ pub fn print_type(s: @ps, ty: @ast::Ty) {
f.purity, f.onceness, &f.decl, None,
Some(&generics), None);
}
ast::ty_path(path, _) => print_path(s, path, false),
ast::ty_path(path, bounds, _) => print_bounded_path(s, path, bounds),
ast::ty_fixed_length_vec(ref mt, v) => {
word(s.s, "[");
match mt.mutbl {
@ -1483,7 +1483,8 @@ pub fn print_for_decl(s: @ps, loc: @ast::local, coll: @ast::expr) {
print_expr(s, coll);
}
pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
fn print_path_(s: @ps, path: @ast::Path, colons_before_params: bool,
opt_bounds: Option<@OptVec<ast::TyParamBound>>) {
maybe_print_comment(s, path.span.lo);
if path.global { word(s.s, "::"); }
let mut first = true;
@ -1491,6 +1492,9 @@ pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
if first { first = false; } else { word(s.s, "::"); }
print_ident(s, *id);
}
do opt_bounds.map_consume |bounds| {
print_bounds(s, bounds);
};
if path.rp.is_some() || !path.types.is_empty() {
if colons_before_params { word(s.s, "::"); }
@ -1511,6 +1515,15 @@ pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
}
}
pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
print_path_(s, path, colons_before_params, None)
}
pub fn print_bounded_path(s: @ps, path: @ast::Path,
bounds: @OptVec<ast::TyParamBound>) {
print_path_(s, path, false, Some(bounds))
}
pub fn print_irrefutable_pat(s: @ps, pat: @ast::pat) {
print_pat(s, pat, false)
}

View File

@ -247,13 +247,17 @@ pub fn visit_ty<E: Copy>(t: @Ty, (e, v): (E, vt<E>)) {
},
ty_closure(ref f) => {
for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); }
(v.visit_ty)(f.decl.output, (e, v));
(v.visit_ty)(f.decl.output, (copy e, v));
visit_ty_param_bounds(&f.bounds, (e, v));
},
ty_bare_fn(ref f) => {
for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); }
(v.visit_ty)(f.decl.output, (e, v));
},
ty_path(p, _) => visit_path(p, (e, v)),
ty_path(p, bounds, _) => {
visit_path(p, (copy e, v));
visit_ty_param_bounds(bounds, (e, v));
},
ty_fixed_length_vec(ref mt, ex) => {
(v.visit_ty)(mt.ty, (copy e, v));
(v.visit_expr)(ex, (copy e, v));
@ -328,7 +332,7 @@ pub fn visit_foreign_item<E: Copy>(ni: @foreign_item, (e, v): (E, vt<E>)) {
}
}
pub fn visit_ty_param_bounds<E: Copy>(bounds: @OptVec<TyParamBound>,
pub fn visit_ty_param_bounds<E: Copy>(bounds: &OptVec<TyParamBound>,
(e, v): (E, vt<E>)) {
for bounds.each |bound| {
match *bound {

View File

@ -58,5 +58,5 @@ fn cat(in_x : uint, in_y : int, in_name: ~str) -> cat {
fn main() {
let nyan : @noisy = @cat(0, 2, ~"nyan") as @noisy;
nyan.eat(); //~ ERROR type `@noisy` does not implement any method in scope named `eat`
nyan.eat(); //~ ERROR does not implement any method in scope named `eat`
}

View File

@ -0,0 +1,20 @@
// Copyright 2013 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.
struct X {
field: @fn:Copy(),
}
fn foo(blk: @fn()) -> X {
return X { field: blk }; //~ ERROR expected bounds `Copy` but found no bounds
}
fn main() {
}

View File

@ -0,0 +1,26 @@
// Copyright 2013 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 std::comm;
// If this were legal you could use it to copy captured noncopyables.
// Issue (#2828)
fn foo(blk: ~fn:Copy()) {
blk();
}
fn main() {
let (p,c) = comm::stream();
do foo {
c.send(()); //~ ERROR does not fulfill `Copy`
}
p.recv();
}

View File

@ -0,0 +1,21 @@
// Copyright 2013 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.
fn bar(blk: &fn:'static()) {
}
fn foo(x: &()) {
do bar {
let _ = x; //~ ERROR does not fulfill `'static`
}
}
fn main() {
}

View File

@ -1,3 +1,4 @@
fn take_any(_: &fn()) {
}
@ -7,6 +8,9 @@ fn take_copyable(_: &fn:Copy()) {
fn take_copyable_owned(_: &fn:Copy+Owned()) {
}
fn take_const_owned(_: &fn:Const+Owned()) {
}
fn give_any(f: &fn()) {
take_any(f);
take_copyable(f); //~ ERROR expected bounds `Copy` but found no bounds
@ -29,6 +33,7 @@ fn give_copyable_owned(f: &fn:Copy+Owned()) {
take_any(f);
take_copyable(f);
take_copyable_owned(f);
take_const_owned(f); //~ ERROR expected bounds `Owned+Const` but found bounds `Copy+Owned`
}
fn main() {}
fn main() {}

View File

@ -13,5 +13,5 @@ extern fn f() {
fn main() {
// extern functions are *u8 types
let _x: &fn() = f; //~ ERROR mismatched types: expected `&fn()` but found `*u8`
let _x: &fn() = f; //~ ERROR found `*u8`
}

View File

@ -10,7 +10,7 @@
fn foopy() {}
static f: &'static fn() = foopy; //~ ERROR mismatched types: expected `&'static fn()`
static f: &'static fn() = foopy; //~ ERROR found extern fn
fn main () {
f();

View File

@ -16,8 +16,8 @@ pub enum TraitWrapper {
fn get_tw_map<'lt>(tw: &'lt TraitWrapper) -> &'lt MyTrait {
match *tw {
A(~ref map) => map, //~ ERROR mismatched types: expected `~MyTrait` but found a ~-box pattern
A(~ref map) => map, //~ ERROR found a ~-box pattern
}
}
pub fn main() {}
pub fn main() {}

View File

@ -17,5 +17,5 @@ fn main() {
let x: @Map<~str, ~str> = @HashMap::new::<~str, ~str>() as
@Map<~str, ~str>;
let y: @Map<uint, ~str> = @x;
//~^ ERROR mismatched types: expected `@std::container::Map<uint,~str>`
//~^ ERROR expected trait std::container::Map but found @-ptr
}

View File

@ -13,7 +13,7 @@
fn foo(f: &fn()) { f() }
fn main() {
~"" || 42; //~ ERROR binary operation || cannot be applied to type `~str`
foo || {}; //~ ERROR binary operation || cannot be applied to type `extern "Rust" fn(&fn())`
~"" || 42; //~ ERROR binary operation || cannot be applied to type
foo || {}; //~ ERROR binary operation || cannot be applied to type
//~^ NOTE did you forget the `do` keyword for the call?
}

View File

@ -0,0 +1,28 @@
// Copyright 2013 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.
trait Foo {
}
fn a(_x: ~Foo:Owned) {
}
fn b(_x: ~Foo:Owned+Copy) {
}
fn c(x: ~Foo:Const+Owned) {
b(x); //~ ERROR expected bounds `Copy+Owned`
}
fn d(x: ~Foo) {
a(x); //~ ERROR found no bounds
}
fn main() { }

View File

@ -0,0 +1,19 @@
// Copyright 2013 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.
trait Foo {
}
// This should emit the less confusing error, not the more confusing one.
fn foo(_x: Foo:Owned) { //~ERROR reference to trait `Foo` where a type is expected
}
fn main() { }

View File

@ -0,0 +1,19 @@
// Copyright 2013 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.
trait Foo {
}
struct Bar;
impl Foo:Owned for Bar { //~ ERROR bounded traits are only valid in type position
}
fn main() { }

View File

@ -0,0 +1,15 @@
// Copyright 2013 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.
struct Foo;
fn foo(_x: ~Foo:Owned) { } //~ ERROR kind bounds can only be used on trait types
fn main() { }

View File

@ -0,0 +1,23 @@
// Copyright 2013 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 std::comm;
fn foo(blk: ~fn:Owned()) {
blk();
}
fn main() {
let (p,c) = comm::stream();
do foo {
c.send(());
}
p.recv();
}

View File

@ -0,0 +1,25 @@
// Copyright 2013 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.
// xfail-pretty
// Tests correct copying of heap closures' environments.
fn foo(x: ~fn:Copy()) -> (~fn(), ~fn()) {
(copy x, x)
}
fn main() {
let v = ~[~[1,2,3],~[4,5,6]]; // shouldn't get double-freed
let (f1,f2) = do foo {
assert!(v.len() == 2);
};
f1();
f2();
}

View File

@ -0,0 +1,28 @@
// Copyright 2013 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.
// xfail-pretty
// Tests correct copying of heap closures' environments.
fn bar<T: Copy>(x: T) -> (T, T) {
(copy x, x)
}
fn foo(x: ~fn:Copy()) -> (~fn(), ~fn()) {
bar(x)
}
fn main() {
let v = ~[~[1,2,3],~[4,5,6]]; // shouldn't get double-freed
let (f1,f2) = do foo {
assert!(v.len() == 2);
};
f1();
f2();
}

View File

@ -0,0 +1,28 @@
// Copyright 2013 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.
trait Foo {
}
fn a(_x: ~Foo) {
}
fn b(_x: ~Foo:Owned) {
}
fn c(x: ~Foo:Const+Owned) {
a(x);
}
fn d(x: ~Foo:Owned+Copy) {
b(x);
}
fn main() { }