diff --git a/src/libcargo/cargo.rc b/src/libcargo/cargo.rc index af86911426f..79bf85021d8 100644 --- a/src/libcargo/cargo.rc +++ b/src/libcargo/cargo.rc @@ -457,7 +457,7 @@ pub fn parse_source(name: ~str, j: &json::Json) -> @Source { } match *j { - json::Object(j) => { + json::Object(ref j) => { let mut url = match j.find(&~"url") { Some(&json::String(u)) => copy u, _ => die!(~"needed 'url' field in source") @@ -563,7 +563,7 @@ pub fn load_one_source_package(src: @Source, p: &json::Object) { let mut tags = ~[]; match p.find(&~"tags") { - Some(&json::List(js)) => { + Some(&json::List(ref js)) => { for js.each |j| { match *j { json::String(ref j) => tags.grow(1u, j), @@ -635,11 +635,11 @@ pub fn load_source_packages(c: &Cargo, src: @Source) { if !os::path_exists(&pkgfile) { return; } let pkgstr = io::read_whole_file_str(&pkgfile); match json::from_str(pkgstr.get()) { - Ok(json::List(js)) => { + Ok(json::List(ref js)) => { for js.each |j| { match *j { - json::Object(p) => { - load_one_source_package(src, p); + json::Object(ref p) => { + load_one_source_package(src, *p); } _ => { warn(~"malformed source json: " + src.name + diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 9b25f92ede2..47e68401485 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -220,6 +220,16 @@ pub pure fn connect(v: &[~str], sep: &str) -> ~str { s } +/// Concatenate a vector of strings, placing a given separator between each +pub pure fn connect_slices(v: &[&str], sep: &str) -> ~str { + let mut s = ~"", first = true; + for vec::each(v) |ss| { + if first { first = false; } else { unsafe { push_str(&mut s, sep); } } + unsafe { push_str(&mut s, *ss) }; + } + s +} + /// Given a string, make a new string with repeated copies of it pub pure fn repeat(ss: &str, nn: uint) -> ~str { let mut acc = ~""; @@ -2667,6 +2677,17 @@ mod tests { t(~[~"hi"], ~" ", ~"hi"); } + #[test] + fn test_connect_slices() { + fn t(v: &[&str], sep: &str, s: &str) { + assert connect_slices(v, sep) == s.to_str(); + } + t(["you", "know", "I'm", "no", "good"], + " ", "you know I'm no good"); + t([], " ", ""); + t(["hi"], " ", "hi"); + } + #[test] fn test_repeat() { assert repeat(~"x", 4) == ~"xxxx"; diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 35d5595fefd..a949b40bf75 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -15,7 +15,6 @@ use middle::freevars; use middle::lint::{non_implicitly_copyable_typarams, implicit_copies}; use middle::liveness; use middle::pat_util; -use middle::ty::{Kind, kind_copyable, kind_noncopyable, kind_const}; use middle::ty; use middle::typeck; use middle; @@ -61,26 +60,6 @@ use syntax::{visit, ast_util}; pub const try_adding: &str = "Try adding a move"; -pub fn kind_to_str(k: Kind) -> ~str { - let mut kinds = ~[]; - - if ty::kind_lteq(kind_const(), k) { - kinds.push(~"const"); - } - - if ty::kind_can_be_copied(k) { - kinds.push(~"copy"); - } - - if ty::kind_can_be_sent(k) { - kinds.push(~"owned"); - } else if ty::kind_is_durable(k) { - kinds.push(~"&static"); - } - - str::connect(kinds, ~" ") -} - pub type rval_map = HashMap; pub type ctx = { @@ -119,11 +98,11 @@ type check_fn = fn@(ctx, @freevar_entry); // closure. fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) { fn check_for_uniq(cx: ctx, fv: @freevar_entry) { - // all captured data must be sendable, regardless of whether it is - // moved in or copied in. Note that send implies owned. + // 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); - if !check_send(cx, var_t, fv.span) { return; } + 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); @@ -281,30 +260,54 @@ fn check_ty(aty: @Ty, cx: ctx, v: visit::vt) { visit::visit_ty(aty, cx, v); } -pub fn check_bounds(cx: ctx, id: node_id, sp: span, - ty: ty::t, bounds: ty::param_bounds) { - let kind = ty::type_kind(cx.tcx, ty); - let p_kind = ty::param_bounds_to_kind(bounds); - if !ty::kind_lteq(p_kind, kind) { - // If the only reason the kind check fails is because the - // argument type isn't implicitly copyable, consult the warning - // settings to figure out what to do. - let implicit = ty::kind_implicitly_copyable() - ty::kind_copyable(); - if ty::kind_lteq(p_kind, kind | implicit) { - cx.tcx.sess.span_lint( - non_implicitly_copyable_typarams, - id, cx.current_item, sp, - ~"instantiating copy type parameter with a \ - not implicitly copyable type"); - } else { - cx.tcx.sess.span_err( - sp, - ~"instantiating a type parameter with an incompatible type " + - ~"(needs `" + kind_to_str(p_kind) + - ~"`, got `" + kind_to_str(kind) + - ~"`, missing `" + kind_to_str(p_kind - kind) + ~"`)"); +pub fn check_bounds(cx: ctx, + _type_parameter_id: node_id, + sp: span, + ty: ty::t, + bounds: ty::param_bounds) +{ + let kind = ty::type_contents(cx.tcx, ty); + let mut missing = ~[]; + for bounds.each |bound| { + match *bound { + ty::bound_trait(_) => { + /* Not our job, checking in typeck */ + } + + ty::bound_copy => { + if !kind.is_copy(cx.tcx) { + missing.push("Copy"); + } + } + + ty::bound_durable => { + if !kind.is_durable(cx.tcx) { + missing.push("&static"); + } + } + + ty::bound_owned => { + if !kind.is_owned(cx.tcx) { + missing.push("Owned"); + } + } + + ty::bound_const => { + if !kind.is_const(cx.tcx) { + missing.push("Const"); + } + } } } + + if !missing.is_empty() { + cx.tcx.sess.span_err( + sp, + fmt!("instantiating a type parameter with an incompatible type \ + `%s`, which does not fulfill `%s`", + ty_to_str(cx.tcx, ty), + str::connect_slices(missing, " "))); + } } fn is_nullary_variant(cx: ctx, ex: @expr) -> bool { @@ -342,16 +345,22 @@ fn check_imm_free_var(cx: ctx, def: def, sp: span) { } fn check_copy(cx: ctx, ty: ty::t, sp: span, reason: &str) { - let k = ty::type_kind(cx.tcx, ty); - if !ty::kind_can_be_copied(k) { - cx.tcx.sess.span_err(sp, ~"copying a noncopyable value"); + debug!("type_contents(%s)=%s", + ty_to_str(cx.tcx, ty), + ty::type_contents(cx.tcx, ty).to_str()); + if !ty::type_is_copyable(cx.tcx, ty) { + cx.tcx.sess.span_err( + sp, fmt!("copying a value of non-copyable type `%s`", + ty_to_str(cx.tcx, ty))); cx.tcx.sess.span_note(sp, fmt!("%s", reason)); } } -pub fn check_send(cx: ctx, ty: ty::t, sp: span) -> bool { - if !ty::kind_can_be_sent(ty::type_kind(cx.tcx, ty)) { - cx.tcx.sess.span_err(sp, ~"not a sendable value"); +pub fn check_owned(cx: ctx, ty: ty::t, sp: span) -> bool { + if !ty::type_is_owned(cx.tcx, ty) { + cx.tcx.sess.span_err( + sp, fmt!("value has non-owned type `%s`", + ty_to_str(cx.tcx, ty))); false } else { true @@ -360,7 +369,7 @@ pub fn check_send(cx: ctx, ty: ty::t, sp: span) -> bool { // note: also used from middle::typeck::regionck! pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool { - if !ty::kind_is_durable(ty::type_kind(tcx, ty)) { + if !ty::type_is_durable(tcx, ty) { match ty::get(ty).sty { ty::ty_param(*) => { tcx.sess.span_err(sp, ~"value may contain borrowed \ @@ -403,8 +412,8 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool { pub fn check_cast_for_escaping_regions( cx: ctx, source: @expr, - target: @expr) { - + target: @expr) +{ // Determine what type we are casting to; if it is not an trait, then no // worries. let target_ty = ty::expr_ty(cx.tcx, target); @@ -450,13 +459,9 @@ pub fn check_kind_bounds_of_cast(cx: ctx, source: @expr, target: @expr) { match ty::get(target_ty).sty { ty::ty_trait(_, _, ty::vstore_uniq) => { let source_ty = ty::expr_ty(cx.tcx, source); - let source_kind = ty::type_kind(cx.tcx, source_ty); - if !ty::kind_can_be_copied(source_kind) { - cx.tcx.sess.span_err(target.span, - ~"uniquely-owned trait objects must be copyable"); - } - if !ty::kind_can_be_sent(source_kind) { - cx.tcx.sess.span_err(target.span, + if !ty::type_is_owned(cx.tcx, source_ty) { + cx.tcx.sess.span_err( + target.span, ~"uniquely-owned trait objects must be sendable"); } } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 51bbdfdc19c..843b01bdb35 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -925,8 +925,8 @@ fn check_fn_deprecated_modes(tcx: ty::ctxt, fn_ty: ty::t, decl: ast::fn_decl, ast::infer(_) => { if tcx.legacy_modes { - let kind = ty::type_kind(tcx, arg_ty.ty); - if !ty::kind_is_safe_for_default_mode(kind) { + let kind = ty::type_contents(tcx, arg_ty.ty); + if !kind.is_safe_for_default_mode(tcx) { tcx.sess.span_lint( deprecated_mode, id, id, span, diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index aaa3156e27c..0d32bb7ecf6 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -374,7 +374,7 @@ impl VisitContext { * not implicitly copyable. */ - let result = if ty::type_implicitly_moves(self.tcx, ty) { + let result = if ty::type_moves_by_default(self.tcx, ty) { MoveInWhole } else { Read @@ -495,7 +495,7 @@ impl VisitContext { // moves-by-default: let consume_with = with_fields.any(|tf| { !fields.any(|f| f.node.ident == tf.ident) && - ty::type_implicitly_moves(self.tcx, tf.mt.ty) + ty::type_moves_by_default(self.tcx, tf.mt.ty) }); if consume_with { @@ -830,7 +830,7 @@ impl VisitContext { let fvar_ty = ty::node_id_to_type(self.tcx, fvar_def_id); debug!("fvar_def_id=%? fvar_ty=%s", fvar_def_id, ppaux::ty_to_str(self.tcx, fvar_ty)); - let mode = if ty::type_implicitly_moves(self.tcx, fvar_ty) { + let mode = if ty::type_moves_by_default(self.tcx, fvar_ty) { CapMove } else { CapCopy diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 6455c5da98d..2a43fc8a601 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -26,6 +26,7 @@ use session::Session; use util::ppaux::{note_and_explain_region, bound_region_to_str}; use util::ppaux::{region_to_str, explain_region, vstore_to_str}; use util::ppaux::{ty_to_str, tys_to_str}; +use util::common::{indenter}; use core::cast; use core::cmp; @@ -39,6 +40,7 @@ use core::result; use core::to_bytes; use core::uint; use core::vec; +use core::hashmap::linear::LinearMap; use std::oldmap::HashMap; use std::{oldmap, oldsmallintmap}; use syntax::ast::*; @@ -259,7 +261,7 @@ struct ctxt_ { short_names_cache: HashMap, needs_drop_cache: HashMap, needs_unwind_cleanup_cache: HashMap, - kind_cache: HashMap, + mut tc_cache: LinearMap, ast_ty_to_ty_cache: HashMap<@ast::Ty, ast_ty_to_ty_cache_entry>, enum_var_cache: HashMap, trait_method_cache: HashMap, @@ -737,37 +739,6 @@ pub impl RegionVid : to_bytes::IterBytes { } } -pub fn kind_to_param_bounds(kind: Kind) -> param_bounds { - let mut bounds = ~[]; - if kind_can_be_copied(kind) { bounds.push(bound_copy); } - if kind_can_be_sent(kind) { bounds.push(bound_owned); } - else if kind_is_durable(kind) { bounds.push(bound_durable); } - if kind_is_const(kind) { bounds.push(bound_const); } - return @bounds; -} - -pub fn param_bounds_to_kind(bounds: param_bounds) -> Kind { - let mut kind = kind_noncopyable(); - for vec::each(*bounds) |bound| { - match *bound { - bound_copy => { - kind = raise_kind(kind, kind_implicitly_copyable()); - } - bound_durable => { - kind = raise_kind(kind, kind_durable()); - } - bound_owned => { - kind = raise_kind(kind, kind_owned_only() | kind_durable()); - } - bound_const => { - kind = raise_kind(kind, kind_const()); - } - bound_trait(_) => () - } - } - kind -} - /// A polytype. /// /// - `bounds`: The list of bounds for each type parameter. The length of the @@ -851,7 +822,7 @@ pub fn mk_ctxt(s: session::Session, short_names_cache: new_ty_hash(), needs_drop_cache: new_ty_hash(), needs_unwind_cleanup_cache: new_ty_hash(), - kind_cache: new_ty_hash(), + tc_cache: LinearMap::new(), ast_ty_to_ty_cache: HashMap(), enum_var_cache: HashMap(), trait_method_cache: HashMap(), @@ -1507,10 +1478,6 @@ pub fn type_is_structural(ty: t) -> bool { } } -pub fn type_is_copyable(cx: ctxt, ty: t) -> bool { - return kind_can_be_copied(type_kind(cx, ty)); -} - pub fn type_is_sequence(ty: t) -> bool { match get(ty).sty { ty_estr(_) | ty_evec(_, _) => true, @@ -1777,467 +1744,491 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t, return needs_unwind_cleanup; } -pub enum Kind { kind_(u32) } - -/// can be copied (implicitly or explicitly) -const KIND_MASK_COPY : u32 = 0b000000000000000000000000001_u32; - -/// no shared box, borrowed ptr (must imply DURABLE) -const KIND_MASK_OWNED : u32 = 0b000000000000000000000000010_u32; - -/// is durable (no borrowed ptrs) -const KIND_MASK_DURABLE : u32 = 0b000000000000000000000000100_u32; - -/// is deeply immutable -const KIND_MASK_CONST : u32 = 0b000000000000000000000001000_u32; - -/// can be implicitly copied (must imply COPY) -const KIND_MASK_IMPLICIT : u32 = 0b000000000000000000000010000_u32; - -/// safe for default mode (subset of KIND_MASK_IMPLICIT) -const KIND_MASK_DEFAULT_MODE : u32 = 0b000000000000000000000100000_u32; - -pub fn kind_noncopyable() -> Kind { - kind_(0u32) +/** + * Type contents is how the type checker reasons about kinds. + * They track what kinds of things are found within a type. You can + * think of them as kind of an "anti-kind". They track the kinds of values + * and thinks that are contained in types. Having a larger contents for + * a type tends to rule that type *out* from various kinds. For example, + * a type that contains a borrowed pointer is not sendable. + * + * The reason we compute type contents and not kinds is that it is + * easier for me (nmatsakis) to think about what is contained within + * a type than to think about what is *not* contained within a type. + */ +pub struct TypeContents { + bits: u32 } -pub fn kind_copyable() -> Kind { - kind_(KIND_MASK_COPY) -} +pub impl TypeContents { + fn intersects(&self, tc: TypeContents) -> bool { + (self.bits & tc.bits) != 0 + } -pub fn kind_implicitly_copyable() -> Kind { - kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY) -} + fn is_copy(&self, cx: ctxt) -> bool { + !self.intersects(TypeContents::noncopyable(cx)) + } -fn kind_safe_for_default_mode() -> Kind { - // similar to implicit copy, but always includes vectors and strings - kind_(KIND_MASK_DEFAULT_MODE | KIND_MASK_IMPLICIT | KIND_MASK_COPY) -} + static fn noncopyable(_cx: ctxt) -> TypeContents { + TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_OWNED_CLOSURE + + TC_EMPTY_ENUM + } -fn kind_implicitly_sendable() -> Kind { - kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY | KIND_MASK_OWNED) -} + fn is_durable(&self, cx: ctxt) -> bool { + !self.intersects(TypeContents::nondurable(cx)) + } -fn kind_safe_for_default_mode_send() -> Kind { - // similar to implicit copy, but always includes vectors and strings - kind_(KIND_MASK_DEFAULT_MODE | KIND_MASK_IMPLICIT | - KIND_MASK_COPY | KIND_MASK_OWNED) -} + static fn nondurable(_cx: ctxt) -> TypeContents { + TC_BORROWED_POINTER + } + fn is_owned(&self, cx: ctxt) -> bool { + !self.intersects(TypeContents::nonowned(cx)) + } -fn kind_owned_copy() -> Kind { - kind_(KIND_MASK_COPY | KIND_MASK_OWNED) -} + static fn nonowned(_cx: ctxt) -> TypeContents { + TC_MANAGED + TC_BORROWED_POINTER + } -fn kind_owned_only() -> Kind { - kind_(KIND_MASK_OWNED) -} + fn is_const(&self, cx: ctxt) -> bool { + !self.intersects(TypeContents::nonconst(cx)) + } -pub fn kind_const() -> Kind { - kind_(KIND_MASK_CONST) -} + static fn nonconst(_cx: ctxt) -> TypeContents { + TC_MUTABLE + } -fn kind_durable() -> Kind { - kind_(KIND_MASK_DURABLE) -} + fn moves_by_default(&self, cx: ctxt) -> bool { + self.intersects(TypeContents::nonimplicitly_copyable(cx)) + } -fn kind_top() -> Kind { - kind_(0xffffffffu32) -} + static fn nonimplicitly_copyable(cx: ctxt) -> TypeContents { + let base = TypeContents::noncopyable(cx) + TC_OWNED_POINTER; + if cx.vecs_implicitly_copyable {base} else {base + TC_OWNED_SLICE} + } -fn remove_const(k: Kind) -> Kind { - k - kind_const() -} + fn is_safe_for_default_mode(&self, cx: ctxt) -> bool { + !self.intersects(TypeContents::nondefault_mode(cx)) + } -fn remove_implicit(k: Kind) -> Kind { - k - kind_(KIND_MASK_IMPLICIT | KIND_MASK_DEFAULT_MODE) -} - -fn remove_owned(k: Kind) -> Kind { - k - kind_(KIND_MASK_OWNED) -} - -fn remove_durable_owned(k: Kind) -> Kind { - k - kind_(KIND_MASK_DURABLE) - kind_(KIND_MASK_OWNED) -} - -fn remove_copyable(k: Kind) -> Kind { - k - kind_(KIND_MASK_COPY | KIND_MASK_DEFAULT_MODE) -} - -impl Kind : ops::BitAnd { - pure fn bitand(&self, other: &Kind) -> Kind { - unsafe { - lower_kind(*self, *other) - } + static fn nondefault_mode(cx: ctxt) -> TypeContents { + let tc = TypeContents::nonimplicitly_copyable(cx); + tc + TC_BIG + TC_OWNED_SLICE // disregard cx.vecs_implicitly_copyable } } -impl Kind : ops::BitOr { - pure fn bitor(&self, other: &Kind) -> Kind { - unsafe { - raise_kind(*self, *other) - } +impl TypeContents : ops::Add { + pure fn add(&self, other: &TypeContents) -> TypeContents { + TypeContents {bits: self.bits | other.bits} } } -impl Kind : ops::Sub { - pure fn sub(&self, other: &Kind) -> Kind { - unsafe { - kind_(**self & !**other) - } +impl TypeContents : ops::Sub { + pure fn sub(&self, other: &TypeContents) -> TypeContents { + TypeContents {bits: self.bits & !other.bits} } } -// Using these query functions is preferable to direct comparison or matching -// against the kind constants, as we may modify the kind hierarchy in the -// future. -pub pure fn kind_can_be_implicitly_copied(k: Kind) -> bool { - *k & KIND_MASK_IMPLICIT == KIND_MASK_IMPLICIT -} - -pub pure fn kind_is_safe_for_default_mode(k: Kind) -> bool { - *k & KIND_MASK_DEFAULT_MODE == KIND_MASK_DEFAULT_MODE -} - -pub pure fn kind_can_be_copied(k: Kind) -> bool { - *k & KIND_MASK_COPY == KIND_MASK_COPY -} - -pub pure fn kind_can_be_sent(k: Kind) -> bool { - *k & KIND_MASK_OWNED == KIND_MASK_OWNED -} - -pub pure fn kind_is_durable(k: Kind) -> bool { - *k & KIND_MASK_DURABLE == KIND_MASK_DURABLE -} - -pure fn kind_is_const(k: Kind) -> bool { - *k & KIND_MASK_CONST == KIND_MASK_CONST -} - -fn closure_kind(cty: &ClosureTy) -> Kind { - let kind = match cty.sigil { - ast::BorrowedSigil => kind_implicitly_copyable(), - ast::ManagedSigil => kind_implicitly_copyable(), - ast::OwnedSigil => kind_owned_only() | kind_durable(), - }; - - let kind = match cty.region { - re_static => kind | kind_durable(), - _ => kind - kind_owned_only() - kind_durable() - }; - - match cty.onceness { - ast::Once => kind - kind_implicitly_copyable(), - ast::Many => kind +impl TypeContents : ToStr { + pure fn to_str(&self) -> ~str { + fmt!("TypeContents(%s)", u32::to_str_radix(self.bits, 2)) } } -pub fn kind_lteq(a: Kind, b: Kind) -> bool { - *a & *b == *a +/// Constant for a type containing nothing of interest. +const TC_NONE: TypeContents = TypeContents{bits:0b0000_00000000}; + +/// Contains a borrowed value with a lifetime other than static +const TC_BORROWED_POINTER: TypeContents = TypeContents{bits:0b0000_00000001}; + +/// Contains an owned pointer (~T) but not slice of some kind +const TC_OWNED_POINTER: TypeContents = TypeContents{bits:0b000000000010}; + +/// Contains an owned slice +const TC_OWNED_SLICE: TypeContents = TypeContents{bits:0b000000000100}; + +/// Contains a ~fn() or a ~Trait, which is non-copyable. +const TC_OWNED_CLOSURE: TypeContents = TypeContents{bits:0b000000001000}; + +/// Type with a destructor +const TC_DTOR: TypeContents = TypeContents{bits:0b000000010000}; + +/// Contains a managed value +const TC_MANAGED: TypeContents = TypeContents{bits:0b000000100000}; + +/// &mut with any region +const TC_BORROWED_MUT: TypeContents = TypeContents{bits:0b000001000000}; + +/// Mutable content, whether owned or by ref +const TC_MUTABLE: TypeContents = TypeContents{bits:0b000010000000}; + +/// Mutable content, whether owned or by ref +const TC_ONCE_CLOSURE: TypeContents = TypeContents{bits:0b000100000000}; + +/// Something we estimate to be "big" +const TC_BIG: TypeContents = TypeContents{bits:0b001000000000}; + +/// An enum with no variants. +const TC_EMPTY_ENUM: TypeContents = TypeContents{bits:0b010000000000}; + +/// All possible contents. +const TC_ALL: TypeContents = TypeContents{bits:0b011111111111}; + +pub fn type_is_copyable(cx: ctxt, t: ty::t) -> bool { + type_contents(cx, t).is_copy(cx) } -fn lower_kind(a: Kind, b: Kind) -> Kind { - kind_(*a & *b) +pub fn type_is_durable(cx: ctxt, t: ty::t) -> bool { + type_contents(cx, t).is_durable(cx) } -fn raise_kind(a: Kind, b: Kind) -> Kind { - kind_(*a | *b) +pub fn type_is_owned(cx: ctxt, t: ty::t) -> bool { + type_contents(cx, t).is_owned(cx) } -#[test] -fn test_kinds() { - // The kind "lattice" is defined by the subset operation on the - // set of permitted operations. - assert kind_lteq(kind_owned_copy(), kind_owned_copy()); - assert kind_lteq(kind_copyable(), kind_owned_copy()); - assert kind_lteq(kind_copyable(), kind_copyable()); - assert kind_lteq(kind_noncopyable(), kind_owned_copy()); - assert kind_lteq(kind_noncopyable(), kind_copyable()); - assert kind_lteq(kind_noncopyable(), kind_noncopyable()); - assert kind_lteq(kind_copyable(), kind_implicitly_copyable()); - assert kind_lteq(kind_copyable(), kind_implicitly_sendable()); - assert kind_lteq(kind_owned_copy(), kind_implicitly_sendable()); - assert !kind_lteq(kind_owned_copy(), kind_implicitly_copyable()); - assert !kind_lteq(kind_copyable(), kind_owned_only()); +pub fn type_is_const(cx: ctxt, t: ty::t) -> bool { + type_contents(cx, t).is_const(cx) } -// Return the most permissive kind that a composite object containing a field -// with the given mutability can have. -// This is used to prevent objects containing mutable state from being -// implicitly copied and to compute whether things have const kind. -fn mutability_kind(m: mutability) -> Kind { - match (m) { - m_mutbl => remove_const(remove_implicit(kind_top())), - m_const => remove_implicit(kind_top()), - m_imm => kind_top() - } -} - -fn mutable_type_kind(cx: ctxt, ty: mt) -> Kind { - lower_kind(mutability_kind(ty.mutbl), type_kind(cx, ty.ty)) -} - -pub fn type_kind(cx: ctxt, ty: t) -> Kind { - type_kind_ext(cx, ty, false) -} - -// If `allow_ty_var` is true, then this is a conservative assumption; we -// assume that type variables *do* have all kinds. -pub fn type_kind_ext(cx: ctxt, ty: t, allow_ty_var: bool) -> Kind { - match cx.kind_cache.find(&ty) { - Some(result) => return result, - None => {/* fall through */ } +pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { + let ty_id = type_id(ty); + match cx.tc_cache.find(&ty_id) { + Some(tc) => { return *tc; } + None => {} } - // Insert a default in case we loop back on self recursively. - cx.kind_cache.insert(ty, kind_top()); + let mut cache = LinearMap::new(); + let result = tc_ty(cx, ty, &mut cache); + cx.tc_cache.insert(ty_id, result); + return result; - let mut result = match /*bad*/copy get(ty).sty { - // Scalar and unique types are sendable, constant, and owned - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_bare_fn(_) | ty_ptr(_) => { - kind_safe_for_default_mode_send() | kind_const() | kind_durable() - } - - // Implicit copyability of strs is configurable - ty_estr(vstore_uniq) => { - if cx.vecs_implicitly_copyable { - kind_implicitly_sendable() | kind_const() | kind_durable() - } else { - kind_owned_copy() | kind_const() | kind_durable() + fn tc_ty(cx: ctxt, + ty: t, + cache: &mut LinearMap) -> TypeContents + { + // Subtle: Note that we are *not* using cx.tc_cache here but rather a + // private cache for this walk. This is needed in the case of cyclic + // types like: + // + // struct List { next: ~Option, ... } + // + // When computing the type contents of such a type, we wind up deeply + // recursing as we go. So when we encounter the recursive reference + // to List, we temporarily use TC_NONE as its contents. Later we'll + // patch up the cache with the correct value, once we've computed it + // (this is basically a co-inductive process, if that helps). So in + // the end we'll compute TC_OWNED_POINTER, in this case. + // + // The problem is, as we are doing the computation, we will also + // compute an *intermediate* contents for, e.g., Option of + // TC_NONE. This is ok during the computation of List itself, but if + // we stored this intermediate value into cx.tc_cache, then later + // requests for the contents of Option would also yield TC_NONE + // which is incorrect. This value was computed based on the crutch + // value for the type contents of list. The correct value is + // TC_OWNED_POINTER. This manifested as issue #4821. + let ty_id = type_id(ty); + match cache.find(&ty_id) { + Some(tc) => { return *tc; } + None => {} } - } + cache.insert(ty_id, TC_NONE); - ty_closure(ref c) => { - closure_kind(c) - } + debug!("computing contents of %s", ty_to_str(cx, ty)); + let _i = indenter(); - // Those with refcounts raise noncopyable to copyable, - // lower sendable to copyable. Therefore just set result to copyable. - ty_box(tm) => { - remove_owned(mutable_type_kind(cx, tm) | kind_safe_for_default_mode()) - } + let mut result = match get(ty).sty { + // Scalar and unique types are sendable, constant, and owned + ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | + ty_bare_fn(_) | ty_ptr(_) => { + TC_NONE + } - // XXX: This is wrong for ~Trait and &Trait! - ty_trait(_, _, _) => kind_safe_for_default_mode() | kind_durable(), + ty_estr(vstore_uniq) => { + TC_OWNED_SLICE + } - // Static region pointers are copyable and sendable, but not owned - ty_rptr(re_static, mt) => - kind_safe_for_default_mode() | mutable_type_kind(cx, mt), + ty_closure(ref c) => { + closure_contents(c) + } - ty_rptr(_, mt) => { - if mt.mutbl == ast::m_mutbl { - // Mutable region pointers are noncopyable - kind_noncopyable() - } else { - // General region pointers are copyable but NOT owned nor sendable - kind_safe_for_default_mode() - } - } + ty_box(mt) => { + TC_MANAGED + nonowned(tc_mt(cx, mt, cache)) + } - // Unique boxes and vecs have the kind of their contained type, - // but unique boxes can't be implicitly copyable. - ty_uniq(tm) => remove_implicit(mutable_type_kind(cx, tm)), + ty_trait(_, _, vstore_uniq) => { + TC_OWNED_CLOSURE + } - // Implicit copyability of vecs is configurable - ty_evec(tm, vstore_uniq) => { - if cx.vecs_implicitly_copyable { - mutable_type_kind(cx, tm) - } else { - remove_implicit(mutable_type_kind(cx, tm)) - } - } + ty_trait(_, _, vstore_box) => { + TC_MANAGED + } - // Slices, refcounted evecs are copyable; uniques depend on the their - // contained type, but aren't implicitly copyable. Fixed vectors have - // the kind of the element they contain, taking mutability into account. - ty_evec(tm, vstore_box) => { - remove_owned(kind_safe_for_default_mode() | mutable_type_kind(cx, tm)) - } - ty_evec(tm, vstore_slice(re_static)) => { - kind_safe_for_default_mode() | mutable_type_kind(cx, tm) - } - ty_evec(tm, vstore_slice(_)) => { - remove_durable_owned(kind_safe_for_default_mode() | - mutable_type_kind(cx, tm)) - } - ty_evec(tm, vstore_fixed(_)) => { - mutable_type_kind(cx, tm) - } + ty_trait(_, _, vstore_slice(r)) => { + borrowed_contents(r, m_imm) + } - // All estrs are copyable; uniques and interiors are sendable. - ty_estr(vstore_box) => { - kind_safe_for_default_mode() | kind_const() | kind_durable() - } - ty_estr(vstore_slice(re_static)) => { - kind_safe_for_default_mode() | kind_owned_copy() | kind_const() - } - ty_estr(vstore_slice(_)) => { - kind_safe_for_default_mode() | kind_const() - } - ty_estr(vstore_fixed(_)) => { - kind_safe_for_default_mode_send() | kind_const() | kind_durable() - } + ty_rptr(r, mt) => { + borrowed_contents(r, mt.mutbl) + + nonowned(tc_mt(cx, mt, cache)) + } - // Records lower to the lowest of their members. - ty_rec(flds) => { - let mut lowest = kind_top(); - for flds.each |f| { - lowest = lower_kind(lowest, mutable_type_kind(cx, f.mt)); - } - lowest - } + ty_uniq(mt) => { + TC_OWNED_POINTER + tc_mt(cx, mt, cache) + } - ty_struct(did, ref substs) => { - // Structs are sendable if all their fields are sendable, - // likewise for copyable... - // also factor out this code, copied from the records case - let mut lowest = kind_top(); - let flds = struct_fields(cx, did, substs); - for flds.each |f| { - lowest = lower_kind(lowest, mutable_type_kind(cx, f.mt)); - } - // ...but structs with dtors are never copyable (they can be - // sendable) - if ty::has_dtor(cx, did) { - lowest = remove_copyable(lowest); - } - lowest - } + ty_evec(mt, vstore_uniq) => { + TC_OWNED_SLICE + tc_mt(cx, mt, cache) + } - // Tuples lower to the lowest of their members. - ty_tup(tys) => { - let mut lowest = kind_top(); - for tys.each |ty| { lowest = lower_kind(lowest, type_kind(cx, *ty)); } - lowest - } + ty_evec(mt, vstore_box) => { + TC_MANAGED + nonowned(tc_mt(cx, mt, cache)) + } - // Enums lower to the lowest of their variants. - ty_enum(did, ref substs) => { - let mut lowest = kind_top(); - let variants = enum_variants(cx, did); - if variants.is_empty() { - lowest = kind_owned_only() | kind_durable(); - } else { - for variants.each |variant| { - for variant.args.each |aty| { - // Perform any type parameter substitutions. - let arg_ty = subst(cx, substs, *aty); - lowest = lower_kind(lowest, type_kind(cx, arg_ty)); - if lowest == kind_noncopyable() { break; } + ty_evec(mt, vstore_slice(r)) => { + borrowed_contents(r, mt.mutbl) + + nonowned(tc_mt(cx, mt, cache)) + } + + ty_evec(mt, vstore_fixed(_)) => { + tc_mt(cx, mt, cache) + } + + ty_estr(vstore_box) => { + TC_MANAGED + } + + ty_estr(vstore_slice(r)) => { + borrowed_contents(r, m_imm) + } + + ty_estr(vstore_fixed(_)) => { + TC_NONE + } + + ty_rec(ref flds) => { + flds.foldl( + TC_NONE, + |tc, f| tc + tc_mt(cx, f.mt, cache)) + } + + ty_struct(did, ref substs) => { + let flds = struct_fields(cx, did, substs); + let flds_tc = flds.foldl( + TC_NONE, + |tc, f| tc + tc_mt(cx, f.mt, cache)); + if ty::has_dtor(cx, did) { + flds_tc + TC_DTOR + } else { + flds_tc } } - } - lowest - } - ty_param(p) => { - // We only ever ask for the kind of types that are defined in the - // current crate; therefore, the only type parameters that could be - // in scope are those defined in the current crate. If this - // assertion failures, it is likely because of a failure in the - // cross-crate inlining code to translate a def-id. - assert p.def_id.crate == ast::local_crate; + ty_tup(ref tys) => { + tys.foldl(TC_NONE, |tc, ty| *tc + tc_ty(cx, *ty, cache)) + } - param_bounds_to_kind(cx.ty_param_bounds.get(&p.def_id.node)) - } + ty_enum(did, ref substs) => { + let variants = substd_enum_variants(cx, did, substs); + if variants.is_empty() { + // we somewhat arbitrary declare that empty enums + // are non-copyable + TC_EMPTY_ENUM + } else { + variants.foldl(TC_NONE, |tc, variant| { + variant.args.foldl( + *tc, + |tc, arg_ty| *tc + tc_ty(cx, *arg_ty, cache)) + }) + } + } - // self is a special type parameter that can only appear in traits; it - // is never bounded in any way, hence it has the bottom kind. - ty_self => kind_noncopyable(), + ty_param(p) => { + // We only ever ask for the kind of types that are defined in + // the current crate; therefore, the only type parameters that + // could be in scope are those defined in the current crate. + // If this assertion failures, it is likely because of a + // failure in the cross-crate inlining code to translate a + // def-id. + assert p.def_id.crate == ast::local_crate; - ty_infer(_) => { - if allow_ty_var { - kind_top() - } else { - cx.sess.bug(~"Asked to compute kind of a type variable") - } - } + param_bounds_to_contents( + cx, cx.ty_param_bounds.get(&p.def_id.node)) + } - ty_type | ty_opaque_closure_ptr(_) - | ty_opaque_box | ty_unboxed_vec(_) | ty_err => { - cx.sess.bug(~"Asked to compute kind of fictitious type"); - } - }; + ty_self => { + // Currently, self is not bounded, so we must assume the + // worst. But in the future we should examine the super + // traits. + // + // FIXME(#4678)---self should just be a ty param + TC_ALL + } + + ty_infer(_) => { + // This occurs during coherence, but shouldn't occur at other + // times. + TC_ALL + } + + ty_trait(_, _, vstore_fixed(_)) | + ty_type | + ty_opaque_closure_ptr(_) | + ty_opaque_box | + ty_unboxed_vec(_) | + ty_err => { + cx.sess.bug(~"Asked to compute contents of fictitious type"); + } + }; - // arbitrary threshold to prevent by-value copying of big records - if kind_is_safe_for_default_mode(result) { if type_size(cx, ty) > 4 { - result = result - kind_(KIND_MASK_DEFAULT_MODE); + result = result + TC_BIG; + } + + debug!("result = %s", result.to_str()); + + cache.insert(ty_id, result); + return result; + } + + fn tc_mt(cx: ctxt, + mt: mt, + cache: &mut LinearMap) -> TypeContents + { + let mc = if mt.mutbl == m_mutbl {TC_MUTABLE} else {TC_NONE}; + mc + tc_ty(cx, mt.ty, cache) + } + + fn borrowed_contents(region: ty::Region, + mutbl: ast::mutability) -> TypeContents + { + let mc = if mutbl == m_mutbl { + TC_MUTABLE + TC_BORROWED_MUT + } else { + TC_NONE + }; + let rc = if region != ty::re_static { + TC_BORROWED_POINTER + } else { + TC_NONE + }; + mc + rc + } + + fn nonowned(pointee: TypeContents) -> TypeContents { + /*! + * + * Given a non-owning pointer to some type `T` with + * contents `pointee` (like `@T` or + * `&T`), returns the relevant bits that + * apply to the owner of the pointer. + */ + + let mask = TC_MUTABLE.bits | TC_BORROWED_POINTER.bits; + TypeContents {bits: pointee.bits & mask} + } + + fn closure_contents(cty: &ClosureTy) -> TypeContents { + let st = match cty.sigil { + ast::BorrowedSigil => TC_BORROWED_POINTER, + ast::ManagedSigil => TC_MANAGED, + ast::OwnedSigil => TC_OWNED_CLOSURE + }; + let rt = borrowed_contents(cty.region, m_imm); + let ot = match cty.onceness { + ast::Once => TC_ONCE_CLOSURE, + ast::Many => TC_NONE + }; + st + rt + ot + } + + fn param_bounds_to_contents(cx: ctxt, + bounds: param_bounds) -> TypeContents + { + debug!("param_bounds_to_contents()"); + let _i = indenter(); + + let r = bounds.foldl(TC_ALL, |tc, bound| { + debug!("tc = %s, bound = %?", tc.to_str(), bound); + match *bound { + bound_copy => tc - TypeContents::nonimplicitly_copyable(cx), + bound_durable => tc - TypeContents::nondurable(cx), + bound_owned => tc - TypeContents::nonowned(cx), + bound_const => tc - TypeContents::nonconst(cx), + bound_trait(_) => *tc + } + }); + + debug!("result = %s", r.to_str()); + return r; + } + + /// gives a rough estimate of how much space it takes to represent + /// an instance of `ty`. Used for the mode transition. + fn type_size(cx: ctxt, ty: t) -> uint { + match /*bad*/copy get(ty).sty { + ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | + ty_ptr(_) | ty_box(_) | ty_uniq(_) | ty_estr(vstore_uniq) | + ty_trait(*) | ty_rptr(*) | ty_evec(_, vstore_uniq) | + ty_evec(_, vstore_box) | ty_estr(vstore_box) => { + 1 + } + + ty_evec(_, vstore_slice(_)) | + ty_estr(vstore_slice(_)) | + ty_bare_fn(*) | + ty_closure(*) => { + 2 + } + + ty_evec(t, vstore_fixed(n)) => { + type_size(cx, t.ty) * n + } + + ty_estr(vstore_fixed(n)) => { + n + } + + ty_rec(flds) => { + flds.foldl(0, |s, f| *s + type_size(cx, f.mt.ty)) + } + + ty_struct(did, ref substs) => { + let flds = struct_fields(cx, did, substs); + flds.foldl(0, |s, f| *s + type_size(cx, f.mt.ty)) + } + + ty_tup(tys) => { + tys.foldl(0, |s, t| *s + type_size(cx, *t)) + } + + ty_enum(did, ref substs) => { + let variants = substd_enum_variants(cx, did, substs); + variants.foldl( // find max size of any variant + 0, + |m, v| uint::max( + *m, + // find size of this variant: + v.args.foldl(0, |s, a| *s + type_size(cx, *a)))) + } + + ty_param(_) | ty_self => { + 1 + } + + ty_infer(_) => { + cx.sess.bug(~"Asked to compute kind of a type variable"); + } + ty_type | ty_opaque_closure_ptr(_) + | ty_opaque_box | ty_unboxed_vec(_) | ty_err => { + cx.sess.bug(~"Asked to compute kind of fictitious type"); + } } } - - cx.kind_cache.insert(ty, result); - return result; } -pub fn type_implicitly_moves(cx: ctxt, ty: t) -> bool { - let kind = type_kind(cx, ty); - !(kind_can_be_copied(kind) && kind_can_be_implicitly_copied(kind)) -} - -/// gives a rough estimate of how much space it takes to represent -/// an instance of `ty`. Used for the mode transition. -fn type_size(cx: ctxt, ty: t) -> uint { - match /*bad*/copy get(ty).sty { - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_ptr(_) | ty_box(_) | ty_uniq(_) | ty_estr(vstore_uniq) | - ty_trait(*) | ty_rptr(*) | ty_evec(_, vstore_uniq) | - ty_evec(_, vstore_box) | ty_estr(vstore_box) => { - 1 - } - - ty_evec(_, vstore_slice(_)) | - ty_estr(vstore_slice(_)) | - ty_bare_fn(*) | - ty_closure(*) => { - 2 - } - - ty_evec(t, vstore_fixed(n)) => { - type_size(cx, t.ty) * n - } - - ty_estr(vstore_fixed(n)) => { - n - } - - ty_rec(flds) => { - flds.foldl(0, |s, f| *s + type_size(cx, f.mt.ty)) - } - - ty_struct(did, ref substs) => { - let flds = struct_fields(cx, did, substs); - flds.foldl(0, |s, f| *s + type_size(cx, f.mt.ty)) - } - - ty_tup(tys) => { - tys.foldl(0, |s, t| *s + type_size(cx, *t)) - } - - ty_enum(did, ref substs) => { - let variants = substd_enum_variants(cx, did, substs); - variants.foldl( // find max size of any variant - 0, - |m, v| uint::max(*m, - // find size of this variant: - v.args.foldl(0, |s, a| *s + type_size(cx, *a)))) - } - - ty_param(_) | ty_self => { - 1 - } - - ty_infer(_) => { - cx.sess.bug(~"Asked to compute kind of a type variable"); - } - ty_type | ty_opaque_closure_ptr(_) - | ty_opaque_box | ty_unboxed_vec(_) | ty_err => { - cx.sess.bug(~"Asked to compute kind of fictitious type"); - } - } +pub fn type_moves_by_default(cx: ctxt, ty: t) -> bool { + type_contents(cx, ty).moves_by_default(cx) } // True if instantiating an instance of `r_ty` requires an instance of `r_ty`. @@ -2678,12 +2669,6 @@ impl arg : to_bytes::IterBytes { } } -impl Kind : to_bytes::IterBytes { - pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) - } -} - impl FnSig : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_2(&self.inputs, @@ -4549,12 +4534,6 @@ impl param_bound : cmp::Eq { pure fn ne(&self, other: ¶m_bound) -> bool { !self.eq(other) } } -impl Kind : cmp::Eq { - pure fn eq(&self, other: &Kind) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &Kind) -> bool { *(*self) != *(*other) } -} - - // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 9f28cb61520..1790bd19925 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -24,13 +24,13 @@ use metadata::cstore::{CStore, iter_crate_data}; use metadata::decoder::{dl_def, dl_field, dl_impl}; use middle::resolve::{Impl, MethodInfo}; use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, bound_copy, get}; -use middle::ty::{kind_can_be_copied, lookup_item_type, param_bounds, subst}; +use middle::ty::{lookup_item_type, param_bounds, subst}; use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err}; use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil}; use middle::ty::{ty_opaque_box, ty_param, ty_param_bounds_and_ty, ty_ptr}; use middle::ty::{ty_rec, ty_rptr, ty_self, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_type, ty_uint, ty_uniq, ty_bare_fn, ty_closure}; -use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_kind_ext}; +use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec}; use middle::ty::{type_is_ty_var}; use middle::ty; use middle::typeck::CrateCtxt; @@ -578,11 +578,10 @@ pub impl CoherenceChecker { for bounds.each |bound| { match *bound { bound_copy => { - let kind = type_kind_ext( + if !ty::type_is_copyable( self.inference_context.tcx, - resolved_ty, - true); - if !kind_can_be_copied(kind) { + resolved_ty) + { might_unify = false; break; } diff --git a/src/libstd/json.rs b/src/libstd/json.rs index d5c91ea5147..404f1bcda99 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -832,7 +832,7 @@ pub impl Decoder: serialize::Decoder { fn read_owned_vec(&self, f: fn(uint) -> T) -> T { debug!("read_owned_vec()"); let len = match *self.peek() { - List(list) => list.len(), + List(ref list) => list.len(), _ => die!(~"not a list"), }; let res = f(len); diff --git a/src/test/compile-fail/bad-method-typaram-kind.rs b/src/test/compile-fail/bad-method-typaram-kind.rs index b79e6ecb3fb..112423a073e 100644 --- a/src/test/compile-fail/bad-method-typaram-kind.rs +++ b/src/test/compile-fail/bad-method-typaram-kind.rs @@ -9,7 +9,7 @@ // except according to those terms. fn foo() { - 1u.bar::(); //~ ERROR: missing `copy` + 1u.bar::(); //~ ERROR: does not fulfill `Copy` } trait bar { diff --git a/src/test/compile-fail/copy-a-resource.rs b/src/test/compile-fail/copy-a-resource.rs index df2540be987..eb135e18893 100644 --- a/src/test/compile-fail/copy-a-resource.rs +++ b/src/test/compile-fail/copy-a-resource.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: copying a noncopyable value - struct foo { i: int, } @@ -24,4 +22,9 @@ fn foo(i:int) -> foo { } } -fn main() { let x = move foo(10); let y = copy x; log(error, x); } +fn main() { + let x = move foo(10); + let _y = copy x; + //~^ ERROR copying a value of non-copyable type `foo` + log(error, x); +} diff --git a/src/test/compile-fail/issue-2548.rs b/src/test/compile-fail/issue-2548.rs index 2684289d70f..402e8ee831f 100644 --- a/src/test/compile-fail/issue-2548.rs +++ b/src/test/compile-fail/issue-2548.rs @@ -34,7 +34,7 @@ fn main() { let mut res = foo(x); let mut v = ~[mut]; - v = move ~[mut (move res)] + v; //~ ERROR instantiating a type parameter with an incompatible type (needs `copy`, got `&static`, missing `copy`) + v = move ~[mut (move res)] + v; //~ ERROR does not fulfill `Copy` assert (v.len() == 2); } diff --git a/src/test/compile-fail/issue-2823.rs b/src/test/compile-fail/issue-2823.rs index 4ad349381da..f2ea4faf482 100644 --- a/src/test/compile-fail/issue-2823.rs +++ b/src/test/compile-fail/issue-2823.rs @@ -20,6 +20,6 @@ impl C : Drop { fn main() { let c = C{ x: 2}; - let d = copy c; //~ ERROR copying a noncopyable value + let d = copy c; //~ ERROR copying a value of non-copyable type `C` error!("%?", d.x); } diff --git a/src/test/compile-fail/kindck-nonsendable-1.rs b/src/test/compile-fail/kindck-nonsendable-1.rs index dd1b3f03f05..f04740bae4c 100644 --- a/src/test/compile-fail/kindck-nonsendable-1.rs +++ b/src/test/compile-fail/kindck-nonsendable-1.rs @@ -12,7 +12,7 @@ fn foo(_x: @uint) {} fn main() { let x = @3u; - let _ = fn~() { foo(x); }; //~ ERROR not a sendable value - let _ = fn~(copy x) { foo(x); }; //~ ERROR not a sendable value - let _ = fn~(move x) { foo(x); }; //~ ERROR not a sendable value + let _ = fn~() { foo(x); }; //~ ERROR value has non-owned type `@uint` + let _ = fn~(copy x) { foo(x); }; //~ ERROR value has non-owned type `@uint` + let _ = fn~(move x) { foo(x); }; //~ ERROR value has non-owned type `@uint` } \ No newline at end of file diff --git a/src/test/compile-fail/kindck-owned.rs b/src/test/compile-fail/kindck-owned.rs index bc6dd8f5dc9..65f6f837c83 100644 --- a/src/test/compile-fail/kindck-owned.rs +++ b/src/test/compile-fail/kindck-owned.rs @@ -18,12 +18,12 @@ fn copy2(t: T) -> fn@() -> T { fn main() { let x = &3; - copy2(&x); //~ ERROR missing `&static` + copy2(&x); //~ ERROR does not fulfill `&static` copy2(@3); - copy2(@&x); //~ ERROR missing `&static` + copy2(@&x); //~ ERROR does not fulfill `&static` copy2(fn@() {}); - copy2(fn~() {}); //~ ERROR missing `copy` - copy2(fn&() {}); //~ ERROR missing `&static` + copy2(fn~() {}); //~ ERROR does not fulfill `Copy` + copy2(fn&() {}); //~ ERROR does not fulfill `&static` } diff --git a/src/test/compile-fail/liveness-unused.rs b/src/test/compile-fail/liveness-unused.rs index 14eacb81cba..351a63f062d 100644 --- a/src/test/compile-fail/liveness-unused.rs +++ b/src/test/compile-fail/liveness-unused.rs @@ -68,5 +68,5 @@ impl r : Drop { fn main() { let x = r { x: () }; - fn@(move x) { copy x; }; //~ ERROR copying a noncopyable value + fn@(move x) { copy x; }; //~ ERROR copying a value of non-copyable type } diff --git a/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs b/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs new file mode 100644 index 00000000000..4af3e1cbe86 --- /dev/null +++ b/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs @@ -0,0 +1,34 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test for a subtle failure computing kinds of cyclic types, in which +// temporary kinds wound up being stored in a cache and used later. +// See middle::ty::type_contents() for more information. + +extern mod std; +use core::cmp::Ord; +use core::option::swap_unwrap; + +struct List { key: int, next: Option<~List> } + +fn foo(node: ~List) -> int { + let r = match node.next { + Some(right) => consume(right), + None => 0 + }; + consume(node) + r //~ ERROR use of partially moved value: `node` +} + +fn consume(v: ~List) -> int { + v.key +} + +fn main() {} + diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs index 9a16ebda59d..d0c216fe231 100644 --- a/src/test/compile-fail/no-send-res-ports.rs +++ b/src/test/compile-fail/no-send-res-ports.rs @@ -29,7 +29,7 @@ fn main() { do task::spawn { let mut y = None; - *x <-> y; //~ ERROR not a sendable value + *x <-> y; //~ ERROR value has non-owned type log(error, y); } } diff --git a/src/test/compile-fail/non-const.rs b/src/test/compile-fail/non-const.rs index b8c7eb4a204..84f34d0e9bd 100644 --- a/src/test/compile-fail/non-const.rs +++ b/src/test/compile-fail/non-const.rs @@ -42,14 +42,14 @@ fn r2(x:@mut int) -> r2 { fn main() { foo({f: 3}); - foo({mut f: 3}); //~ ERROR missing `const` + foo({mut f: 3}); //~ ERROR does not fulfill `Const` foo(~[1]); - foo(~[mut 1]); //~ ERROR missing `const` + foo(~[mut 1]); //~ ERROR does not fulfill `Const` foo(~1); - foo(~mut 1); //~ ERROR missing `const` + foo(~mut 1); //~ ERROR does not fulfill `Const` foo(@1); - foo(@mut 1); //~ ERROR missing `const` + foo(@mut 1); //~ ERROR does not fulfill `Const` foo(r(1)); // this is okay now. - foo(r2(@mut 1)); //~ ERROR missing `const` - foo({f: {mut f: 1}}); //~ ERROR missing `const` + foo(r2(@mut 1)); //~ ERROR does not fulfill `Const` + foo({f: {mut f: 1}}); //~ ERROR does not fulfill `Const` } diff --git a/src/test/compile-fail/non-copyable-void.rs b/src/test/compile-fail/non-copyable-void.rs index e96650938d2..d8192a24652 100644 --- a/src/test/compile-fail/non-copyable-void.rs +++ b/src/test/compile-fail/non-copyable-void.rs @@ -13,6 +13,6 @@ fn main() { let y : *libc::c_void = x as *libc::c_void; unsafe { let _z = copy *y; - //~^ ERROR copying a noncopyable value + //~^ ERROR copying a value of non-copyable type } } diff --git a/src/test/compile-fail/noncopyable-class.rs b/src/test/compile-fail/noncopyable-class.rs index 96a9347d2e9..360180ee455 100644 --- a/src/test/compile-fail/noncopyable-class.rs +++ b/src/test/compile-fail/noncopyable-class.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: copying a noncopyable value - // Test that a class with a non-copyable field can't be // copied struct bar { @@ -38,4 +36,8 @@ fn foo(i:int) -> foo { } } -fn main() { let x = move foo(10); let y = copy x; log(error, x); } +fn main() { + let x = move foo(10); + let _y = copy x; //~ ERROR copying a value of non-copyable type + log(error, x); +} diff --git a/src/test/compile-fail/noncopyable-match-pattern.rs b/src/test/compile-fail/noncopyable-match-pattern.rs index 9b2d129a1a8..a123cf9fc6f 100644 --- a/src/test/compile-fail/noncopyable-match-pattern.rs +++ b/src/test/compile-fail/noncopyable-match-pattern.rs @@ -11,7 +11,7 @@ fn main() { let x = Some(private::exclusive(false)); match x { - Some(copy z) => { //~ ERROR copying a noncopyable value + Some(copy z) => { //~ ERROR copying a value of non-copyable type do z.with |b| { assert !*b; } } None => die!() diff --git a/src/test/compile-fail/pinned-deep-copy.rs b/src/test/compile-fail/pinned-deep-copy.rs index 16adb6f1925..80cf409f239 100644 --- a/src/test/compile-fail/pinned-deep-copy.rs +++ b/src/test/compile-fail/pinned-deep-copy.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: copying a noncopyable value - struct r { i: @mut int, } @@ -31,7 +29,7 @@ fn main() { { // Can't do this copy let x = ~~~{y: r(i)}; - let z = copy x; + let _z = copy x; //~ ERROR copying a value of non-copyable type log(debug, x); } log(error, *i); diff --git a/src/test/compile-fail/record-with-resource.rs b/src/test/compile-fail/record-with-resource.rs index 95b0aba92fc..c9dc77ce4d2 100644 --- a/src/test/compile-fail/record-with-resource.rs +++ b/src/test/compile-fail/record-with-resource.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: copying a noncopyable value - struct my_resource { x: int, } @@ -29,7 +27,7 @@ fn my_resource(x: int) -> my_resource { fn main() { { let a = {x: 0, y: my_resource(20)}; - let b = {x: 2,.. copy a}; + let b = {x: 2,.. copy a}; //~ ERROR copying a value of non-copyable type log(error, (a, b)); } } diff --git a/src/test/compile-fail/repeat-to-run-dtor-twice.rs b/src/test/compile-fail/repeat-to-run-dtor-twice.rs index d3205ef4f4b..58c07cc8ea6 100644 --- a/src/test/compile-fail/repeat-to-run-dtor-twice.rs +++ b/src/test/compile-fail/repeat-to-run-dtor-twice.rs @@ -24,6 +24,6 @@ impl Foo : Drop { fn main() { let a = Foo { x: 3 }; - let _ = [ a, ..5 ]; //~ ERROR copying a noncopyable value + let _ = [ a, ..5 ]; //~ ERROR copying a value of non-copyable type } diff --git a/src/test/compile-fail/unique-object-noncopyable.rs b/src/test/compile-fail/unique-object-noncopyable.rs index 85ab64ce076..010161181f5 100644 --- a/src/test/compile-fail/unique-object-noncopyable.rs +++ b/src/test/compile-fail/unique-object-noncopyable.rs @@ -9,7 +9,7 @@ // except according to those terms. trait Foo { - fn f(); + fn f(&self); } struct Bar { @@ -21,14 +21,14 @@ impl Bar : Drop { } impl Bar : Foo { - fn f() { + fn f(&self) { io::println("hi"); } } fn main() { let x = ~Bar { x: 10 }; - let y = (move x) as ~Foo; //~ ERROR uniquely-owned trait objects must be copyable - let _z = copy y; + let y: ~Foo = x as ~Foo; + let _z = copy y; //~ ERROR copying a value of non-copyable type } diff --git a/src/test/compile-fail/unique-pinned-nocopy.rs b/src/test/compile-fail/unique-pinned-nocopy.rs index 9037290af4e..0211fd3c011 100644 --- a/src/test/compile-fail/unique-pinned-nocopy.rs +++ b/src/test/compile-fail/unique-pinned-nocopy.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: copying a noncopyable value - struct r { b:bool, } @@ -20,6 +18,6 @@ impl r : Drop { fn main() { let i = move ~r { b: true }; - let j = copy i; + let _j = copy i; //~ ERROR copying a value of non-copyable type log(debug, i); } diff --git a/src/test/compile-fail/unique-unique-kind.rs b/src/test/compile-fail/unique-unique-kind.rs index e20971a63bd..25c42ab4add 100644 --- a/src/test/compile-fail/unique-unique-kind.rs +++ b/src/test/compile-fail/unique-unique-kind.rs @@ -13,5 +13,5 @@ fn f(_i: T) { fn main() { let i = ~@100; - f(move i); //~ ERROR missing `owned` + f(move i); //~ ERROR does not fulfill `Owned` } diff --git a/src/test/compile-fail/unique-vec-res.rs b/src/test/compile-fail/unique-vec-res.rs index 1193861f19b..a97f47551e1 100644 --- a/src/test/compile-fail/unique-vec-res.rs +++ b/src/test/compile-fail/unique-vec-res.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: copying a noncopyable value - struct r { i: @mut int, } @@ -20,7 +18,7 @@ impl r : Drop { } } -fn f(+i: ~[T], +j: ~[T]) { +fn f(+_i: ~[T], +_j: ~[T]) { } fn main() { @@ -29,6 +27,8 @@ fn main() { let r1 = move ~[~r { i: i1 }]; let r2 = move ~[~r { i: i2 }]; f(copy r1, copy r2); + //~^ ERROR copying a value of non-copyable type + //~^^ ERROR copying a value of non-copyable type log(debug, (r2, *i1)); log(debug, (r1, *i2)); } diff --git a/src/test/compile-fail/unsendable-class.rs b/src/test/compile-fail/unsendable-class.rs index b5bb05d5c69..e660884e40b 100644 --- a/src/test/compile-fail/unsendable-class.rs +++ b/src/test/compile-fail/unsendable-class.rs @@ -25,6 +25,6 @@ fn foo(i:int, j: @~str) -> foo { fn main() { let cat = ~"kitty"; - let (_, ch) = pipes::stream(); //~ ERROR missing `owned` - ch.send(foo(42, @(move cat))); //~ ERROR missing `owned` + let (_, ch) = pipes::stream(); //~ ERROR does not fulfill `Owned` + ch.send(foo(42, @(move cat))); //~ ERROR does not fulfill `Owned` } diff --git a/src/test/run-pass/explicit-self-objects-uniq.rs b/src/test/run-pass/explicit-self-objects-uniq.rs index bf1776e598e..6e789b7ff1e 100644 --- a/src/test/run-pass/explicit-self-objects-uniq.rs +++ b/src/test/run-pass/explicit-self-objects-uniq.rs @@ -26,8 +26,6 @@ pub fn main() { let x = ~S { x: 3 }; let y = x as ~Foo; y.f(); - y.f(); - y.f(); } diff --git a/src/test/run-pass/unique-object.rs b/src/test/run-pass/unique-object.rs index 058d212eb69..4ad8ab38e4b 100644 --- a/src/test/run-pass/unique-object.rs +++ b/src/test/run-pass/unique-object.rs @@ -9,7 +9,7 @@ // except according to those terms. trait Foo { - fn f(); + fn f(&self) -> int; } struct Bar { @@ -17,16 +17,14 @@ struct Bar { } impl Bar : Foo { - fn f() { - io::println("hi"); + fn f(&self) -> int { + self.x } } pub fn main() { let x = ~Bar { x: 10 }; let y = x as ~Foo; - let z = copy y; - y.f(); - z.f(); + assert y.f() == 10; }