diff options
| author | bors <bors@rust-lang.org> | 2013-06-23 14:58:58 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-06-23 14:58:58 -0700 |
| commit | f82756180bec5a8405e1fc6ee1b22949db24861f (patch) | |
| tree | 76bc5be01aa0605cb212ea1b0556cd48f69facdc | |
| parent | cb58b19f023f95614e4a2bc3c812614d0938a9f2 (diff) | |
| parent | ba3f43e506de97109788e4a96df438b3c89f5e49 (diff) | |
| download | rust-f82756180bec5a8405e1fc6ee1b22949db24861f.tar.gz rust-f82756180bec5a8405e1fc6ee1b22949db24861f.zip | |
auto merge of #7314 : bblum/rust/trait-bounds2, r=nikomatsakis
Fixed a merge conflict, some tests, some bitrotting, etc., from #7248.
56 files changed, 583 insertions, 180 deletions
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 <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 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<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. - } -} 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<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())) } 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<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()); 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<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)) + } } } } 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<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 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<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)); 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::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 { 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::<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 } }; 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<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) } 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<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 { 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 <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() { +} 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 <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(); +} 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 <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() { +} 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<uint, ~str> = @x; - //~^ ERROR mismatched types: expected `@std::container::Map<uint,~str>` + //~^ 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 <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() { } 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 <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() { } 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 <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() { } 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 <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() { } 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 <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(); +} 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 <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(); +} 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 <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(); +} 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 <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() { } |
