diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index 5c08fdfecca..625424ac870 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -2,7 +2,7 @@ " Language: Rust " Maintainer: Patrick Walton " Maintainer: Ben Blum -" 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 "\(); -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 diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 826b64b9a64..94cad18ece2 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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)); } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index cf2a92b291f..b53bdcc9bbe 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -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); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 5f854b1f24e..dd62a8e11cb 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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) => { diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 6492850b668..7f7a81fa974 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -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)) { 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)) { // 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)) { 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)) { 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)) { fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt)) { 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)) { 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. - } -} diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index d29c027f3c2..821aed731c2 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -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, diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 4b6cedd114c..0e6d8617ba4 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -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| { diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index fbea5d4adf2..eed0b12b9e1 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -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) => { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 2eadad7d8d1..11eecf82bac 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -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) }, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 58f04ab3b2e..7d86f743a8e 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -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); } diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index e9febb51005..d8ba524b2bd 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -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])); diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index fd382a869df..4f4bbf84a72 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -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, diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index 5cb52d2a057..6a40c1f75e9 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -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 diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index cb68a2af92b..316eb6893f2 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -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) => { diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 448ded6b70f..3699314a1d2 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -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); diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 49cb3bd51dd..f2446d1a115 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -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() { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a367cf4c430..90cd8a8665e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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 { 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())) } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 660ff83b5b3..3b651451db8 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -277,7 +277,10 @@ pub fn ast_ty_to_ty( } 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( 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( 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()); diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 33d1377d000..60855e6cd96 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -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); diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index ac89c48a29b..69d4d82d15f 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -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); diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 5ce95e23e2c..bd78e9cc5fb 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -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 || diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index bf935d92c75..7ad27077cd8 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -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 { diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 773860ffc64..884f72b57f0 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -508,13 +508,15 @@ pub fn super_tys( } } - (&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)) + } } } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 2e83acfa9f4..1bfe452f25e 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -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} } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index c730e74c903..e25267f4441 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1758433aa73..2e3d557daa9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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, 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 diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 34c247662a4..24cf5662a36 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -473,7 +473,7 @@ pub fn id_visitor(vfn: @fn(node_id, T)) -> visit::vt { 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)); diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index dc31a248065..b6399794477 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -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::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::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::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 { diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index dca1b7bbd59..981b28afd02 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -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, diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index 3b39cb691a6..d28613f52fa 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -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() { diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index 8478a827e85..a20528082ab 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -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(¶ms))) + .add_tys(cx.ty_vars_global(¶ms)), @opt_vec::Empty) } fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item { diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs index d00f1fd7746..87aaf7781fa 100644 --- a/src/libsyntax/ext/pipes/proto.rs +++ b/src/libsyntax/ext/pipes/proto.rs @@ -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 diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 568324bc599..4bd2c0a3de1 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -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), diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 5edd2ec4d47..0c5731c8b29 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -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( diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index bb315bf2933..19b4d254580 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -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 diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 753c69b23d6..f2443f9e533 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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:: - 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 + 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:: + 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) { + 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 } }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8e47df51010..fa22b7ceb71 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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>) { 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) { + print_path_(s, path, false, Some(bounds)) +} + pub fn print_irrefutable_pat(s: @ps, pat: @ast::pat) { print_pat(s, pat, false) } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index e7afeb12a61..5aa38c0348c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -247,13 +247,17 @@ pub fn visit_ty(t: @Ty, (e, v): (E, vt)) { }, 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(ni: @foreign_item, (e, v): (E, vt)) { } } -pub fn visit_ty_param_bounds(bounds: @OptVec, +pub fn visit_ty_param_bounds(bounds: &OptVec, (e, v): (E, vt)) { for bounds.each |bound| { match *bound { diff --git a/src/test/compile-fail/class-cast-to-trait.rs b/src/test/compile-fail/class-cast-to-trait.rs index 7f7c58a60df..0d1582bf857 100644 --- a/src/test/compile-fail/class-cast-to-trait.rs +++ b/src/test/compile-fail/class-cast-to-trait.rs @@ -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` } diff --git a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs new file mode 100644 index 00000000000..c3c8467233c --- /dev/null +++ b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs @@ -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 or the MIT license +// , 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() { +} diff --git a/src/test/compile-fail/closure-bounds-copy-cant-capture-noncopyable.rs b/src/test/compile-fail/closure-bounds-copy-cant-capture-noncopyable.rs new file mode 100644 index 00000000000..0b11da14e71 --- /dev/null +++ b/src/test/compile-fail/closure-bounds-copy-cant-capture-noncopyable.rs @@ -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 or the MIT license +// , 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(); +} diff --git a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs new file mode 100644 index 00000000000..cac1244a560 --- /dev/null +++ b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs @@ -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 or the MIT license +// , 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() { +} diff --git a/src/test/compile-fail/closure-bounds-subtype.rs b/src/test/compile-fail/closure-bounds-subtype.rs index ebec113cedc..a975349e730 100644 --- a/src/test/compile-fail/closure-bounds-subtype.rs +++ b/src/test/compile-fail/closure-bounds-subtype.rs @@ -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() {} \ No newline at end of file +fn main() {} diff --git a/src/test/compile-fail/extern-wrong-value-type.rs b/src/test/compile-fail/extern-wrong-value-type.rs index 4daa7f71adf..fbb0f6e46a1 100644 --- a/src/test/compile-fail/extern-wrong-value-type.rs +++ b/src/test/compile-fail/extern-wrong-value-type.rs @@ -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` } diff --git a/src/test/compile-fail/issue-4523.rs b/src/test/compile-fail/issue-4523.rs index 6d072ce210e..332db60c836 100644 --- a/src/test/compile-fail/issue-4523.rs +++ b/src/test/compile-fail/issue-4523.rs @@ -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(); diff --git a/src/test/compile-fail/issue-4972.rs b/src/test/compile-fail/issue-4972.rs index bd74199dabd..fcd15a21219 100644 --- a/src/test/compile-fail/issue-4972.rs +++ b/src/test/compile-fail/issue-4972.rs @@ -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() {} \ No newline at end of file +pub fn main() {} diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs index f5d6e95fe2f..f6fd8e29a4f 100644 --- a/src/test/compile-fail/map-types.rs +++ b/src/test/compile-fail/map-types.rs @@ -17,5 +17,5 @@ fn main() { let x: @Map<~str, ~str> = @HashMap::new::<~str, ~str>() as @Map<~str, ~str>; let y: @Map = @x; - //~^ ERROR mismatched types: expected `@std::container::Map` + //~^ ERROR expected trait std::container::Map but found @-ptr } diff --git a/src/test/compile-fail/missing-do.rs b/src/test/compile-fail/missing-do.rs index b5789d73771..e6a7698d0f0 100644 --- a/src/test/compile-fail/missing-do.rs +++ b/src/test/compile-fail/missing-do.rs @@ -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? } diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs new file mode 100644 index 00000000000..88c2d491747 --- /dev/null +++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs new file mode 100644 index 00000000000..e9cc9575003 --- /dev/null +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/compile-fail/trait-bounds-not-on-impl.rs b/src/test/compile-fail/trait-bounds-not-on-impl.rs new file mode 100644 index 00000000000..ac88b21b456 --- /dev/null +++ b/src/test/compile-fail/trait-bounds-not-on-impl.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/compile-fail/trait-bounds-not-on-struct.rs b/src/test/compile-fail/trait-bounds-not-on-struct.rs new file mode 100644 index 00000000000..45bb5e29a88 --- /dev/null +++ b/src/test/compile-fail/trait-bounds-not-on-struct.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/run-pass/closure-bounds-can-capture-chan.rs b/src/test/run-pass/closure-bounds-can-capture-chan.rs new file mode 100644 index 00000000000..26bea0e5141 --- /dev/null +++ b/src/test/run-pass/closure-bounds-can-capture-chan.rs @@ -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 or the MIT license +// , 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(); +} diff --git a/src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs b/src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs new file mode 100644 index 00000000000..f39c914916f --- /dev/null +++ b/src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs @@ -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 or the MIT license +// , 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(); +} diff --git a/src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs b/src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs new file mode 100644 index 00000000000..2fdce4e5c7c --- /dev/null +++ b/src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs @@ -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 or the MIT license +// , 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(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(); +} diff --git a/src/test/run-pass/trait-bounds-basic.rs b/src/test/run-pass/trait-bounds-basic.rs new file mode 100644 index 00000000000..b9251c038af --- /dev/null +++ b/src/test/run-pass/trait-bounds-basic.rs @@ -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 or the MIT license +// , 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() { }