diff options
Diffstat (limited to 'src')
287 files changed, 6791 insertions, 3758 deletions
diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 683d5fecc34..d858003c353 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -75,7 +75,7 @@ pub fn parse_config(args: ~[~str]) -> config { ]; assert!(!args.is_empty()); - let args_ = vec::tail(args); + let args_ = args.tail(); let matches = &match getopts::getopts(args_, opts) { Ok(m) => m, diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs index cdc0defcbca..4649d4dfc3c 100644 --- a/src/compiletest/errors.rs +++ b/src/compiletest/errors.rs @@ -21,7 +21,7 @@ pub fn load_errors(testfile: &Path) -> ~[ExpectedError] { let mut line_num = 1u; while !rdr.eof() { let ln = rdr.read_line(); - error_patterns += parse_expected(line_num, ln); + error_patterns.push_all_move(parse_expected(line_num, ln)); line_num += 1u; } return error_patterns; diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 3e2f484ee53..0e04be34c79 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -226,8 +226,8 @@ actual:\n\ ~"-L", config.build_base.to_str(), ~"-L", aux_output_dir_name(config, testfile).to_str()]; - args += split_maybe_args(&config.rustcflags); - args += split_maybe_args(&props.compile_flags); + args.push_all_move(split_maybe_args(&config.rustcflags)); + args.push_all_move(split_maybe_args(&props.compile_flags)); return ProcArgs {prog: config.rustc_path.to_str(), args: args}; } } @@ -321,8 +321,7 @@ fn check_error_patterns(props: &TestProps, if done { return; } let missing_patterns = - vec::slice(props.error_patterns, next_err_idx, - props.error_patterns.len()); + props.error_patterns.slice(next_err_idx, props.error_patterns.len()); if missing_patterns.len() == 1u { fatal_ProcRes(fmt!("error pattern '%s' not found!", missing_patterns[0]), ProcRes); @@ -582,8 +581,8 @@ fn make_compile_args(config: &config, props: &TestProps, extras: ~[~str], ~"-o", xform(config, testfile).to_str(), ~"-L", config.build_base.to_str()] + extras; - args += split_maybe_args(&config.rustcflags); - args += split_maybe_args(&props.compile_flags); + args.push_all_move(split_maybe_args(&config.rustcflags)); + args.push_all_move(split_maybe_args(&props.compile_flags)); return ProcArgs {prog: config.rustc_path.to_str(), args: args}; } diff --git a/src/etc/pkg/rust.iss b/src/etc/pkg/rust.iss index 18f358a9893..0375a041a39 100644 --- a/src/etc/pkg/rust.iss +++ b/src/etc/pkg/rust.iss @@ -1,4 +1,5 @@ #define CFG_VERSION GetEnv("CFG_VERSION") +#define CFG_VERSION_WIN GetEnv("CFG_VERSION_WIN") [Setup] @@ -8,7 +9,7 @@ AppVersion={#CFG_VERSION} AppCopyright=Copyright (C) 2006-2013 Mozilla Foundation, MIT license AppPublisher=Mozilla Foundation AppPublisherURL=http://www.rust-lang.org -VersionInfoVersion={#CFG_VERSION} +VersionInfoVersion={#CFG_VERSION_WIN} LicenseFile=LICENSE.txt DisableWelcomePage=true diff --git a/src/etc/zsh/_rust b/src/etc/zsh/_rust index faa21a29616..86dcbab93fd 100644 --- a/src/etc/zsh/_rust +++ b/src/etc/zsh/_rust @@ -29,36 +29,30 @@ _rustc_opts_switches=( --target'[Target triple cpu-manufacturer-kernel\[-os\] to compile]' --target-feature'[Target specific attributes (llc -mattr=help for detail)]' --android-cross-path'[The path to the Android NDK]' - {-W,--warn}'[Set lint warnings]' - {-A,--allow}'[Set lint allowed]' - {-D,--deny}'[Set lint denied]' - {-F,--forbid}'[Set lint forbidden]' - -Z'[Set internal debugging options]' {-v,--version}'[Print version info and exit]' ) - _rustc_opts_lint=( - 'path-statement:path statements with no effect' - 'deprecated-pattern:warn about deprecated uses of pattern bindings' - 'non-implicitly-copyable-typarams:passing non implicitly copyable types as copy type params' - 'missing-trait-doc:detects missing documentation for traits' - 'missing-struct-doc:detects missing documentation for structs' - 'ctypes:proper use of core::libc types in foreign modules' - 'implicit-copies:implicit copies of non implicitly copyable data' - "unused-mut:detect mut variables which don't need to be mutable" - 'unused-imports:imports that are never used' - 'heap-memory:use of any (~ type or @ type) heap memory' - 'default-methods:allow default methods' - 'unused-variable:detect variables which are not used in any way' - 'dead-assignment:detect assignments that will never be read' - 'unrecognized-lint:unrecognized lint attribute' - 'type-limits:comparisons made useless by limits of the types involved' - 'unused-unsafe:unnecessary use of an `unsafe` block' - 'while-true:suggest using loop { } instead of while(true) { }' - 'non-camel-case-types:types, variants and traits should have camel case names' - 'managed-heap-memory:use of managed (@ type) heap memory' - 'unnecessary-allocation:detects unnecessary allocations that can be eliminated' - 'owned-heap-memory:use of owned (~ type) heap memory' + 'path-statement[path statements with no effect]' + 'deprecated-pattern[warn about deprecated uses of pattern bindings]' + 'non-implicitly-copyable-typarams[passing non implicitly copyable types as copy type params]' + 'missing-trait-doc[detects missing documentation for traits]' + 'missing-struct-doc[detects missing documentation for structs]' + 'ctypes[proper use of core::libc types in foreign modules]' + 'implicit-copies[implicit copies of non implicitly copyable data]' + "unused-mut[detect mut variables which don't need to be mutable]" + 'unused-imports[imports that are never used]' + 'heap-memory[use of any (~ type or @ type) heap memory]' + 'default-methods[allow default methods]' + 'unused-variable[detect variables which are not used in any way]' + 'dead-assignment[detect assignments that will never be read]' + 'unrecognized-lint[unrecognized lint attribute]' + 'type-limits[comparisons made useless by limits of the types involved]' + 'unused-unsafe[unnecessary use of an `unsafe` block]' + 'while-true[suggest using loop { } instead of while(true) { }]' + 'non-camel-case-types[types, variants and traits should have camel case names]' + 'managed-heap-memory[use of managed (@ type) heap memory]' + 'unnecessary-allocation[detects unnecessary allocations that can be eliminated]' + 'owned-heap-memory[use of owned (~ type) heap memory]' ) _rustc_opts_debug=( @@ -90,13 +84,20 @@ _rustc_opts_debug=( 'lint-llvm:Run the LLVM lint pass on the pre-optimization IR' ) -_rustc() { - case $words[2] in - -[WADF]) _describe 'options' _rustc_opts_lint ;; - -Z) _describe 'options' _rustc_opts_debug ;; - -) _arguments -s -w : "$_rustc_opts_switches[@]" ;; - *) _files -g "*.rs" ;; - esac +_rustc_opts_fun_lint(){ + _values -s , 'options' \ + "$_rustc_opts_lint[@]" +} + +_rustc_opts_fun_debug(){ + _describe 'options' _rustc_opts_debug } -_rustc "$@" +_arguments -s : \ + '(-W --warn)'{-W,--warn}'[Set lint warnings]:lint options:_rustc_opts_fun_lint' \ + '(-A --allow)'{-A,--allow}'[Set lint allowed]:lint options:_rustc_opts_fun_lint' \ + '(-D --deny)'{-D,--deny}'[Set lint denied]:lint options:_rustc_opts_fun_lint' \ + '(-F --forbid)'{-F,--forbid}'[Set lint forbidden]:lint options:_rustc_opts_fun_lint' \ + '*-Z[Set internal debugging options]:debug options:_rustc_opts_fun_debug' \ + "$_rustc_opts_switches[@]" \ + '*::files:_files -g "*.rs"' diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index c04ee63880e..30067c92300 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -112,7 +112,7 @@ impl<'self> Condvar<'self> { pub struct ARC<T> { x: UnsafeAtomicRcBox<T> } /// Create an atomically reference counted wrapper. -pub fn ARC<T:Const + Owned>(data: T) -> ARC<T> { +pub fn ARC<T:Freeze + Send>(data: T) -> ARC<T> { ARC { x: UnsafeAtomicRcBox::new(data) } } @@ -120,7 +120,7 @@ pub fn ARC<T:Const + Owned>(data: T) -> ARC<T> { * Access the underlying data in an atomically reference counted * wrapper. */ -impl<T:Const+Owned> ARC<T> { +impl<T:Freeze+Send> ARC<T> { pub fn get<'a>(&'a self) -> &'a T { unsafe { &*self.x.get_immut() } } @@ -133,7 +133,7 @@ impl<T:Const+Owned> ARC<T> { * object. However, one of the `arc` objects can be sent to another task, * allowing them to share the underlying data. */ -impl<T:Const + Owned> Clone for ARC<T> { +impl<T:Freeze + Send> Clone for ARC<T> { fn clone(&self) -> ARC<T> { ARC { x: self.x.clone() } } @@ -149,14 +149,14 @@ struct MutexARCInner<T> { lock: Mutex, failed: bool, data: T } struct MutexARC<T> { x: UnsafeAtomicRcBox<MutexARCInner<T>> } /// Create a mutex-protected ARC with the supplied data. -pub fn MutexARC<T:Owned>(user_data: T) -> MutexARC<T> { +pub fn MutexARC<T:Send>(user_data: T) -> MutexARC<T> { mutex_arc_with_condvars(user_data, 1) } /** * Create a mutex-protected ARC with the supplied data and a specified number * of condvars (as sync::mutex_with_condvars). */ -pub fn mutex_arc_with_condvars<T:Owned>(user_data: T, +pub fn mutex_arc_with_condvars<T:Send>(user_data: T, num_condvars: uint) -> MutexARC<T> { let data = MutexARCInner { lock: mutex_with_condvars(num_condvars), @@ -164,7 +164,7 @@ pub fn mutex_arc_with_condvars<T:Owned>(user_data: T, MutexARC { x: UnsafeAtomicRcBox::new(data) } } -impl<T:Owned> Clone for MutexARC<T> { +impl<T:Send> Clone for MutexARC<T> { /// Duplicate a mutex-protected ARC, as arc::clone. fn clone(&self) -> MutexARC<T> { // NB: Cloning the underlying mutex is not necessary. Its reference @@ -173,7 +173,7 @@ impl<T:Owned> Clone for MutexARC<T> { } } -impl<T:Owned> MutexARC<T> { +impl<T:Send> MutexARC<T> { /** * Access the underlying mutable data with mutual exclusion from other @@ -276,20 +276,21 @@ struct RWARCInner<T> { lock: RWlock, failed: bool, data: T } * * Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested. */ -#[mutable] +#[mutable] // XXX remove after snap +#[no_freeze] struct RWARC<T> { x: UnsafeAtomicRcBox<RWARCInner<T>>, } /// Create a reader/writer ARC with the supplied data. -pub fn RWARC<T:Const + Owned>(user_data: T) -> RWARC<T> { +pub fn RWARC<T:Freeze + Send>(user_data: T) -> RWARC<T> { rw_arc_with_condvars(user_data, 1) } /** * Create a reader/writer ARC with the supplied data and a specified number * of condvars (as sync::rwlock_with_condvars). */ -pub fn rw_arc_with_condvars<T:Const + Owned>( +pub fn rw_arc_with_condvars<T:Freeze + Send>( user_data: T, num_condvars: uint) -> RWARC<T> { @@ -299,7 +300,7 @@ pub fn rw_arc_with_condvars<T:Const + Owned>( RWARC { x: UnsafeAtomicRcBox::new(data), } } -impl<T:Const + Owned> RWARC<T> { +impl<T:Freeze + Send> RWARC<T> { /// Duplicate a rwlock-protected ARC, as arc::clone. pub fn clone(&self) -> RWARC<T> { RWARC { @@ -309,7 +310,7 @@ impl<T:Const + Owned> RWARC<T> { } -impl<T:Const + Owned> RWARC<T> { +impl<T:Freeze + Send> RWARC<T> { /** * Access the underlying data mutably. Locks the rwlock in write mode; * other readers and writers will block. @@ -435,7 +436,7 @@ impl<T:Const + Owned> RWARC<T> { // lock it. This wraps the unsafety, with the justification that the 'lock' // field is never overwritten; only 'failed' and 'data'. #[doc(hidden)] -fn borrow_rwlock<T:Const + Owned>(state: *const RWARCInner<T>) -> *RWlock { +fn borrow_rwlock<T:Freeze + Send>(state: *const RWARCInner<T>) -> *RWlock { unsafe { cast::transmute(&const (*state).lock) } } @@ -452,7 +453,7 @@ pub struct RWReadMode<'self, T> { token: sync::RWlockReadMode<'self>, } -impl<'self, T:Const + Owned> RWWriteMode<'self, T> { +impl<'self, T:Freeze + Send> RWWriteMode<'self, T> { /// Access the pre-downgrade RWARC in write mode. pub fn write<U>(&mut self, blk: &fn(x: &mut T) -> U) -> U { match *self { @@ -493,7 +494,7 @@ impl<'self, T:Const + Owned> RWWriteMode<'self, T> { } } -impl<'self, T:Const + Owned> RWReadMode<'self, T> { +impl<'self, T:Freeze + Send> RWReadMode<'self, T> { /// Access the post-downgrade rwlock in read mode. pub fn read<U>(&self, blk: &fn(x: &T) -> U) -> U { match *self { @@ -517,7 +518,6 @@ mod tests { use arc::*; - use core::vec; use core::cell::Cell; use core::comm; use core::task; diff --git a/src/libextra/arena.rs b/src/libextra/arena.rs index 604d9ba7373..2c6e7a30448 100644 --- a/src/libextra/arena.rs +++ b/src/libextra/arena.rs @@ -65,7 +65,8 @@ struct Chunk { is_pod: bool, } -#[mutable] +#[mutable] // XXX remove after snap +#[no_freeze] pub struct Arena { // The head is separated out from the list as a unbenchmarked // microoptimization, to avoid needing to case on the list to @@ -186,20 +187,18 @@ impl Arena { #[inline] fn alloc_pod_inner(&mut self, n_bytes: uint, align: uint) -> *u8 { unsafe { - // XXX: Borrow check - let head = transmute_mut_region(&mut self.pod_head); - - let start = round_up_to(head.fill, align); + let this = transmute_mut_region(self); + let start = round_up_to(this.pod_head.fill, align); let end = start + n_bytes; - if end > at_vec::capacity(head.data) { - return self.alloc_pod_grow(n_bytes, align); + if end > at_vec::capacity(this.pod_head.data) { + return this.alloc_pod_grow(n_bytes, align); } - head.fill = end; + this.pod_head.fill = end; //debug!("idx = %u, size = %u, align = %u, fill = %u", // start, n_bytes, align, head.fill); - ptr::offset(vec::raw::to_ptr(head.data), start) + ptr::offset(vec::raw::to_ptr(this.pod_head.data), start) } } @@ -231,21 +230,31 @@ impl Arena { fn alloc_nonpod_inner(&mut self, n_bytes: uint, align: uint) -> (*u8, *u8) { unsafe { - let head = transmute_mut_region(&mut self.head); + let start; + let end; + let tydesc_start; + let after_tydesc; + + { + let head = transmute_mut_region(&mut self.head); + + tydesc_start = head.fill; + after_tydesc = head.fill + sys::size_of::<*TyDesc>(); + start = round_up_to(after_tydesc, align); + end = start + n_bytes; + } - let tydesc_start = head.fill; - let after_tydesc = head.fill + sys::size_of::<*TyDesc>(); - let start = round_up_to(after_tydesc, align); - let end = start + n_bytes; - if end > at_vec::capacity(head.data) { + if end > at_vec::capacity(self.head.data) { return self.alloc_nonpod_grow(n_bytes, align); } + + let head = transmute_mut_region(&mut self.head); head.fill = round_up_to(end, sys::pref_align_of::<*TyDesc>()); //debug!("idx = %u, size = %u, align = %u, fill = %u", // start, n_bytes, align, head.fill); - let buf = vec::raw::to_ptr(head.data); + let buf = vec::raw::to_ptr(self.head.data); return (ptr::offset(buf, tydesc_start), ptr::offset(buf, start)); } } diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index 6e4507d4277..4fe7761bf18 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -476,9 +476,15 @@ impl Bitv { * character is either '0' or '1'. */ pub fn to_str(&self) -> ~str { - let mut rs = ~""; - for self.each() |i| { if i { rs += "1"; } else { rs += "0"; } }; - rs + let mut rs = ~""; + for self.each() |i| { + if i { + rs.push_char('1'); + } else { + rs.push_char('0'); + } + }; + rs } diff --git a/src/libextra/c_vec.rs b/src/libextra/c_vec.rs index 84593630cab..79ef5bf2b7e 100644 --- a/src/libextra/c_vec.rs +++ b/src/libextra/c_vec.rs @@ -159,8 +159,7 @@ mod tests { assert!(mem as int != 0); - return c_vec_with_dtor(mem as *mut u8, n as uint, - || unsafe { free(mem) }); + c_vec_with_dtor(mem as *mut u8, n as uint, || free(mem)) } } diff --git a/src/libextra/comm.rs b/src/libextra/comm.rs index 1001d4f6ac9..2cb2128db5f 100644 --- a/src/libextra/comm.rs +++ b/src/libextra/comm.rs @@ -30,7 +30,7 @@ pub struct DuplexStream<T, U> { } // Allow these methods to be used without import: -impl<T:Owned,U:Owned> DuplexStream<T, U> { +impl<T:Send,U:Send> DuplexStream<T, U> { pub fn send(&self, x: T) { self.chan.send(x) } @@ -48,19 +48,19 @@ impl<T:Owned,U:Owned> DuplexStream<T, U> { } } -impl<T:Owned,U:Owned> GenericChan<T> for DuplexStream<T, U> { +impl<T:Send,U:Send> GenericChan<T> for DuplexStream<T, U> { fn send(&self, x: T) { self.chan.send(x) } } -impl<T:Owned,U:Owned> GenericSmartChan<T> for DuplexStream<T, U> { +impl<T:Send,U:Send> GenericSmartChan<T> for DuplexStream<T, U> { fn try_send(&self, x: T) -> bool { self.chan.try_send(x) } } -impl<T:Owned,U:Owned> GenericPort<U> for DuplexStream<T, U> { +impl<T:Send,U:Send> GenericPort<U> for DuplexStream<T, U> { fn recv(&self) -> U { self.port.recv() } @@ -70,20 +70,20 @@ impl<T:Owned,U:Owned> GenericPort<U> for DuplexStream<T, U> { } } -impl<T:Owned,U:Owned> Peekable<U> for DuplexStream<T, U> { +impl<T:Send,U:Send> Peekable<U> for DuplexStream<T, U> { fn peek(&self) -> bool { self.port.peek() } } -impl<T:Owned,U:Owned> Selectable for DuplexStream<T, U> { +impl<T:Send,U:Send> Selectable for DuplexStream<T, U> { fn header(&mut self) -> *mut pipes::PacketHeader { self.port.header() } } /// Creates a bidirectional stream. -pub fn DuplexStream<T:Owned,U:Owned>() +pub fn DuplexStream<T:Send,U:Send>() -> (DuplexStream<T, U>, DuplexStream<U, T>) { let (p1, c2) = comm::stream(); diff --git a/src/libextra/crypto/digest.rs b/src/libextra/crypto/digest.rs index 8fd44bfc9ab..c4fb03a7a7d 100644 --- a/src/libextra/crypto/digest.rs +++ b/src/libextra/crypto/digest.rs @@ -49,9 +49,9 @@ fn to_hex(rr: &[u8]) -> ~str { for rr.iter().advance() |b| { let hex = uint::to_str_radix(*b as uint, 16u); if hex.len() == 1 { - s += "0"; + s.push_char('0'); } - s += hex; + s.push_str(hex); } return s; } diff --git a/src/libextra/crypto/sha2.rs b/src/libextra/crypto/sha2.rs index dd179fde70f..e9c6ac72212 100644 --- a/src/libextra/crypto/sha2.rs +++ b/src/libextra/crypto/sha2.rs @@ -11,7 +11,6 @@ use core::prelude::*; use core::uint; -use core::vec; use digest::Digest; @@ -118,7 +117,7 @@ impl Engine512 { } while in.len() - i >= 8 { - let w = to_u64(vec::slice(in, i, i + 8)); + let w = to_u64(in.slice(i, i + 8)); self.process_word(w); self.bit_counter.add_bytes(8); i += 8; @@ -274,43 +273,43 @@ impl Engine512 { fn result_512(&mut self, out: &mut [u8]) { self.finish(); - from_u64(self.H0, vec::mut_slice(out, 0, 8)); - from_u64(self.H1, vec::mut_slice(out, 8, 16)); - from_u64(self.H2, vec::mut_slice(out, 16, 24)); - from_u64(self.H3, vec::mut_slice(out, 24, 32)); - from_u64(self.H4, vec::mut_slice(out, 32, 40)); - from_u64(self.H5, vec::mut_slice(out, 40, 48)); - from_u64(self.H6, vec::mut_slice(out, 48, 56)); - from_u64(self.H7, vec::mut_slice(out, 56, 64)); + from_u64(self.H0, out.mut_slice(0, 8)); + from_u64(self.H1, out.mut_slice(8, 16)); + from_u64(self.H2, out.mut_slice(16, 24)); + from_u64(self.H3, out.mut_slice(24, 32)); + from_u64(self.H4, out.mut_slice(32, 40)); + from_u64(self.H5, out.mut_slice(40, 48)); + from_u64(self.H6, out.mut_slice(48, 56)); + from_u64(self.H7, out.mut_slice(56, 64)); } fn result_384(&mut self, out: &mut [u8]) { self.finish(); - from_u64(self.H0, vec::mut_slice(out, 0, 8)); - from_u64(self.H1, vec::mut_slice(out, 8, 16)); - from_u64(self.H2, vec::mut_slice(out, 16, 24)); - from_u64(self.H3, vec::mut_slice(out, 24, 32)); - from_u64(self.H4, vec::mut_slice(out, 32, 40)); - from_u64(self.H5, vec::mut_slice(out, 40, 48)); + from_u64(self.H0, out.mut_slice(0, 8)); + from_u64(self.H1, out.mut_slice(8, 16)); + from_u64(self.H2, out.mut_slice(16, 24)); + from_u64(self.H3, out.mut_slice(24, 32)); + from_u64(self.H4, out.mut_slice(32, 40)); + from_u64(self.H5, out.mut_slice(40, 48)); } fn result_256(&mut self, out: &mut [u8]) { self.finish(); - from_u64(self.H0, vec::mut_slice(out, 0, 8)); - from_u64(self.H1, vec::mut_slice(out, 8, 16)); - from_u64(self.H2, vec::mut_slice(out, 16, 24)); - from_u64(self.H3, vec::mut_slice(out, 24, 32)); + from_u64(self.H0, out.mut_slice(0, 8)); + from_u64(self.H1, out.mut_slice(8, 16)); + from_u64(self.H2, out.mut_slice(16, 24)); + from_u64(self.H3, out.mut_slice(24, 32)); } fn result_224(&mut self, out: &mut [u8]) { self.finish(); - from_u64(self.H0, vec::mut_slice(out, 0, 8)); - from_u64(self.H1, vec::mut_slice(out, 8, 16)); - from_u64(self.H2, vec::mut_slice(out, 16, 24)); - from_u32((self.H3 >> 32) as u32, vec::mut_slice(out, 24, 28)); + from_u64(self.H0, out.mut_slice(0, 8)); + from_u64(self.H1, out.mut_slice(8, 16)); + from_u64(self.H2, out.mut_slice(16, 24)); + from_u32((self.H3 >> 32) as u32, out.mut_slice(24, 28)); } } @@ -400,7 +399,7 @@ impl Engine256 { } while in.len() - i >= 4 { - let w = to_u32(vec::slice(in, i, i + 4)); + let w = to_u32(in.slice(i, i + 4)); self.process_word(w); self.length_bytes += 4; i += 4; @@ -556,26 +555,26 @@ impl Engine256 { fn result_256(&mut self, out: &mut [u8]) { self.finish(); - from_u32(self.H0, vec::mut_slice(out, 0, 4)); - from_u32(self.H1, vec::mut_slice(out, 4, 8)); - from_u32(self.H2, vec::mut_slice(out, 8, 12)); - from_u32(self.H3, vec::mut_slice(out, 12, 16)); - from_u32(self.H4, vec::mut_slice(out, 16, 20)); - from_u32(self.H5, vec::mut_slice(out, 20, 24)); - from_u32(self.H6, vec::mut_slice(out, 24, 28)); - from_u32(self.H7, vec::mut_slice(out, 28, 32)); + from_u32(self.H0, out.mut_slice(0, 4)); + from_u32(self.H1, out.mut_slice(4, 8)); + from_u32(self.H2, out.mut_slice(8, 12)); + from_u32(self.H3, out.mut_slice(12, 16)); + from_u32(self.H4, out.mut_slice(16, 20)); + from_u32(self.H5, out.mut_slice(20, 24)); + from_u32(self.H6, out.mut_slice(24, 28)); + from_u32(self.H7, out.mut_slice(28, 32)); } fn result_224(&mut self, out: &mut [u8]) { self.finish(); - from_u32(self.H0, vec::mut_slice(out, 0, 4)); - from_u32(self.H1, vec::mut_slice(out, 4, 8)); - from_u32(self.H2, vec::mut_slice(out, 8, 12)); - from_u32(self.H3, vec::mut_slice(out, 12, 16)); - from_u32(self.H4, vec::mut_slice(out, 16, 20)); - from_u32(self.H5, vec::mut_slice(out, 20, 24)); - from_u32(self.H6, vec::mut_slice(out, 24, 28)); + from_u32(self.H0, out.mut_slice(0, 4)); + from_u32(self.H1, out.mut_slice(4, 8)); + from_u32(self.H2, out.mut_slice(8, 12)); + from_u32(self.H3, out.mut_slice(12, 16)); + from_u32(self.H4, out.mut_slice(16, 20)); + from_u32(self.H5, out.mut_slice(20, 24)); + from_u32(self.H6, out.mut_slice(24, 28)); } } diff --git a/src/libextra/deque.rs b/src/libextra/deque.rs index e6a7dd64837..c70c87b6ea1 100644 --- a/src/libextra/deque.rs +++ b/src/libextra/deque.rs @@ -137,7 +137,7 @@ impl<T> Deque<T> { /// /// * n - The number of elements to reserve space for pub fn reserve(&mut self, n: uint) { - vec::reserve(&mut self.elts, n); + self.elts.reserve(n); } /// Reserve capacity for at least `n` elements in the given deque, @@ -151,7 +151,7 @@ impl<T> Deque<T> { /// /// * n - The number of elements to reserve space for pub fn reserve_at_least(&mut self, n: uint) { - vec::reserve_at_least(&mut self.elts, n); + self.elts.reserve_at_least(n); } /// Front-to-back iterator. @@ -256,7 +256,6 @@ mod tests { use super::*; use core::cmp::Eq; use core::kinds::Copy; - use core::vec::capacity; use core; #[test] @@ -442,11 +441,11 @@ mod tests { let mut d = Deque::new(); d.add_back(0u64); d.reserve(50); - assert_eq!(capacity(&mut d.elts), 50); + assert_eq!(d.elts.capacity(), 50); let mut d = Deque::new(); d.add_back(0u32); d.reserve(50); - assert_eq!(capacity(&mut d.elts), 50); + assert_eq!(d.elts.capacity(), 50); } #[test] @@ -454,11 +453,11 @@ mod tests { let mut d = Deque::new(); d.add_back(0u64); d.reserve_at_least(50); - assert_eq!(capacity(&mut d.elts), 64); + assert_eq!(d.elts.capacity(), 64); let mut d = Deque::new(); d.add_back(0u32); d.reserve_at_least(50); - assert_eq!(capacity(&mut d.elts), 64); + assert_eq!(d.elts.capacity(), 64); } #[test] diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index 1767aa8c397..ee86340e47b 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -526,8 +526,6 @@ mod tests { use super::*; - use core::vec; - #[test] fn test_dlist_concat() { let a = from_vec([1,2]); diff --git a/src/libextra/ebml.rs b/src/libextra/ebml.rs index dd08f23a7a1..4634a7db05e 100644 --- a/src/libextra/ebml.rs +++ b/src/libextra/ebml.rs @@ -12,6 +12,8 @@ use core::prelude::*; +use core::str; + // Simple Extensible Binary Markup Language (ebml) reader and writer on a // cursor model. See the specification here: // http://www.matroska.org/technical/specs/rfc/index.html @@ -34,6 +36,20 @@ pub struct Doc { end: uint, } +impl Doc { + pub fn get(&self, tag: uint) -> Doc { + reader::get_doc(*self, tag) + } + + pub fn as_str_slice<'a>(&'a self) -> &'a str { + str::from_bytes_slice(self.data.slice(self.start, self.end)) + } + + pub fn as_str(&self) -> ~str { + self.as_str_slice().to_owned() + } +} + pub struct TaggedDoc { tag: uint, doc: Doc, @@ -78,31 +94,21 @@ pub mod reader { use serialize; - use core::prelude::*; use core::cast::transmute; use core::int; use core::io; + use core::option::{None, Option, Some}; + + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "x86_64")] use core::ptr::offset; - use core::str; + + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "x86_64")] use core::unstable::intrinsics::bswap32; - use core::vec; // ebml reading - impl Doc { - pub fn get(&self, tag: uint) -> Doc { - get_doc(*self, tag) - } - - pub fn as_str_slice<'a>(&'a self) -> &'a str { - str::from_bytes_slice(self.data.slice(self.start, self.end)) - } - - pub fn as_str(&self) -> ~str { - self.as_str_slice().to_owned() - } - } - struct Res { val: uint, next: uint @@ -248,7 +254,7 @@ pub mod reader { } pub fn with_doc_data<T>(d: Doc, f: &fn(x: &[u8]) -> T) -> T { - f(vec::slice(*d.data, d.start, d.end)) + f(d.data.slice(d.start, d.end)) } diff --git a/src/libextra/flatpipes.rs b/src/libextra/flatpipes.rs index 60fbfdeb62c..d5e43e85a14 100644 --- a/src/libextra/flatpipes.rs +++ b/src/libextra/flatpipes.rs @@ -166,8 +166,8 @@ Constructors for flat pipes that send POD types using memcpy. # Safety Note -This module is currently unsafe because it uses `Copy Owned` as a type -parameter bounds meaning POD (plain old data), but `Copy Owned` and +This module is currently unsafe because it uses `Copy Send` as a type +parameter bounds meaning POD (plain old data), but `Copy Send` and POD are not equivelant. */ @@ -191,7 +191,7 @@ pub mod pod { pub type PipeChan<T> = FlatChan<T, PodFlattener<T>, PipeByteChan>; /// Create a `FlatPort` from a `Reader` - pub fn reader_port<T:Copy + Owned,R:Reader>( + pub fn reader_port<T:Copy + Send,R:Reader>( reader: R ) -> ReaderPort<T, R> { let unflat: PodUnflattener<T> = PodUnflattener::new(); @@ -200,7 +200,7 @@ pub mod pod { } /// Create a `FlatChan` from a `Writer` - pub fn writer_chan<T:Copy + Owned,W:Writer>( + pub fn writer_chan<T:Copy + Send,W:Writer>( writer: W ) -> WriterChan<T, W> { let flat: PodFlattener<T> = PodFlattener::new(); @@ -209,21 +209,21 @@ pub mod pod { } /// Create a `FlatPort` from a `Port<~[u8]>` - pub fn pipe_port<T:Copy + Owned>(port: Port<~[u8]>) -> PipePort<T> { + pub fn pipe_port<T:Copy + Send>(port: Port<~[u8]>) -> PipePort<T> { let unflat: PodUnflattener<T> = PodUnflattener::new(); let byte_port = PipeBytePort::new(port); FlatPort::new(unflat, byte_port) } /// Create a `FlatChan` from a `Chan<~[u8]>` - pub fn pipe_chan<T:Copy + Owned>(chan: Chan<~[u8]>) -> PipeChan<T> { + pub fn pipe_chan<T:Copy + Send>(chan: Chan<~[u8]>) -> PipeChan<T> { let flat: PodFlattener<T> = PodFlattener::new(); let byte_chan = PipeByteChan::new(chan); FlatChan::new(flat, byte_chan) } /// Create a pair of `FlatChan` and `FlatPort`, backed by pipes - pub fn pipe_stream<T:Copy + Owned>() -> (PipePort<T>, PipeChan<T>) { + pub fn pipe_stream<T:Copy + Send>() -> (PipePort<T>, PipeChan<T>) { let (port, chan) = comm::stream(); return (pipe_port(port), pipe_chan(chan)); } @@ -352,7 +352,7 @@ pub mod flatteners { use core::sys::size_of; use core::vec; - // FIXME #4074: Copy + Owned != POD + // FIXME #4074: Copy + Send != POD pub struct PodUnflattener<T> { bogus: () } @@ -361,7 +361,7 @@ pub mod flatteners { bogus: () } - impl<T:Copy + Owned> Unflattener<T> for PodUnflattener<T> { + impl<T:Copy + Send> Unflattener<T> for PodUnflattener<T> { fn unflatten(&self, buf: ~[u8]) -> T { assert!(size_of::<T>() != 0); assert_eq!(size_of::<T>(), buf.len()); @@ -371,7 +371,7 @@ pub mod flatteners { } } - impl<T:Copy + Owned> Flattener<T> for PodFlattener<T> { + impl<T:Copy + Send> Flattener<T> for PodFlattener<T> { fn flatten(&self, val: T) -> ~[u8] { assert!(size_of::<T>() != 0); let val: *T = ptr::to_unsafe_ptr(&val); @@ -380,7 +380,7 @@ pub mod flatteners { } } - impl<T:Copy + Owned> PodUnflattener<T> { + impl<T:Copy + Send> PodUnflattener<T> { pub fn new() -> PodUnflattener<T> { PodUnflattener { bogus: () @@ -388,7 +388,7 @@ pub mod flatteners { } } - impl<T:Copy + Owned> PodFlattener<T> { + impl<T:Copy + Send> PodFlattener<T> { pub fn new() -> PodFlattener<T> { PodFlattener { bogus: () diff --git a/src/libextra/fun_treemap.rs b/src/libextra/fun_treemap.rs index eb8c27e9902..5906e809c98 100644 --- a/src/libextra/fun_treemap.rs +++ b/src/libextra/fun_treemap.rs @@ -66,9 +66,9 @@ pub fn traverse<K, V: Copy>(m: Treemap<K, V>, f: &fn(&K, &V)) { // matches to me, so I changed it. but that may be a // de-optimization -- tjc Node(@ref k, @ref v, left, right) => { - traverse(left, f); + traverse(left, |k,v| f(k,v)); f(k, v); - traverse(right, f); + traverse(right, |k,v| f(k,v)); } } } diff --git a/src/libextra/future.rs b/src/libextra/future.rs index f2cd64085ef..00f4cc3989b 100644 --- a/src/libextra/future.rs +++ b/src/libextra/future.rs @@ -101,7 +101,7 @@ pub fn from_value<A>(val: A) -> Future<A> { Future {state: Forced(val)} } -pub fn from_port<A:Owned>(port: PortOne<A>) -> Future<A> { +pub fn from_port<A:Send>(port: PortOne<A>) -> Future<A> { /*! * Create a future from a port * @@ -127,7 +127,7 @@ pub fn from_fn<A>(f: ~fn() -> A) -> Future<A> { Future {state: Pending(f)} } -pub fn spawn<A:Owned>(blk: ~fn() -> A) -> Future<A> { +pub fn spawn<A:Send>(blk: ~fn() -> A) -> Future<A> { /*! * Create a future from a unique closure. * diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs index 9c416550eb7..fa064e6330e 100644 --- a/src/libextra/getopts.rs +++ b/src/libextra/getopts.rs @@ -606,33 +606,47 @@ pub mod groups { let mut row = " ".repeat(4); // short option - row += match short_name.len() { - 0 => ~"", - 1 => ~"-" + short_name + " ", + match short_name.len() { + 0 => {} + 1 => { + row.push_char('-'); + row.push_str(short_name); + row.push_char(' '); + } _ => fail!("the short name should only be 1 ascii char long"), - }; + } // long option - row += match long_name.len() { - 0 => ~"", - _ => ~"--" + long_name + " ", - }; + match long_name.len() { + 0 => {} + _ => { + row.push_str("--"); + row.push_str(long_name); + row.push_char(' '); + } + } // arg - row += match hasarg { - No => ~"", - Yes => hint, - Maybe => ~"[" + hint + "]", - }; + match hasarg { + No => {} + Yes => row.push_str(hint), + Maybe => { + row.push_char('['); + row.push_str(hint); + row.push_char(']'); + } + } // FIXME: #5516 // here we just need to indent the start of the description let rowlen = row.len(); - row += if rowlen < 24 { - " ".repeat(24 - rowlen) + if rowlen < 24 { + for (24 - rowlen).times { + row.push_char(' ') + } } else { - copy desc_sep - }; + row.push_str(desc_sep) + } // Normalize desc to contain words separated by one space character let mut desc_normalized_whitespace = ~""; @@ -649,7 +663,7 @@ pub mod groups { // FIXME: #5516 // wrapped description - row += desc_rows.connect(desc_sep); + row.push_str(desc_rows.connect(desc_sep)); row }); diff --git a/src/libextra/json.rs b/src/libextra/json.rs index 15553b035f6..a71be18174a 100644 --- a/src/libextra/json.rs +++ b/src/libextra/json.rs @@ -60,25 +60,27 @@ fn escape_str(s: &str) -> ~str { let mut escaped = ~"\""; for s.iter().advance |c| { match c { - '"' => escaped += "\\\"", - '\\' => escaped += "\\\\", - '\x08' => escaped += "\\b", - '\x0c' => escaped += "\\f", - '\n' => escaped += "\\n", - '\r' => escaped += "\\r", - '\t' => escaped += "\\t", - _ => escaped += str::from_char(c) + '"' => escaped.push_str("\\\""), + '\\' => escaped.push_str("\\\\"), + '\x08' => escaped.push_str("\\b"), + '\x0c' => escaped.push_str("\\f"), + '\n' => escaped.push_str("\\n"), + '\r' => escaped.push_str("\\r"), + '\t' => escaped.push_str("\\t"), + _ => escaped.push_char(c), } }; - escaped += "\""; + escaped.push_char('"'); escaped } fn spaces(n: uint) -> ~str { let mut ss = ~""; - for n.times { ss.push_str(" "); } + for n.times { + ss.push_str(" "); + } return ss; } diff --git a/src/libextra/md4.rs b/src/libextra/md4.rs index 6c972a313c4..3be7394b46d 100644 --- a/src/libextra/md4.rs +++ b/src/libextra/md4.rs @@ -59,7 +59,8 @@ pub fn md4(msg: &[u8]) -> Quad { while i < e { let (aa, bb, cc, dd) = (a, b, c, d); - let mut (j, base) = (0u, i); + let mut j = 0u; + let mut base = i; while j < 16u { x[j] = (msg[base] as u32) + (msg[base + 1u] as u32 << 8u32) + (msg[base + 2u] as u32 << 16u32) + @@ -118,8 +119,10 @@ pub fn md4_str(msg: &[u8]) -> ~str { let mut i = 0u32; while i < 4u32 { let byte = (u >> (i * 8u32)) as u8; - if byte <= 16u8 { result += "0"; } - result += uint::to_str_radix(byte as uint, 16u); + if byte <= 16u8 { + result.push_char('0') + } + result.push_str(uint::to_str_radix(byte as uint, 16u)); i += 1u32; } } diff --git a/src/libextra/net_tcp.rs b/src/libextra/net_tcp.rs index 6ad51931c67..f3f6ffde660 100644 --- a/src/libextra/net_tcp.rs +++ b/src/libextra/net_tcp.rs @@ -976,9 +976,7 @@ impl io::Writer for TcpSocketBuf { let socket_data_ptr: *TcpSocketData = &(*((*(self.data)).sock).socket_data); let w_result = write_common_impl(socket_data_ptr, - vec::slice(data, - 0, - data.len()).to_owned()); + data.slice(0, data.len()).to_owned()); if w_result.is_err() { let err_data = w_result.get_err(); debug!( @@ -1459,33 +1457,23 @@ mod test { #[test] fn test_gl_tcp_server_and_client_ipv4() { - unsafe { - impl_gl_tcp_ipv4_server_and_client(); - } + impl_gl_tcp_ipv4_server_and_client(); } #[test] fn test_gl_tcp_get_peer_addr() { - unsafe { - impl_gl_tcp_ipv4_get_peer_addr(); - } + impl_gl_tcp_ipv4_get_peer_addr(); } #[test] fn test_gl_tcp_ipv4_client_error_connection_refused() { - unsafe { - impl_gl_tcp_ipv4_client_error_connection_refused(); - } + impl_gl_tcp_ipv4_client_error_connection_refused(); } #[test] fn test_gl_tcp_server_address_in_use() { - unsafe { - impl_gl_tcp_ipv4_server_address_in_use(); - } + impl_gl_tcp_ipv4_server_address_in_use(); } #[test] fn test_gl_tcp_server_access_denied() { - unsafe { - impl_gl_tcp_ipv4_server_access_denied(); - } + impl_gl_tcp_ipv4_server_access_denied(); } // Strange failure on Windows. --pcwalton #[test] diff --git a/src/libextra/net_url.rs b/src/libextra/net_url.rs index 5d3d31fdec4..a60f51e751e 100644 --- a/src/libextra/net_url.rs +++ b/src/libextra/net_url.rs @@ -93,10 +93,10 @@ fn encode_inner(s: &str, full_url: bool) -> ~str { out.push_char(ch); } - _ => out += fmt!("%%%X", ch as uint) + _ => out.push_str(fmt!("%%%X", ch as uint)) } } else { - out += fmt!("%%%X", ch as uint); + out.push_str(fmt!("%%%X", ch as uint)); } } } @@ -192,7 +192,7 @@ fn encode_plus(s: &str) -> ~str { out.push_char(ch); } ' ' => out.push_char('+'), - _ => out += fmt!("%%%X", ch as uint) + _ => out.push_str(fmt!("%%%X", ch as uint)) } } @@ -218,7 +218,7 @@ pub fn encode_form_urlencoded(m: &HashMap<~str, ~[~str]>) -> ~str { first = false; } - out += fmt!("%s=%s", key, encode_plus(*value)); + out.push_str(fmt!("%s=%s", key, encode_plus(*value))); } } @@ -415,7 +415,9 @@ fn get_authority(rawurl: &str) -> let mut port = None; let mut colon_count = 0; - let mut (pos, begin, end) = (0, 2, len); + let mut pos = 0; + let mut begin = 2; + let mut end = len; for rawurl.iter().enumerate().advance |(i,c)| { if i < 2 { loop; } // ignore the leading // diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 4b080e0153c..002d8a7f956 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -298,9 +298,8 @@ impl Mul<BigUint, BigUint> for BigUint { fn cut_at(a: &BigUint, n: uint) -> (BigUint, BigUint) { let mid = uint::min(a.data.len(), n); - return (BigUint::from_slice(vec::slice(a.data, mid, - a.data.len())), - BigUint::from_slice(vec::slice(a.data, 0, mid))); + return (BigUint::from_slice(a.data.slice(mid, a.data.len())), + BigUint::from_slice(a.data.slice(0, mid))); } @@ -381,7 +380,8 @@ impl Integer for BigUint { let mut d = Zero::zero::<BigUint>(); let mut n = 1; while m >= b { - let mut (d0, d_unit, b_unit) = div_estimate(&m, &b, n); + let (d0, d_unit, b_unit) = div_estimate(&m, &b, n); + let mut d0 = d0; let mut prod = b * d0; while prod > m { // FIXME(#6050): overloaded operators force moves with generic types @@ -413,7 +413,7 @@ impl Integer for BigUint { return (Zero::zero(), Zero::zero(), copy *a); } - let an = vec::slice(a.data, a.data.len() - n, a.data.len()); + let an = a.data.slice(a.data.len() - n, a.data.len()); let bn = *b.data.last(); let mut d = ~[]; let mut carry = 0; @@ -443,7 +443,8 @@ impl Integer for BigUint { fn gcd(&self, other: &BigUint) -> BigUint { // Use Euclid's algorithm - let mut (m, n) = (copy *self, copy *other); + let mut m = copy *self; + let mut n = copy *other; while !m.is_zero() { let temp = m; m = n % temp; @@ -507,11 +508,11 @@ impl ToStrRadix for BigUint { let mut m = n; while m > divider { let (d, m0) = m.div_mod_floor(÷r); - result += [m0.to_uint() as BigDigit]; + result.push(m0.to_uint() as BigDigit); m = d; } if !m.is_zero() { - result += [m.to_uint() as BigDigit]; + result.push(m.to_uint() as BigDigit); } return result; } @@ -578,7 +579,7 @@ impl BigUint { let mut power: BigUint = One::one(); loop { let start = uint::max(end, unit_len) - unit_len; - match uint::parse_bytes(vec::slice(buf, start, end), radix) { + match uint::parse_bytes(buf.slice(start, end), radix) { // FIXME(#6102): Assignment operator for BigInt causes ICE // Some(d) => n += BigUint::from_uint(d) * power, Some(d) => n = n + BigUint::from_uint(d) * power, @@ -634,7 +635,7 @@ impl BigUint { if n_unit == 0 { return copy *self; } if self.data.len() < n_unit { return Zero::zero(); } return BigUint::from_slice( - vec::slice(self.data, n_unit, self.data.len()) + self.data.slice(n_unit, self.data.len()) ); } @@ -1132,7 +1133,7 @@ impl BigInt { sign = Minus; start = 1; } - return BigUint::parse_bytes(vec::slice(buf, start, buf.len()), radix) + return BigUint::parse_bytes(buf.slice(start, buf.len()), radix) .map_consume(|bu| BigInt::from_biguint(sign, bu)); } @@ -1176,7 +1177,7 @@ mod biguint_tests { let data = [ &[], &[1], &[2], &[-1], &[0, 1], &[2, 1], &[1, 1, 1] ] .map(|v| BigUint::from_slice(*v)); for data.iter().enumerate().advance |(i, ni)| { - for vec::slice(data, i, data.len()).iter().enumerate().advance |(j0, nj)| { + for data.slice(i, data.len()).iter().enumerate().advance |(j0, nj)| { let j = j0 + i; if i == j { assert_eq!(ni.cmp(nj), Equal); @@ -1654,7 +1655,7 @@ mod bigint_tests { nums.push_all_move(vs.map(|s| BigInt::from_slice(Plus, *s))); for nums.iter().enumerate().advance |(i, ni)| { - for vec::slice(nums, i, nums.len()).iter().enumerate().advance |(j0, nj)| { + for nums.slice(i, nums.len()).iter().enumerate().advance |(j0, nj)| { let j = i + j0; if i == j { assert_eq!(ni.cmp(nj), Equal); diff --git a/src/libextra/par.rs b/src/libextra/par.rs index 334ab7c9c99..a3014cf8894 100644 --- a/src/libextra/par.rs +++ b/src/libextra/par.rs @@ -33,7 +33,7 @@ static min_granularity : uint = 1024u; * This is used to build most of the other parallel vector functions, * like map or alli. */ -fn map_slices<A:Copy + Owned,B:Copy + Owned>( +fn map_slices<A:Copy + Send,B:Copy + Send>( xs: &[A], f: &fn() -> ~fn(uint, v: &[A]) -> B) -> ~[B] { @@ -88,7 +88,7 @@ fn map_slices<A:Copy + Owned,B:Copy + Owned>( } /// A parallel version of map. -pub fn map<A:Copy + Owned,B:Copy + Owned>( +pub fn map<A:Copy + Send,B:Copy + Send>( xs: &[A], fn_factory: &fn() -> ~fn(&A) -> B) -> ~[B] { vec::concat(map_slices(xs, || { let f = fn_factory(); @@ -99,7 +99,7 @@ pub fn map<A:Copy + Owned,B:Copy + Owned>( } /// A parallel version of mapi. -pub fn mapi<A:Copy + Owned,B:Copy + Owned>( +pub fn mapi<A:Copy + Send,B:Copy + Send>( xs: &[A], fn_factory: &fn() -> ~fn(uint, &A) -> B) -> ~[B] { let slices = map_slices(xs, || { @@ -118,7 +118,7 @@ pub fn mapi<A:Copy + Owned,B:Copy + Owned>( } /// Returns true if the function holds for all elements in the vector. -pub fn alli<A:Copy + Owned>( +pub fn alli<A:Copy + Send>( xs: &[A], fn_factory: &fn() -> ~fn(uint, &A) -> bool) -> bool { @@ -133,7 +133,7 @@ pub fn alli<A:Copy + Owned>( } /// Returns true if the function holds for any elements in the vector. -pub fn any<A:Copy + Owned>( +pub fn any<A:Copy + Send>( xs: &[A], fn_factory: &fn() -> ~fn(&A) -> bool) -> bool { let mapped = map_slices(xs, || { diff --git a/src/libextra/priority_queue.rs b/src/libextra/priority_queue.rs index af891edf9e5..fbb4be0febb 100644 --- a/src/libextra/priority_queue.rs +++ b/src/libextra/priority_queue.rs @@ -52,12 +52,12 @@ impl<T:Ord> PriorityQueue<T> { } /// Returns the number of elements the queue can hold without reallocating - pub fn capacity(&self) -> uint { vec::capacity(&self.data) } + pub fn capacity(&self) -> uint { self.data.capacity() } - pub fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) } + pub fn reserve(&mut self, n: uint) { self.data.reserve(n) } pub fn reserve_at_least(&mut self, n: uint) { - vec::reserve_at_least(&mut self.data, n) + self.data.reserve_at_least(n) } /// Pop the greatest item from the queue - fails if empty diff --git a/src/libextra/rc.rs b/src/libextra/rc.rs index 8ef58a188d9..613c0b1ae41 100644 --- a/src/libextra/rc.rs +++ b/src/libextra/rc.rs @@ -13,10 +13,10 @@ /** Task-local reference counted smart pointers Task-local reference counted smart pointers are an alternative to managed boxes with deterministic -destruction. They are restricted to containing types that are either `Owned` or `Const` (or both) to +destruction. They are restricted to containing types that are either `Send` or `Freeze` (or both) to prevent cycles. -Neither `Rc<T>` or `RcMut<T>` is ever `Owned` and `RcMut<T>` is never `Const`. If `T` is `Const`, a +Neither `Rc<T>` or `RcMut<T>` is ever `Send` and `RcMut<T>` is never `Freeze`. If `T` is `Freeze`, a cycle cannot be created with `Rc<T>` because there is no way to modify it after creation. */ @@ -35,7 +35,8 @@ struct RcBox<T> { } /// Immutable reference counted pointer type -#[non_owned] +#[unsafe_no_drop_flag] +#[no_send] pub struct Rc<T> { priv ptr: *mut RcBox<T>, } @@ -50,12 +51,12 @@ impl<T> Rc<T> { } // FIXME: #6516: should be a static method -pub fn rc_from_owned<T: Owned>(value: T) -> Rc<T> { +pub fn rc_from_owned<T: Send>(value: T) -> Rc<T> { unsafe { Rc::new(value) } } // FIXME: #6516: should be a static method -pub fn rc_from_const<T: Const>(value: T) -> Rc<T> { +pub fn rc_from_const<T: Freeze>(value: T) -> Rc<T> { unsafe { Rc::new(value) } } @@ -167,7 +168,10 @@ struct RcMutBox<T> { /// Mutable reference counted pointer type #[non_owned] -#[mutable] +#[no_send] +#[mutable] // XXX remove after snap +#[no_freeze] +#[unsafe_no_drop_flag] pub struct RcMut<T> { priv ptr: *mut RcMutBox<T>, } @@ -182,12 +186,12 @@ impl<T> RcMut<T> { } // FIXME: #6516: should be a static method -pub fn rc_mut_from_owned<T: Owned>(value: T) -> RcMut<T> { +pub fn rc_mut_from_owned<T: Send>(value: T) -> RcMut<T> { unsafe { RcMut::new(value) } } // FIXME: #6516: should be a static method -pub fn rc_mut_from_const<T: Const>(value: T) -> RcMut<T> { +pub fn rc_mut_from_const<T: Freeze>(value: T) -> RcMut<T> { unsafe { RcMut::new(value) } } diff --git a/src/libextra/rope.rs b/src/libextra/rope.rs index fed73256c00..71393ff9fae 100644 --- a/src/libextra/rope.rs +++ b/src/libextra/rope.rs @@ -1078,7 +1078,7 @@ pub mod node { pub fn loop_chars(node: @Node, it: &fn(c: char) -> bool) -> bool { return loop_leaves(node,|leaf| { - leaf.content.slice(leaf.byte_offset, leaf.byte_len).iter().all(it) + leaf.content.slice(leaf.byte_offset, leaf.byte_len).iter().all(|c| it(c)) }); } @@ -1101,7 +1101,7 @@ pub mod node { loop { match (*current) { Leaf(x) => return it(x), - Concat(ref x) => if loop_leaves(x.left, it) { //non tail call + Concat(ref x) => if loop_leaves(x.left, |l| it(l)) { //non tail call current = x.right; //tail call } else { return false; diff --git a/src/libextra/sort.rs b/src/libextra/sort.rs index 3c872d64ca0..10dbe2326d7 100644 --- a/src/libextra/sort.rs +++ b/src/libextra/sort.rs @@ -42,7 +42,8 @@ pub fn merge_sort<T:Copy>(v: &[T], le: Le<T>) -> ~[T] { let mid = v_len / 2 + begin; let a = (begin, mid); let b = (mid, end); - return merge(le, merge_sort_(v, a, le), merge_sort_(v, b, le)); + return merge(|x,y| le(x,y), merge_sort_(v, a, |x,y| le(x,y)), + merge_sort_(v, b, |x,y| le(x,y))); } fn merge<T:Copy>(le: Le<T>, a: &[T], b: &[T]) -> ~[T] { @@ -57,8 +58,8 @@ pub fn merge_sort<T:Copy>(v: &[T], le: Le<T>) -> ~[T] { a_ix += 1; } else { rs.push(copy b[b_ix]); b_ix += 1; } } - rs.push_all(vec::slice(a, a_ix, a_len)); - rs.push_all(vec::slice(b, b_ix, b_len)); + rs.push_all(a.slice(a_ix, a_len)); + rs.push_all(b.slice(b_ix, b_len)); rs } } @@ -83,10 +84,10 @@ fn qsort<T>(arr: &mut [T], left: uint, right: uint, compare_func: Le<T>) { if right > left { let pivot = (left + right) / 2u; - let new_pivot = part::<T>(arr, left, right, pivot, compare_func); + let new_pivot = part::<T>(arr, left, right, pivot, |x,y| compare_func(x,y)); if new_pivot != 0u { // Need to do this check before recursing due to overflow - qsort::<T>(arr, left, new_pivot - 1u, compare_func); + qsort::<T>(arr, left, new_pivot - 1u, |x,y| compare_func(x,y)); } qsort::<T>(arr, new_pivot + 1u, right, compare_func); } @@ -201,12 +202,12 @@ pub fn tim_sort<T:Copy + Ord>(array: &mut [T]) { loop { let run_len: uint = { // This scope contains the slice `arr` here: - let arr = vec::mut_slice(array, idx, size); + let arr = array.mut_slice(idx, size); let mut run_len: uint = count_run_ascending(arr); if run_len < min_run { let force = if remaining <= min_run {remaining} else {min_run}; - let slice = vec::mut_slice(arr, 0, force); + let slice = arr.mut_slice(0, force); binarysort(slice, run_len); run_len = force; } @@ -443,14 +444,14 @@ impl<T:Copy + Ord> MergeState<T> { } let k = { // constrain lifetime of slice below - let slice = vec::slice(array, b1, b1+l1); + let slice = array.slice(b1, b1+l1); gallop_right(&array[b2], slice, 0) }; b1 += k; l1 -= k; if l1 != 0 { let l2 = { // constrain lifetime of slice below - let slice = vec::slice(array, b2, b2+l2); + let slice = array.slice(b2, b2+l2); gallop_left(&array[b1+l1-1],slice,l2-1) }; if l2 > 0 { @@ -526,7 +527,7 @@ impl<T:Copy + Ord> MergeState<T> { assert!(len1 > 1 && len2 != 0); count1 = { - let tmp_view = vec::slice(tmp, c1, c1+len1); + let tmp_view = tmp.slice(c1, c1+len1); gallop_right(&array[c2], tmp_view, 0) }; if count1 != 0 { @@ -539,7 +540,7 @@ impl<T:Copy + Ord> MergeState<T> { if len2 == 0 { break_outer = true; break; } count2 = { - let tmp_view = vec::slice(array, c2, c2+len2); + let tmp_view = array.slice(c2, c2+len2); gallop_left(&tmp[c1], tmp_view, 0) }; if count2 != 0 { @@ -638,7 +639,7 @@ impl<T:Copy + Ord> MergeState<T> { assert!(len2 > 1 && len1 != 0); { // constrain scope of tmp_view: - let tmp_view = vec::mut_slice (array, base1, base1+len1); + let tmp_view = array.mut_slice(base1, base1+len1); count1 = len1 - gallop_right( &tmp[c2], tmp_view, len1-1); } @@ -655,7 +656,7 @@ impl<T:Copy + Ord> MergeState<T> { let count2; { // constrain scope of tmp_view - let tmp_view = vec::mut_slice(tmp, 0, len2); + let tmp_view = tmp.mut_slice(0, len2); count2 = len2 - gallop_left(&array[c1], tmp_view, len2-1); @@ -1111,7 +1112,7 @@ mod big_tests { isSorted(arr); let mut arr = if n > 4 { - let part = vec::slice(arr, 0, 4); + let part = arr.slice(0, 4); multiplyVec(part, n) } else { arr }; tim_sort(arr); // ~sort @@ -1183,7 +1184,7 @@ mod big_tests { isSorted(arr); let mut arr = if n > 4 { - let part = vec::slice(arr, 0, 4); + let part = arr.slice(0, 4); multiplyVec(part, n) } else { arr }; tim_sort(arr); // ~sort @@ -1202,7 +1203,7 @@ mod big_tests { struct LVal<'self> { val: uint, - key: &'self fn(@uint), + key: &'self fn:Copy(@uint), } #[unsafe_destructor] diff --git a/src/libextra/sync.rs b/src/libextra/sync.rs index 8cfe39c5ef2..9c6be901d98 100644 --- a/src/libextra/sync.rs +++ b/src/libextra/sync.rs @@ -86,7 +86,7 @@ struct SemInner<Q> { struct Sem<Q>(Exclusive<SemInner<Q>>); #[doc(hidden)] -fn new_sem<Q:Owned>(count: int, q: Q) -> Sem<Q> { +fn new_sem<Q:Send>(count: int, q: Q) -> Sem<Q> { Sem(exclusive(SemInner { count: count, waiters: new_waitqueue(), blocked: q })) } @@ -101,7 +101,7 @@ fn new_sem_and_signal(count: int, num_condvars: uint) } #[doc(hidden)] -impl<Q:Owned> Sem<Q> { +impl<Q:Send> Sem<Q> { pub fn acquire(&self) { unsafe { let mut waiter_nobe = None; @@ -153,7 +153,7 @@ impl Sem<()> { #[doc(hidden)] impl Sem<~[Waitqueue]> { - pub fn access<U>(&self, blk: &fn() -> U) -> U { + pub fn access_waitqueue<U>(&self, blk: &fn() -> U) -> U { let mut release = None; unsafe { do task::unkillable { @@ -175,7 +175,7 @@ struct SemReleaseGeneric<'self, Q> { sem: &'self Sem<Q> } #[doc(hidden)] #[unsafe_destructor] -impl<'self, Q:Owned> Drop for SemReleaseGeneric<'self, Q> { +impl<'self, Q:Send> Drop for SemReleaseGeneric<'self, Q> { fn drop(&self) { self.sem.release(); } @@ -381,7 +381,7 @@ impl Sem<~[Waitqueue]> { // The only other places that condvars get built are rwlock.write_cond() // and rwlock_write_mode. pub fn access_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U { - do self.access { + do self.access_waitqueue { blk(&Condvar { sem: self, order: Nothing }) } } @@ -456,7 +456,9 @@ impl Clone for Mutex { impl Mutex { /// Run a function with ownership of the mutex. - pub fn lock<U>(&self, blk: &fn() -> U) -> U { (&self.sem).access(blk) } + pub fn lock<U>(&self, blk: &fn() -> U) -> U { + (&self.sem).access_waitqueue(blk) + } /// Run a function with ownership of the mutex and a handle to a condvar. pub fn lock_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U { @@ -559,9 +561,11 @@ impl RWlock { unsafe { do task::unkillable { (&self.order_lock).acquire(); - do (&self.access_lock).access { + do (&self.access_lock).access_waitqueue { (&self.order_lock).release(); - task::rekillable(blk) + do task::rekillable { + blk() + } } } } @@ -808,7 +812,6 @@ mod tests { use core::comm; use core::result; use core::task; - use core::vec; /************************************************************************ * Semaphore tests @@ -1181,12 +1184,12 @@ mod tests { Write => x.write(blk), Downgrade => do x.write_downgrade |mode| { - (&mode).write(blk); + do mode.write { blk() }; }, DowngradeRead => do x.write_downgrade |mode| { let mode = x.downgrade(mode); - (&mode).read(blk); + do mode.read { blk() }; }, } } @@ -1339,10 +1342,10 @@ mod tests { fn lock_cond(x: &RWlock, downgrade: bool, blk: &fn(c: &Condvar)) { if downgrade { do x.write_downgrade |mode| { - (&mode).write_cond(blk) + do mode.write_cond |c| { blk(c) } } } else { - x.write_cond(blk) + do x.write_cond |c| { blk(c) } } } let x = ~RWlock(); diff --git a/src/libextra/term.rs b/src/libextra/term.rs index 9a4469cb526..d448a1588a6 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -97,7 +97,7 @@ impl Terminal { if s.is_ok() { self.out.write(s.unwrap()); } else { - warn!(s.unwrap_err()); + warn!("%s", s.unwrap_err()); } } } @@ -113,17 +113,22 @@ impl Terminal { if s.is_ok() { self.out.write(s.unwrap()); } else { - warn!(s.unwrap_err()); + warn!("%s", s.unwrap_err()); } } } pub fn reset(&self) { let mut vars = Variables::new(); - let s = expand(*self.ti.strings.find_equiv(&("op")).unwrap(), [], &mut vars); + let s = do self.ti.strings.find_equiv(&("op")) + .map_consume_default(Err(~"can't find terminfo capability `op`")) |&op| { + expand(op, [], &mut vars) + }; if s.is_ok() { self.out.write(s.unwrap()); + } else if self.num_colors > 0 { + warn!("%s", s.unwrap_err()); } else { - warn!(s.unwrap_err()); + debug!("%s", s.unwrap_err()); } } diff --git a/src/libextra/terminfo/parm.rs b/src/libextra/terminfo/parm.rs index dca890ddf51..5180a71939c 100644 --- a/src/libextra/terminfo/parm.rs +++ b/src/libextra/terminfo/parm.rs @@ -470,13 +470,14 @@ priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { FormatHex|FormatHEX => 16, FormatString => util::unreachable() }; - let mut (s,_) = match op { + let (s,_) = match op { FormatDigit => { let sign = if flags.sign { SignAll } else { SignNeg }; to_str_bytes_common(&d, radix, false, sign, DigAll) } _ => to_str_bytes_common(&(d as uint), radix, false, SignNone, DigAll) }; + let mut s = s; if flags.precision > s.len() { let mut s_ = vec::with_capacity(flags.precision); let n = flags.precision - s.len(); diff --git a/src/libextra/test.rs b/src/libextra/test.rs index 72e70943ce1..50ca96e6e21 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -19,15 +19,21 @@ use core::prelude::*; use getopts; use sort; +use stats::Stats; use term; +use time::precise_time_ns; use core::comm::{stream, SharedChan}; use core::either; use core::io; +use core::num; use core::option; +use core::rand::RngUtil; +use core::rand; use core::result; use core::task; use core::to_str::ToStr; +use core::u64; use core::uint; use core::vec; @@ -139,7 +145,7 @@ type OptRes = Either<TestOpts, ~str>; // Parses command line arguments into test options pub fn parse_opts(args: &[~str]) -> OptRes { - let args_ = vec::tail(args); + let args_ = args.tail(); let opts = ~[getopts::optflag("ignored"), getopts::optflag("test"), getopts::optflag("bench"), @@ -431,7 +437,7 @@ fn run_tests(opts: &TestOpts, callback(TeFiltered(filtered_descs)); let (filtered_tests, filtered_benchs) = - do vec::partition(filtered_tests) |e| { + do filtered_tests.partition |e| { match e.testfn { StaticTestFn(_) | DynTestFn(_) => true, StaticBenchFn(_) | DynBenchFn(_) => false @@ -609,152 +615,143 @@ fn calc_result(desc: &TestDesc, task_succeeded: bool) -> TestResult { } } -pub mod bench { - use core::prelude::*; - - use core::num; - use core::rand::RngUtil; - use core::rand; - use core::u64; - use core::vec; - use stats::Stats; - use test::{BenchHarness, BenchSamples}; - use time::precise_time_ns; - - impl BenchHarness { - /// Callback for benchmark functions to run in their body. - pub fn iter(&mut self, inner:&fn()) { - self.ns_start = precise_time_ns(); - let k = self.iterations; - for u64::range(0, k) |_| { - inner(); - } - self.ns_end = precise_time_ns(); +impl BenchHarness { + /// Callback for benchmark functions to run in their body. + pub fn iter(&mut self, inner:&fn()) { + self.ns_start = precise_time_ns(); + let k = self.iterations; + for u64::range(0, k) |_| { + inner(); } + self.ns_end = precise_time_ns(); + } - pub fn ns_elapsed(&mut self) -> u64 { - if self.ns_start == 0 || self.ns_end == 0 { - 0 - } else { - self.ns_end - self.ns_start - } + pub fn ns_elapsed(&mut self) -> u64 { + if self.ns_start == 0 || self.ns_end == 0 { + 0 + } else { + self.ns_end - self.ns_start } + } - pub fn ns_per_iter(&mut self) -> u64 { - if self.iterations == 0 { - 0 - } else { - self.ns_elapsed() / self.iterations - } + pub fn ns_per_iter(&mut self) -> u64 { + if self.iterations == 0 { + 0 + } else { + self.ns_elapsed() / self.iterations } + } - pub fn bench_n(&mut self, n: u64, f: &fn(&mut BenchHarness)) { - self.iterations = n; - debug!("running benchmark for %u iterations", - n as uint); - f(self); - } + pub fn bench_n(&mut self, n: u64, f: &fn(&mut BenchHarness)) { + self.iterations = n; + debug!("running benchmark for %u iterations", + n as uint); + f(self); + } - // This is the Go benchmark algorithm. It produces a single - // datapoint and always tries to run for 1s. - pub fn go_bench(&mut self, f: &fn(&mut BenchHarness)) { - - // Rounds a number down to the nearest power of 10. - fn round_down_10(n: u64) -> u64 { - let mut n = n; - let mut res = 1; - while n > 10 { - n = n / 10; - res *= 10; - } - res - } + // This is the Go benchmark algorithm. It produces a single + // datapoint and always tries to run for 1s. + pub fn go_bench(&mut self, f: &fn(&mut BenchHarness)) { - // Rounds x up to a number of the form [1eX, 2eX, 5eX]. - fn round_up(n: u64) -> u64 { - let base = round_down_10(n); - if n < (2 * base) { - 2 * base - } else if n < (5 * base) { - 5 * base - } else { - 10 * base - } + // Rounds a number down to the nearest power of 10. + fn round_down_10(n: u64) -> u64 { + let mut n = n; + let mut res = 1; + while n > 10 { + n = n / 10; + res *= 10; } + res + } - // Initial bench run to get ballpark figure. - let mut n = 1_u64; - self.bench_n(n, f); - - while n < 1_000_000_000 && - self.ns_elapsed() < 1_000_000_000 { - let last = n; - - // Try to estimate iter count for 1s falling back to 1bn - // iterations if first run took < 1ns. - if self.ns_per_iter() == 0 { - n = 1_000_000_000; - } else { - n = 1_000_000_000 / self.ns_per_iter(); - } - - n = u64::max(u64::min(n+n/2, 100*last), last+1); - n = round_up(n); - self.bench_n(n, f); + // Rounds x up to a number of the form [1eX, 2eX, 5eX]. + fn round_up(n: u64) -> u64 { + let base = round_down_10(n); + if n < (2 * base) { + 2 * base + } else if n < (5 * base) { + 5 * base + } else { + 10 * base } } - // This is a more statistics-driven benchmark algorithm. - // It stops as quickly as 50ms, so long as the statistical - // properties are satisfactory. If those properties are - // not met, it may run as long as the Go algorithm. - pub fn auto_bench(&mut self, f: &fn(&mut BenchHarness)) -> ~[f64] { - - let mut rng = rand::rng(); - let mut magnitude = 10; - let mut prev_madp = 0.0; + // Initial bench run to get ballpark figure. + let mut n = 1_u64; + self.bench_n(n, |x| f(x)); - loop { - let n_samples = rng.gen_uint_range(50, 60); - let n_iter = rng.gen_uint_range(magnitude, - magnitude * 2); + while n < 1_000_000_000 && + self.ns_elapsed() < 1_000_000_000 { + let last = n; - let samples = do vec::from_fn(n_samples) |_| { - self.bench_n(n_iter as u64, f); - self.ns_per_iter() as f64 - }; + // Try to estimate iter count for 1s falling back to 1bn + // iterations if first run took < 1ns. + if self.ns_per_iter() == 0 { + n = 1_000_000_000; + } else { + n = 1_000_000_000 / self.ns_per_iter(); + } - // Eliminate outliers - let med = samples.median(); - let mad = samples.median_abs_dev(); - let samples = do vec::filter(samples) |f| { - num::abs(*f - med) <= 3.0 * mad - }; + n = u64::max(u64::min(n+n/2, 100*last), last+1); + n = round_up(n); + self.bench_n(n, |x| f(x)); + } + } - debug!("%u samples, median %f, MAD=%f, %u survived filter", - n_samples, med as float, mad as float, - samples.len()); - - if samples.len() != 0 { - // If we have _any_ cluster of signal... - let curr_madp = samples.median_abs_dev_pct(); - if self.ns_elapsed() > 1_000_000 && - (curr_madp < 1.0 || - num::abs(curr_madp - prev_madp) < 0.1) { - return samples; - } - prev_madp = curr_madp; - - if n_iter > 20_000_000 || - self.ns_elapsed() > 20_000_000 { - return samples; - } + // This is a more statistics-driven benchmark algorithm. + // It stops as quickly as 50ms, so long as the statistical + // properties are satisfactory. If those properties are + // not met, it may run as long as the Go algorithm. + pub fn auto_bench(&mut self, f: &fn(&mut BenchHarness)) -> ~[f64] { + + let mut rng = rand::rng(); + let mut magnitude = 10; + let mut prev_madp = 0.0; + + loop { + let n_samples = rng.gen_uint_range(50, 60); + let n_iter = rng.gen_uint_range(magnitude, + magnitude * 2); + + let samples = do vec::from_fn(n_samples) |_| { + self.bench_n(n_iter as u64, |x| f(x)); + self.ns_per_iter() as f64 + }; + + // Eliminate outliers + let med = samples.median(); + let mad = samples.median_abs_dev(); + let samples = do vec::filter(samples) |f| { + num::abs(*f - med) <= 3.0 * mad + }; + + debug!("%u samples, median %f, MAD=%f, %u survived filter", + n_samples, med as float, mad as float, + samples.len()); + + if samples.len() != 0 { + // If we have _any_ cluster of signal... + let curr_madp = samples.median_abs_dev_pct(); + if self.ns_elapsed() > 1_000_000 && + (curr_madp < 1.0 || + num::abs(curr_madp - prev_madp) < 0.1) { + return samples; } + prev_madp = curr_madp; - magnitude *= 2; + if n_iter > 20_000_000 || + self.ns_elapsed() > 20_000_000 { + return samples; + } } + + magnitude *= 2; } } +} + +pub mod bench { + use test::{BenchHarness, BenchSamples}; pub fn benchmark(f: &fn(&mut BenchHarness)) -> BenchSamples { diff --git a/src/libextra/time.rs b/src/libextra/time.rs index 555563a0cd7..931a42d3c53 100644 --- a/src/libextra/time.rs +++ b/src/libextra/time.rs @@ -849,7 +849,7 @@ priv fn do_strftime(format: &str, tm: &Tm) -> ~str { do io::with_str_reader(format) |rdr| { while !rdr.eof() { match rdr.read_char() { - '%' => buf += parse_type(rdr.read_char(), tm), + '%' => buf.push_str(parse_type(rdr.read_char(), tm)), ch => buf.push_char(ch) } } diff --git a/src/libextra/timer.rs b/src/libextra/timer.rs index 71d8a5d81e7..e23f9113319 100644 --- a/src/libextra/timer.rs +++ b/src/libextra/timer.rs @@ -39,7 +39,7 @@ use core::libc; * * ch - a channel of type T to send a `val` on * * val - a value of type T to send over the provided `ch` */ -pub fn delayed_send<T:Owned>(iotask: &IoTask, +pub fn delayed_send<T:Send>(iotask: &IoTask, msecs: uint, ch: &Chan<T>, val: T) { @@ -119,11 +119,12 @@ pub fn sleep(iotask: &IoTask, msecs: uint) { * on the provided port in the allotted timeout period, then the result will * be a `Some(T)`. If not, then `None` will be returned. */ -pub fn recv_timeout<T:Copy + Owned>(iotask: &IoTask, +pub fn recv_timeout<T:Copy + Send>(iotask: &IoTask, msecs: uint, wait_po: &Port<T>) -> Option<T> { - let mut (timeout_po, timeout_ch) = stream::<()>(); + let (timeout_po, timeout_ch) = stream::<()>(); + let mut timeout_po = timeout_po; delayed_send(iotask, msecs, &timeout_ch, ()); // XXX: Workaround due to ports and channels not being &mut. They should diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index 33ec4ae94ba..d546b48f817 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -511,14 +511,14 @@ impl<K: TotalOrd, V> TreeNode<K, V> { fn each<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>, f: &fn(&'r K, &'r V) -> bool) -> bool { - node.iter().advance(|x| each(&x.left, f) && f(&x.key, &x.value) && - each(&x.right, f)) + node.iter().advance(|x| each(&x.left, |k,v| f(k,v)) && f(&x.key, &x.value) && + each(&x.right, |k,v| f(k,v))) } fn each_reverse<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>, f: &fn(&'r K, &'r V) -> bool) -> bool { - node.iter().advance(|x| each_reverse(&x.right, f) && f(&x.key, &x.value) && - each_reverse(&x.left, f)) + node.iter().advance(|x| each_reverse(&x.right, |k,v| f(k,v)) && f(&x.key, &x.value) && + each_reverse(&x.left, |k,v| f(k,v))) } fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode<K, V>>, @@ -527,9 +527,9 @@ fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode<K, V>>, match *node { Some(~TreeNode{key: ref key, value: ref mut value, left: ref mut left, right: ref mut right, _}) => { - if !mutate_values(left, f) { return false } + if !mutate_values(left, |k,v| f(k,v)) { return false } if !f(key, value) { return false } - if !mutate_values(right, f) { return false } + if !mutate_values(right, |k,v| f(k,v)) { return false } } None => return false } @@ -695,7 +695,6 @@ mod test_treemap { use core::rand::RngUtil; use core::rand; - use core::vec; #[test] fn find_empty() { @@ -848,7 +847,7 @@ mod test_treemap { for 30.times { let r = rng.gen_uint_range(0, ctrl.len()); - let (key, _) = vec::remove(&mut ctrl, r); + let (key, _) = ctrl.remove(r); assert!(map.remove(&key)); check_structure(&map); check_equal(ctrl, &map); diff --git a/src/libextra/uv_global_loop.rs b/src/libextra/uv_global_loop.rs index 286863bef64..f1dde1b8cb4 100644 --- a/src/libextra/uv_global_loop.rs +++ b/src/libextra/uv_global_loop.rs @@ -150,9 +150,7 @@ mod test { let hl_loop = &get_gl(); do iotask::interact(hl_loop) |_loop_ptr| { debug!(~"closing timer"); - unsafe { - ll::close(timer_ptr, simple_timer_close_cb); - } + ll::close(timer_ptr, simple_timer_close_cb); debug!(~"about to deref exit_ch_ptr"); debug!(~"after msg sent on deref'd exit_ch"); }; @@ -169,24 +167,22 @@ mod test { let timer_handle = ll::timer_t(); let timer_ptr: *ll::uv_timer_t = &timer_handle; do iotask::interact(iotask) |loop_ptr| { - unsafe { - debug!(~"user code inside interact loop!!!"); - let init_status = ll::timer_init(loop_ptr, timer_ptr); - if(init_status == 0i32) { - ll::set_data_for_uv_handle( - timer_ptr as *libc::c_void, - exit_ch_ptr); - let start_status = ll::timer_start(timer_ptr, - simple_timer_cb, - 1u, 0u); - if(start_status != 0i32) { - fail!("failure on ll::timer_start()"); - } - } - else { - fail!("failure on ll::timer_init()"); + debug!(~"user code inside interact loop!!!"); + let init_status = ll::timer_init(loop_ptr, timer_ptr); + if(init_status == 0i32) { + ll::set_data_for_uv_handle( + timer_ptr as *libc::c_void, + exit_ch_ptr); + let start_status = ll::timer_start(timer_ptr, + simple_timer_cb, + 1u, 0u); + if(start_status != 0i32) { + fail!("failure on ll::timer_start()"); } } + else { + fail!("failure on ll::timer_init()"); + } }; exit_po.recv(); debug!( diff --git a/src/libextra/uv_ll.rs b/src/libextra/uv_ll.rs index 744f4555d5c..58b477d4ccf 100644 --- a/src/libextra/uv_ll.rs +++ b/src/libextra/uv_ll.rs @@ -1767,9 +1767,7 @@ mod test { mod impl64 { #[test] fn test_uv_ll_tcp_server_and_request() { - unsafe { - super::super::impl_uv_tcp_server_and_request(); - } + super::super::impl_uv_tcp_server_and_request(); } } #[cfg(target_arch="x86")] diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index a014293f063..4d4f3c3a49b 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -107,7 +107,7 @@ struct WorkKey { impl to_bytes::IterBytes for WorkKey { #[inline] fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.kind.iter_bytes(lsb0, f) && self.name.iter_bytes(lsb0, f) + self.kind.iter_bytes(lsb0, |b| f(b)) && self.name.iter_bytes(lsb0, |b| f(b)) } } @@ -272,7 +272,7 @@ impl Context { } } - pub fn prep<T:Owned + + pub fn prep<T:Send + Encodable<json::Encoder> + Decodable<json::Decoder>>(@self, // FIXME(#5121) fn_name:&str, @@ -292,7 +292,7 @@ trait TPrep { fn declare_input(&mut self, kind:&str, name:&str, val:&str); fn is_fresh(&self, cat:&str, kind:&str, name:&str, val:&str) -> bool; fn all_fresh(&self, cat:&str, map:&WorkMap) -> bool; - fn exec<T:Owned + + fn exec<T:Send + Encodable<json::Encoder> + Decodable<json::Decoder>>( // FIXME(#5121) &self, blk: ~fn(&Exec) -> T) -> Work<T>; @@ -328,7 +328,7 @@ impl TPrep for Prep { return true; } - fn exec<T:Owned + + fn exec<T:Send + Encodable<json::Encoder> + Decodable<json::Decoder>>( // FIXME(#5121) &self, blk: ~fn(&Exec) -> T) -> Work<T> { @@ -365,7 +365,7 @@ impl TPrep for Prep { } } -impl<T:Owned + +impl<T:Send + Encodable<json::Encoder> + Decodable<json::Decoder>> Work<T> { // FIXME(#5121) pub fn new(p: @mut Prep, e: Either<T,PortOne<(Exec,T)>>) -> Work<T> { @@ -374,7 +374,7 @@ impl<T:Owned + } // FIXME (#3724): movable self. This should be in impl Work. -fn unwrap<T:Owned + +fn unwrap<T:Send + Encodable<json::Encoder> + Decodable<json::Decoder>>( // FIXME(#5121) w: Work<T>) -> T { diff --git a/src/librust/rust.rs b/src/librust/rust.rs index 68427745ff5..ba5e592b605 100644 --- a/src/librust/rust.rs +++ b/src/librust/rust.rs @@ -57,13 +57,13 @@ impl ValidUsage { } enum Action<'self> { - Call(&'self fn(args: &[~str]) -> ValidUsage), - CallMain(&'static str, &'self fn()), + Call(&'self fn:Copy(args: &[~str]) -> ValidUsage), + CallMain(&'static str, &'self fn:Copy()), } enum UsageSource<'self> { UsgStr(&'self str), - UsgCall(&'self fn()), + UsgCall(&'self fn:Copy()), } struct Command<'self> { diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 01ad3507b83..af23696cbc1 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -19,6 +19,7 @@ use lib; use metadata::common::LinkMeta; use metadata::{encoder, csearch, cstore}; use middle::trans::context::CrateContext; +use middle::trans::common::gensym_name; use middle::ty; use util::ppaux; @@ -37,6 +38,7 @@ use syntax::ast; use syntax::ast_map::{path, path_mod, path_name}; use syntax::attr; use syntax::print::pprust; +use syntax::parse::token; #[deriving(Eq)] pub enum output_type { @@ -640,15 +642,15 @@ pub fn sanitize(s: &str) -> ~str { for s.iter().advance |c| { match c { // Escape these with $ sequences - '@' => result += "$SP$", - '~' => result += "$UP$", - '*' => result += "$RP$", - '&' => result += "$BP$", - '<' => result += "$LT$", - '>' => result += "$GT$", - '(' => result += "$LP$", - ')' => result += "$RP$", - ',' => result += "$C$", + '@' => result.push_str("$SP$"), + '~' => result.push_str("$UP$"), + '*' => result.push_str("$RP$"), + '&' => result.push_str("$BP$"), + '<' => result.push_str("$LT$"), + '>' => result.push_str("$GT$"), + '(' => result.push_str("$LP$"), + ')' => result.push_str("$RP$"), + ',' => result.push_str("$C$"), // '.' doesn't occur in types and functions, so reuse it // for ':' @@ -684,12 +686,14 @@ pub fn mangle(sess: Session, ss: path) -> ~str { let mut n = ~"_ZN"; // Begin name-sequence. for ss.iter().advance |s| { - match *s { path_name(s) | path_mod(s) => { - let sani = sanitize(sess.str_of(s)); - n += fmt!("%u%s", sani.len(), sani); - } } + match *s { + path_name(s) | path_mod(s) => { + let sani = sanitize(sess.str_of(s)); + n.push_str(fmt!("%u%s", sani.len(), sani)); + } + } } - n += "E"; // End name-sequence. + n.push_char('E'); // End name-sequence. n } @@ -731,22 +735,22 @@ pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext, return mangle(ccx.sess, ~[path_name(ccx.sess.ident_of(s)), path_name(ccx.sess.ident_of(hash)), - path_name((ccx.names)(name))]); + path_name(gensym_name(name))]); } pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext, - path: path, + mut path: path, flav: &str) -> ~str { - mangle(ccx.sess, - vec::append_one(path, path_name((ccx.names)(flav)))) + path.push(path_name(gensym_name(flav))); + mangle(ccx.sess, path) } pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str { mangle(ccx.sess, path) } -pub fn mangle_internal_name_by_seq(ccx: &mut CrateContext, flav: &str) -> ~str { - fmt!("%s_%u", flav, (ccx.names)(flav).name) +pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str { + return fmt!("%s_%u", flav, token::gensym(flav)); } diff --git a/src/librustc/back/passes.rs b/src/librustc/back/passes.rs index fa261a977f5..d2b4c87c744 100644 --- a/src/librustc/back/passes.rs +++ b/src/librustc/back/passes.rs @@ -60,90 +60,109 @@ impl PassManager { } } -pub fn create_standard_passes(level:OptLevel) -> ~[~str] { - let mut passes = ~[~"strip-dead-prototypes"]; - - if level == No { - passes.push(~"always-inline"); - return passes; +pub fn create_standard_passes(level: OptLevel) -> ~[~str] { + let mut passes = ~[]; + + // mostly identical to clang 3.3, all differences are documented with comments + + if level != No { + passes.push(~"targetlibinfo"); + passes.push(~"no-aa"); + // "tbaa" omitted, we don't emit clang-style type-based alias analysis information + passes.push(~"basicaa"); + passes.push(~"globalopt"); + passes.push(~"ipsccp"); + passes.push(~"deadargelim"); + passes.push(~"instcombine"); + passes.push(~"simplifycfg"); } - passes.push(~"targetlibinfo"); - - passes.push(~"scev-aa"); - passes.push(~"basicaa"); - - passes.push(~"instcombine"); - passes.push(~"simplifycfg"); - passes.push(~"scalarrepl-ssa"); - passes.push(~"early-cse"); - - passes.push(~"globalopt"); - passes.push(~"ipsccp"); - passes.push(~"deadargelim"); - passes.push(~"instcombine"); - passes.push(~"simplifycfg"); + passes.push(~"basiccg"); - passes.push(~"prune-eh"); - - passes.push(~"inline"); - - passes.push(~"functionattrs"); - - if level == Aggressive { - passes.push(~"argpromotion"); + if level != No { + passes.push(~"prune-eh"); } - passes.push(~"scalarrepl-ssa"); - passes.push(~"early-cse"); - passes.push(~"simplify-libcalls"); - passes.push(~"jump-threading"); - passes.push(~"correlated-propagation"); - passes.push(~"simplifycfg"); - passes.push(~"instcombine"); - - passes.push(~"tailcallelim"); - passes.push(~"simplifycfg"); - passes.push(~"reassociate"); - passes.push(~"loop-rotate"); - passes.push(~"licm"); - - passes.push(~"lcssa"); - passes.push(~"loop-unswitch"); + passes.push(~"inline-cost"); - passes.push(~"instcombine"); - passes.push(~"indvars"); - passes.push(~"loop-idiom"); - passes.push(~"loop-deletion"); - - if level == Aggressive { - passes.push(~"loop-vectorize"); + if level == No || level == Less { + passes.push(~"always-inline"); + } else { + passes.push(~"inline"); } - passes.push(~"loop-unroll"); - - if level != Less { - passes.push(~"gvn"); + if level != No { + passes.push(~"functionattrs"); + if level == Aggressive { + passes.push(~"argpromotion"); + } + passes.push(~"sroa"); + passes.push(~"domtree"); + passes.push(~"early-cse"); + passes.push(~"simplify-libcalls"); + passes.push(~"lazy-value-info"); + passes.push(~"jump-threading"); + passes.push(~"correlated-propagation"); + passes.push(~"simplifycfg"); + passes.push(~"instcombine"); + passes.push(~"tailcallelim"); + passes.push(~"simplifycfg"); + passes.push(~"reassociate"); + passes.push(~"domtree"); + passes.push(~"loops"); + passes.push(~"loop-simplify"); + passes.push(~"lcssa"); + passes.push(~"loop-rotate"); + passes.push(~"licm"); + passes.push(~"lcssa"); + passes.push(~"loop-unswitch"); + passes.push(~"instcombine"); + passes.push(~"scalar-evolution"); + passes.push(~"loop-simplify"); + passes.push(~"lcssa"); + passes.push(~"indvars"); + passes.push(~"loop-idiom"); + passes.push(~"loop-deletion"); + if level == Aggressive { + passes.push(~"loop-simplify"); + passes.push(~"lcssa"); + passes.push(~"loop-vectorize"); + passes.push(~"loop-simplify"); + passes.push(~"lcssa"); + passes.push(~"scalar-evolution"); + passes.push(~"loop-simplify"); + passes.push(~"lcssa"); + } + if level != Less { + passes.push(~"loop-unroll"); + passes.push(~"memdep"); + passes.push(~"gvn"); + } + passes.push(~"memdep"); + passes.push(~"memcpyopt"); + passes.push(~"sccp"); + passes.push(~"instcombine"); + passes.push(~"lazy-value-info"); + passes.push(~"jump-threading"); + passes.push(~"correlated-propagation"); + passes.push(~"domtree"); + passes.push(~"memdep"); + passes.push(~"dse"); + passes.push(~"adce"); + passes.push(~"simplifycfg"); + passes.push(~"instcombine"); + // clang does `strip-dead-prototypes` here, since it does not emit them } - passes.push(~"memcpyopt"); - passes.push(~"sccp"); - - passes.push(~"instcombine"); - passes.push(~"jump-threading"); - passes.push(~"correlated-propagation"); - passes.push(~"dse"); - - passes.push(~"adce"); - passes.push(~"simplifycfg"); - passes.push(~"instsimplify"); + // rustc emits dead prototypes, so always ask LLVM to strip them + passes.push(~"strip-dead-prototypes"); if level != Less { passes.push(~"globaldce"); passes.push(~"constmerge"); } - return passes; + passes } pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) { diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index 4657c069c21..dce2b7fe3df 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -154,7 +154,7 @@ pub fn get_relative_to(abs1: &Path, abs2: &Path) -> Path { let mut path = ~[]; for uint::range(start_idx, len1 - 1) |_i| { path.push(~".."); }; - path.push_all(vec::slice(split2, start_idx, len2 - 1)); + path.push_all(split2.slice(start_idx, len2 - 1)); return if !path.is_empty() { Path("").push_many(path) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 2229a85836a..18693b52fc8 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -19,7 +19,7 @@ use front; use lib::llvm::llvm; use metadata::{creader, cstore, filesearch}; use metadata; -use middle::{trans, freevars, kind, ty, typeck, lint, astencode}; +use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable}; use middle; use util::common::time; use util::ppaux; @@ -299,10 +299,16 @@ pub fn compile_rest(sess: Session, time(time_passes, ~"kind checking", || kind::check_crate(ty_cx, method_map, crate)); + let reachable_map = + time(time_passes, ~"reachability checking", || + reachable::find_reachable(ty_cx, method_map, crate)); + time(time_passes, ~"lint checking", || lint::check_crate(ty_cx, crate)); - if phases.to == cu_no_trans { return (Some(crate), Some(ty_cx)); } + if phases.to == cu_no_trans { + return (Some(crate), Some(ty_cx)); + } let maps = astencode::Maps { root_map: root_map, @@ -315,9 +321,13 @@ pub fn compile_rest(sess: Session, let outputs = outputs.get_ref(); time(time_passes, ~"translation", || - trans::base::trans_crate(sess, crate, ty_cx, + trans::base::trans_crate(sess, + crate, + ty_cx, &outputs.obj_filename, - exp_map2, maps)) + exp_map2, + reachable_map, + maps)) }; let outputs = outputs.get_ref(); diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index b5eb351a8a5..9459116307d 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -45,32 +45,33 @@ pub struct config { float_type: float_ty } -pub static verbose: uint = 1 << 0; -pub static time_passes: uint = 1 << 1; -pub static count_llvm_insns: uint = 1 << 2; -pub static time_llvm_passes: uint = 1 << 3; -pub static trans_stats: uint = 1 << 4; -pub static asm_comments: uint = 1 << 5; -pub static no_verify: uint = 1 << 6; -pub static trace: uint = 1 << 7; -pub static coherence: uint = 1 << 8; -pub static borrowck_stats: uint = 1 << 9; -pub static borrowck_note_pure: uint = 1 << 10; -pub static borrowck_note_loan: uint = 1 << 11; -pub static no_landing_pads: uint = 1 << 12; -pub static debug_llvm: uint = 1 << 13; -pub static count_type_sizes: uint = 1 << 14; -pub static meta_stats: uint = 1 << 15; -pub static no_opt: uint = 1 << 16; +pub static verbose: uint = 1 << 0; +pub static time_passes: uint = 1 << 1; +pub static count_llvm_insns: uint = 1 << 2; +pub static time_llvm_passes: uint = 1 << 3; +pub static trans_stats: uint = 1 << 4; +pub static asm_comments: uint = 1 << 5; +pub static no_verify: uint = 1 << 6; +pub static trace: uint = 1 << 7; +pub static coherence: uint = 1 << 8; +pub static borrowck_stats: uint = 1 << 9; +pub static borrowck_note_pure: uint = 1 << 10; +pub static borrowck_note_loan: uint = 1 << 11; +pub static no_landing_pads: uint = 1 << 12; +pub static debug_llvm: uint = 1 << 13; +pub static count_type_sizes: uint = 1 << 14; +pub static meta_stats: uint = 1 << 15; +pub static no_opt: uint = 1 << 16; pub static no_monomorphic_collapse: uint = 1 << 17; -pub static gc: uint = 1 << 18; -pub static jit: uint = 1 << 19; -pub static debug_info: uint = 1 << 20; -pub static extra_debug_info: uint = 1 << 21; -pub static statik: uint = 1 << 22; -pub static print_link_args: uint = 1 << 23; -pub static no_debug_borrows: uint = 1 << 24; -pub static lint_llvm : uint = 1 << 25; +pub static gc: uint = 1 << 18; +pub static jit: uint = 1 << 19; +pub static debug_info: uint = 1 << 20; +pub static extra_debug_info: uint = 1 << 21; +pub static statik: uint = 1 << 22; +pub static print_link_args: uint = 1 << 23; +pub static no_debug_borrows: uint = 1 << 24; +pub static lint_llvm: uint = 1 << 25; +pub static once_fns: uint = 1 << 26; pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { ~[(~"verbose", ~"in general, enable more debug printouts", verbose), @@ -112,6 +113,9 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { (~"lint-llvm", ~"Run the LLVM lint pass on the pre-optimization IR", lint_llvm), + (~"once-fns", + ~"Allow 'once fn' closures to deinitialize captured variables", + once_fns), ] } @@ -293,6 +297,7 @@ impl Session_ { pub fn debug_borrows(@self) -> bool { self.opts.optimize == No && !self.debugging_opt(no_debug_borrows) } + pub fn once_fns(@self) -> bool { self.debugging_opt(once_fns) } // pointless function, now... pub fn str_of(@self, id: ast::ident) -> @str { @@ -403,8 +408,12 @@ mod test { fn make_crate(with_bin: bool, with_lib: bool) -> @ast::crate { let mut attrs = ~[]; - if with_bin { attrs += [make_crate_type_attr(@"bin")]; } - if with_lib { attrs += [make_crate_type_attr(@"lib")]; } + if with_bin { + attrs.push(make_crate_type_attr(@"bin")); + } + if with_lib { + attrs.push(make_crate_type_attr(@"lib")); + } @codemap::respan(codemap::dummy_sp(), ast::crate_ { module: ast::_mod { view_items: ~[], items: ~[] }, attrs: attrs, diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index d7f33dcf0d0..41349d9c085 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -2149,18 +2149,24 @@ impl TypeNames { self.named_types.find_equiv(&s).map_consume(|x| Type::from_ref(*x)) } - pub fn type_to_str(&self, ty: Type) -> ~str { + // We have a depth count, because we seem to make infinite types. + pub fn type_to_str_depth(&self, ty: Type, depth: int) -> ~str { match self.find_name(&ty) { option::Some(name) => return name.to_owned(), None => () } + if depth == 0 { + return ~"###"; + } + unsafe { let kind = ty.kind(); match kind { Void => ~"Void", Half => ~"Half", + Float => ~"Float", Double => ~"Double", X86_FP80 => ~"X86_FP80", FP128 => ~"FP128", @@ -2175,24 +2181,25 @@ impl TypeNames { Function => { let out_ty = ty.return_type(); let args = ty.func_params(); - let args = args.map(|&ty| self.type_to_str(ty)).connect(", "); - let out_ty = self.type_to_str(out_ty); + let args = + args.map(|&ty| self.type_to_str_depth(ty, depth-1)).connect(", "); + let out_ty = self.type_to_str_depth(out_ty, depth-1); fmt!("fn(%s) -> %s", args, out_ty) } Struct => { let tys = ty.field_types(); - let tys = tys.map(|&ty| self.type_to_str(ty)).connect(", "); + let tys = tys.map(|&ty| self.type_to_str_depth(ty, depth-1)).connect(", "); fmt!("{%s}", tys) } Array => { let el_ty = ty.element_type(); - let el_ty = self.type_to_str(el_ty); + let el_ty = self.type_to_str_depth(el_ty, depth-1); let len = ty.array_length(); fmt!("[%s x %u]", el_ty, len) } Pointer => { let el_ty = ty.element_type(); - let el_ty = self.type_to_str(el_ty); + let el_ty = self.type_to_str_depth(el_ty, depth-1); fmt!("*%s", el_ty) } _ => fail!("Unknown Type Kind (%u)", kind as uint) @@ -2200,6 +2207,10 @@ impl TypeNames { } } + pub fn type_to_str(&self, ty: Type) -> ~str { + self.type_to_str_depth(ty, 30) + } + pub fn val_to_str(&self, val: ValueRef) -> ~str { unsafe { let ty = Type::from_ref(llvm::LLVMTypeOf(val)); diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index f487c73372f..e7725436f2b 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -176,6 +176,10 @@ pub static tag_item_method_tps: uint = 0x7b; pub static tag_item_method_fty: uint = 0x7c; pub static tag_item_method_transformed_self_ty: uint = 0x7d; +pub static tag_mod_child: uint = 0x7e; +pub static tag_misc_info: uint = 0x7f; +pub static tag_misc_info_crate_items: uint = 0x80; + pub struct LinkMeta { name: @str, vers: @str, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index bfc5d512b37..4ede9f96f1f 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -97,18 +97,14 @@ pub fn get_enum_variants(tcx: ty::ctxt, def: ast::def_id) return decoder::get_enum_variants(cstore.intr, cdata, def.node, tcx) } -pub fn get_impls_for_mod(cstore: @mut cstore::CStore, def: ast::def_id, - name: Option<ast::ident>) - -> @~[@resolve::Impl] { - let cdata = cstore::get_crate_data(cstore, def.crate); - do decoder::get_impls_for_mod(cstore.intr, cdata, def.node, name) |cnum| { - cstore::get_crate_data(cstore, cnum) - } +/// Returns information about the given implementation. +pub fn get_impl(cstore: @mut cstore::CStore, impl_def_id: ast::def_id) + -> resolve::Impl { + let cdata = cstore::get_crate_data(cstore, impl_def_id.crate); + decoder::get_impl(cstore.intr, cdata, impl_def_id.node) } -pub fn get_method(tcx: ty::ctxt, - def: ast::def_id) -> ty::Method -{ +pub fn get_method(tcx: ty::ctxt, def: ast::def_id) -> ty::Method { let cdata = cstore::get_crate_data(tcx.cstore, def.crate); decoder::get_method(tcx.cstore.intr, cdata, def.node, tcx) } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 30f0a52b4e5..69faf519bc2 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -60,7 +60,7 @@ fn lookup_hash(d: ebml::Doc, eq_fn: &fn(x:&[u8]) -> bool, hash: uint) -> let belt = tag_index_buckets_bucket_elt; for reader::tagged_docs(tagged_doc.doc, belt) |elt| { let pos = io::u64_from_be_bytes(*elt.data, elt.start, 4u) as uint; - if eq_fn(vec::slice(*elt.data, elt.start + 4u, elt.end)) { + if eq_fn(elt.data.slice(elt.start + 4u, elt.end)) { return Some(reader::doc_at(d.data, pos).doc); } }; @@ -72,7 +72,7 @@ pub type GetCrateDataCb<'self> = &'self fn(ast::crate_num) -> cmd; pub fn maybe_find_item(item_id: int, items: ebml::Doc) -> Option<ebml::Doc> { fn eq_item(bytes: &[u8], item_id: int) -> bool { return io::u64_from_be_bytes( - vec::slice(bytes, 0u, 4u), 0u, 4u) as int + bytes.slice(0u, 4u), 0u, 4u) as int == item_id; } lookup_hash(items, @@ -458,64 +458,192 @@ pub fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) -> bool { return true; } -/// Iterates over all the paths in the given crate. -pub fn each_path(intr: @ident_interner, - cdata: cmd, - get_crate_data: GetCrateDataCb, - f: &fn(&str, def_like, ast::visibility) -> bool) - -> bool { - // FIXME #4572: This function needs to be nuked, as it's impossible to make fast. - // It's the source of most of the performance problems when compiling small crates. +struct EachItemContext<'self> { + intr: @ident_interner, + cdata: cmd, + get_crate_data: GetCrateDataCb<'self>, + path_builder: &'self mut ~str, + callback: &'self fn(&str, def_like, ast::visibility) -> bool, +} - let root = reader::Doc(cdata.data); - let items = reader::get_doc(root, tag_items); - let items_data = reader::get_doc(items, tag_items_data); - - // First, go through all the explicit items. - for reader::tagged_docs(items_data, tag_items_data_item) |item_doc| { - let path = ast_map::path_to_str(item_path(item_doc), intr); - let path_is_empty = path.is_empty(); - if !path_is_empty { - // Extract the def ID. - let def_id = item_def_id(item_doc, cdata); - - // Construct the def for this item. - debug!("(each_path) yielding explicit item: %s", path); - let def_like = item_to_def_like(item_doc, def_id, cdata.cnum); - - let vis = item_visibility(item_doc); - - // Hand the information off to the iteratee. - if !f(path, def_like, vis) { - return false; +impl<'self> EachItemContext<'self> { + // Pushes the given name and returns the old length. + fn push_name(&mut self, string: &str) -> uint { + let path_len = self.path_builder.len(); + if path_len != 0 { + self.path_builder.push_str("::") + } + self.path_builder.push_str(string); + path_len + } + + // Pops the given name. + fn pop_name(&mut self, old_len: uint) { + // XXX(pcwalton): There's no safe function to do this. :( + unsafe { + str::raw::set_len(self.path_builder, old_len) + } + } + + fn process_item_and_pop_name(&mut self, + doc: ebml::Doc, + def_id: ast::def_id, + old_len: uint) + -> bool { + let def_like = item_to_def_like(doc, def_id, self.cdata.cnum); + match def_like { + dl_def(def) => { + debug!("(iterating over each item of a module) processing \ + `%s` (def %?)", + *self.path_builder, + def); + } + _ => { + debug!("(iterating over each item of a module) processing \ + `%s` (%d:%d)", + *self.path_builder, + def_id.crate, + def_id.node); } } - // If this is a module, find the reexports. - for each_reexport(item_doc) |reexport_doc| { - let def_id_doc = - reader::get_doc(reexport_doc, - tag_items_data_item_reexport_def_id); - let def_id = reader::with_doc_data(def_id_doc, parse_def_id); - let def_id = translate_def_id(cdata, def_id); - - let reexport_name_doc = - reader::get_doc(reexport_doc, - tag_items_data_item_reexport_name); - let reexport_name = reexport_name_doc.as_str_slice(); - - let reexport_path; - if path_is_empty { - reexport_path = reexport_name.to_owned(); + let vis = item_visibility(doc); + + let mut continue = (self.callback)(*self.path_builder, def_like, vis); + + let family = item_family(doc); + if family == ForeignMod { + // These are unnamed; pop the name now. + self.pop_name(old_len) + } + + if continue { + // Recurse if necessary. + match family { + Mod | ForeignMod | Trait | Impl => { + continue = self.each_item_of_module(def_id); + } + ImmStatic | MutStatic | Struct | UnsafeFn | Fn | ForeignFn | + UnsafeStaticMethod | StaticMethod | Type | ForeignType | + Variant | Enum | PublicField | PrivateField | + InheritedField => {} + } + } + + if family != ForeignMod { + self.pop_name(old_len) + } + + continue + } + + fn each_item_of_module(&mut self, def_id: ast::def_id) -> bool { + // This item might not be in this crate. If it's not, look it up. + let (cdata, items) = if def_id.crate == self.cdata.cnum { + let items = reader::get_doc(reader::Doc(self.cdata.data), + tag_items); + (self.cdata, items) + } else { + let crate_data = (self.get_crate_data)(def_id.crate); + let root = reader::Doc(crate_data.data); + (crate_data, reader::get_doc(root, tag_items)) + }; + + // Look up the item. + let item_doc = match maybe_find_item(def_id.node, items) { + None => return false, + Some(item_doc) => item_doc, + }; + + self.each_child_of_module_or_crate(item_doc) + } + + fn each_child_of_module_or_crate(&mut self, item_doc: ebml::Doc) -> bool { + let mut continue = true; + + // Iterate over all children. + for reader::tagged_docs(item_doc, tag_mod_child) |child_info_doc| { + let child_def_id = reader::with_doc_data(child_info_doc, + parse_def_id); + let child_def_id = translate_def_id(self.cdata, child_def_id); + + // This item may be in yet another crate, if it was the child of + // a reexport. + let other_crates_items = if child_def_id.crate == + self.cdata.cnum { + reader::get_doc(reader::Doc(self.cdata.data), tag_items) } else { - reexport_path = path + "::" + reexport_name; + let crate_data = (self.get_crate_data)(child_def_id.crate); + let root = reader::Doc(crate_data.data); + reader::get_doc(root, tag_items) + }; + + debug!("(iterating over each item of a module) looking up item \ + %d:%d in `%s`, crate %d", + child_def_id.crate, + child_def_id.node, + *self.path_builder, + self.cdata.cnum); + + // Get the item. + match maybe_find_item(child_def_id.node, other_crates_items) { + None => {} + Some(child_item_doc) => { + // Push the name. + let child_name = item_name(self.intr, child_item_doc); + debug!("(iterating over each item of a module) pushing \ + name `%s` onto `%s`", + token::ident_to_str(&child_name), + *self.path_builder); + let old_len = + self.push_name(token::ident_to_str(&child_name)); + + // Process this item. + continue = self.process_item_and_pop_name(child_item_doc, + child_def_id, + old_len); + + if !continue { + break + } + } } + } + + if !continue { + return false + } - // This reexport may be in yet another crate - let other_crates_items = if def_id.crate == cdata.cnum { - items + // Iterate over reexports. + for each_reexport(item_doc) |reexport_doc| { + let def_id_doc = reader::get_doc( + reexport_doc, + tag_items_data_item_reexport_def_id); + let orig_def_id = reader::with_doc_data(def_id_doc, parse_def_id); + + // NB: was "cdata" + let def_id = translate_def_id(self.cdata, orig_def_id); + + let name_doc = reader::get_doc(reexport_doc, + tag_items_data_item_reexport_name); + let name = name_doc.as_str_slice(); + + // Push the name. + debug!("(iterating over each item of a module) pushing \ + reexported name `%s` onto `%s` (crate %d, orig %d, \ + in crate %d)", + name, + *self.path_builder, + def_id.crate, + orig_def_id.crate, + self.cdata.cnum); + let old_len = self.push_name(name); + + // This reexport may be in yet another crate. + let other_crates_items = if def_id.crate == self.cdata.cnum { + reader::get_doc(reader::Doc(self.cdata.data), tag_items) } else { - let crate_data = get_crate_data(def_id.crate); + let crate_data = (self.get_crate_data)(def_id.crate); let root = reader::Doc(crate_data.data); reader::get_doc(root, tag_items) }; @@ -523,29 +651,53 @@ pub fn each_path(intr: @ident_interner, // Get the item. match maybe_find_item(def_id.node, other_crates_items) { None => {} - Some(item_doc) => { - // Construct the def for this item. - let def_like = item_to_def_like(item_doc, - def_id, - cdata.cnum); - - // Hand the information off to the iteratee. - debug!("(each_path) yielding reexported \ - item: %s", reexport_path); - - if (!f(reexport_path, def_like, ast::public)) { - return false; - } + Some(reexported_item_doc) => { + continue = self.process_item_and_pop_name( + reexported_item_doc, + def_id, + old_len); } } + + if !continue { + break + } } + + continue } +} - return true; +/// Iterates over all the paths in the given crate. +pub fn each_path(intr: @ident_interner, + cdata: cmd, + get_crate_data: GetCrateDataCb, + f: &fn(&str, def_like, ast::visibility) -> bool) + -> bool { + // FIXME #4572: This function needs to be nuked, as it's impossible to + // make fast. It's the source of most of the performance problems when + // compiling small crates. + + let root_doc = reader::Doc(cdata.data); + let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); + let crate_items_doc = reader::get_doc(misc_info_doc, + tag_misc_info_crate_items); + + let mut path_builder = ~""; + + let mut context = EachItemContext { + intr: intr, + cdata: cdata, + get_crate_data: get_crate_data, + path_builder: &mut path_builder, + callback: f, + }; + + // Iterate over all top-level crate items. + context.each_child_of_module_or_crate(crate_items_doc) } -pub fn get_item_path(cdata: cmd, id: ast::node_id) - -> ast_map::path { +pub fn get_item_path(cdata: cmd, id: ast::node_id) -> ast_map::path { item_path(lookup_item(id, cdata.data)) } @@ -661,35 +813,20 @@ fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc, rslt } -pub fn get_impls_for_mod(intr: @ident_interner, - cdata: cmd, - m_id: ast::node_id, - name: Option<ast::ident>, - get_cdata: &fn(ast::crate_num) -> cmd) - -> @~[@resolve::Impl] { +/// Returns information about the given implementation. +pub fn get_impl(intr: @ident_interner, cdata: cmd, impl_id: ast::node_id) + -> resolve::Impl { let data = cdata.data; - let mod_item = lookup_item(m_id, data); - let mut result = ~[]; - for reader::tagged_docs(mod_item, tag_mod_impl) |doc| { - let did = reader::with_doc_data(doc, parse_def_id); - let local_did = translate_def_id(cdata, did); - debug!("(get impls for mod) getting did %? for '%?'", - local_did, name); - // The impl may be defined in a different crate. Ask the caller - // to give us the metadata - let impl_cdata = get_cdata(local_did.crate); - let impl_data = impl_cdata.data; - let item = lookup_item(local_did.node, impl_data); - let nm = item_name(intr, item); - if match name { Some(n) => { n == nm } None => { true } } { - let base_tps = item_ty_param_count(item); - result.push(@resolve::Impl { - did: local_did, ident: nm, - methods: item_impl_methods(intr, impl_cdata, item, base_tps) - }); - }; + let impl_item = lookup_item(impl_id, data); + let base_tps = item_ty_param_count(impl_item); + resolve::Impl { + did: ast::def_id { + crate: cdata.cnum, + node: impl_id, + }, + ident: item_name(intr, impl_item), + methods: item_impl_methods(intr, cdata, impl_item, base_tps), } - @result } pub fn get_method_name_and_explicit_self( @@ -754,8 +891,7 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, if item_method_sort(mth) != 'p' { loop; } - vec::push(&mut result, - @get_method(intr, cdata, did.node, tcx)); + result.push(@get_method(intr, cdata, did.node, tcx)); } return result; diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index b96e96c9618..e394c8dcf92 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -16,14 +16,13 @@ use metadata::common::*; use metadata::cstore; use metadata::decoder; use metadata::tyencode; -use middle::trans::reachable; use middle::ty::node_id_to_type; use middle::ty; use middle; use util::ppaux::ty_to_str; use core::hash::HashUtil; -use core::hashmap::HashMap; +use core::hashmap::{HashMap, HashSet}; use core::int; use core::io; use core::str; @@ -60,13 +59,13 @@ pub type encode_inlined_item<'self> = &'self fn(ecx: &EncodeContext, pub struct EncodeParams<'self> { diag: @span_handler, tcx: ty::ctxt, - reachable: reachable::map, reexports2: middle::resolve::ExportMap2, item_symbols: &'self HashMap<ast::node_id, ~str>, discrim_symbols: &'self HashMap<ast::node_id, @str>, link_meta: &'self LinkMeta, cstore: @mut cstore::CStore, - encode_inlined_item: encode_inlined_item<'self> + encode_inlined_item: encode_inlined_item<'self>, + reachable: @mut HashSet<ast::node_id>, } struct Stats { @@ -75,6 +74,7 @@ struct Stats { dep_bytes: uint, lang_item_bytes: uint, link_args_bytes: uint, + misc_bytes: uint, item_bytes: uint, index_bytes: uint, zero_bytes: uint, @@ -87,14 +87,14 @@ pub struct EncodeContext<'self> { diag: @span_handler, tcx: ty::ctxt, stats: @mut Stats, - reachable: reachable::map, reexports2: middle::resolve::ExportMap2, item_symbols: &'self HashMap<ast::node_id, ~str>, discrim_symbols: &'self HashMap<ast::node_id, @str>, link_meta: &'self LinkMeta, cstore: &'self cstore::CStore, encode_inlined_item: encode_inlined_item<'self>, - type_abbrevs: abbrev_map + type_abbrevs: abbrev_map, + reachable: @mut HashSet<ast::node_id>, } pub fn reachable(ecx: &EncodeContext, id: node_id) -> bool { @@ -157,8 +157,8 @@ fn encode_trait_ref(ebml_w: &mut writer::Encoder, diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs) + }; ebml_w.start_tag(tag); tyencode::enc_trait_ref(ebml_w.writer, ty_str_ctxt, trait_ref); @@ -185,8 +185,8 @@ fn encode_ty_type_param_defs(ebml_w: &mut writer::Encoder, diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs) + }; for params.iter().advance |param| { ebml_w.start_tag(tag); tyencode::enc_type_param_def(ebml_w.writer, ty_str_ctxt, param); @@ -218,8 +218,8 @@ pub fn write_type(ecx: &EncodeContext, diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs) + }; tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ); } @@ -231,8 +231,8 @@ pub fn write_vstore(ecx: &EncodeContext, diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs) + }; tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore); } @@ -264,8 +264,8 @@ fn encode_method_fty(ecx: &EncodeContext, diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs) + }; tyencode::enc_bare_fn_ty(ebml_w.writer, ty_str_ctxt, typ); ebml_w.end_tag(); @@ -473,12 +473,77 @@ fn encode_reexported_static_methods(ecx: &EncodeContext, } } +/// Iterates through "auxiliary node IDs", which are node IDs that describe +/// top-level items that are sub-items of the given item. Specifically: +/// +/// * For enums, iterates through the node IDs of the variants. +/// +/// * For newtype structs, iterates through the node ID of the constructor. +fn each_auxiliary_node_id(item: @item, callback: &fn(node_id) -> bool) + -> bool { + let mut continue = true; + match item.node { + item_enum(ref enum_def, _) => { + for enum_def.variants.iter().advance |variant| { + continue = callback(variant.node.id); + if !continue { + break + } + } + } + item_struct(struct_def, _) => { + // If this is a newtype struct, return the constructor. + match struct_def.ctor_id { + Some(ctor_id) if struct_def.fields.len() > 0 && + struct_def.fields[0].node.kind == + ast::unnamed_field => { + continue = callback(ctor_id); + } + _ => {} + } + } + _ => {} + } + + continue +} + +fn encode_reexports(ecx: &EncodeContext, + ebml_w: &mut writer::Encoder, + id: node_id, + path: &[ast_map::path_elt]) { + debug!("(encoding info for module) encoding reexports for %d", id); + match ecx.reexports2.find(&id) { + Some(ref exports) => { + debug!("(encoding info for module) found reexports for %d", id); + for exports.iter().advance |exp| { + debug!("(encoding info for module) reexport '%s' for %d", + exp.name, id); + ebml_w.start_tag(tag_items_data_item_reexport); + ebml_w.start_tag(tag_items_data_item_reexport_def_id); + ebml_w.wr_str(def_to_str(exp.def_id)); + ebml_w.end_tag(); + ebml_w.start_tag(tag_items_data_item_reexport_name); + ebml_w.wr_str(exp.name); + ebml_w.end_tag(); + ebml_w.end_tag(); + encode_reexported_static_methods(ecx, ebml_w, path, exp); + } + } + None => { + debug!("(encoding info for module) found no reexports for %d", + id); + } + } +} + fn encode_info_for_mod(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, md: &_mod, id: node_id, path: &[ast_map::path_elt], - name: ident) { + name: ident, + vis: visibility) { ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(id)); encode_family(ebml_w, 'm'); @@ -487,6 +552,16 @@ fn encode_info_for_mod(ecx: &EncodeContext, // Encode info about all the module children. for md.items.iter().advance |item| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(item.id))); + ebml_w.end_tag(); + + for each_auxiliary_node_id(*item) |auxiliary_node_id| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(auxiliary_node_id))); + ebml_w.end_tag(); + } + match item.node { item_impl(*) => { let (ident, did) = (item.ident, item.id); @@ -500,35 +575,16 @@ fn encode_info_for_mod(ecx: &EncodeContext, ebml_w.wr_str(def_to_str(local_def(did))); ebml_w.end_tag(); } - _ => {} // FIXME #4573: Encode these too. + _ => {} } } encode_path(ecx, ebml_w, path, ast_map::path_mod(name)); - // Encode the reexports of this module. - debug!("(encoding info for module) encoding reexports for %d", id); - match ecx.reexports2.find(&id) { - Some(ref exports) => { - debug!("(encoding info for module) found reexports for %d", id); - for exports.iter().advance |exp| { - debug!("(encoding info for module) reexport '%s' for %d", - exp.name, id); - ebml_w.start_tag(tag_items_data_item_reexport); - ebml_w.start_tag(tag_items_data_item_reexport_def_id); - ebml_w.wr_str(def_to_str(exp.def_id)); - ebml_w.end_tag(); - ebml_w.start_tag(tag_items_data_item_reexport_name); - ebml_w.wr_str(exp.name); - ebml_w.end_tag(); - ebml_w.end_tag(); - encode_reexported_static_methods(ecx, ebml_w, path, exp); - } - } - None => { - debug!("(encoding info for module) found no reexports for %d", - id); - } + // Encode the reexports of this module, if this module is public. + if vis == public { + debug!("(encoding info for module) encoding reexports for %d", id); + encode_reexports(ecx, ebml_w, id, path); } ebml_w.end_tag(); @@ -780,13 +836,6 @@ fn encode_info_for_item(ecx: &EncodeContext, index: @mut ~[entry<int>], path: &[ast_map::path_elt]) { let tcx = ecx.tcx; - let must_write = - match item.node { - item_enum(_, _) | item_impl(*) | item_trait(*) | item_struct(*) | - item_mod(*) | item_foreign_mod(*) | item_static(*) => true, - _ => false - }; - if !must_write && !reachable(ecx, item.id) { return; } fn add_to_index_(item: @item, ebml_w: &writer::Encoder, index: @mut ~[entry<int>]) { @@ -809,6 +858,7 @@ fn encode_info_for_item(ecx: &EncodeContext, } encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_symbol(ecx, ebml_w, item.id); + encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); ebml_w.end_tag(); @@ -821,6 +871,7 @@ fn encode_info_for_item(ecx: &EncodeContext, let tps_len = generics.ty_params.len(); encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); encode_attributes(ebml_w, item.attrs); if tps_len > 0u || should_inline(item.attrs) { @@ -832,15 +883,29 @@ fn encode_info_for_item(ecx: &EncodeContext, } item_mod(ref m) => { add_to_index(); - encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident); + encode_info_for_mod(ecx, + ebml_w, + m, + item.id, + path, + item.ident, + item.vis); } - item_foreign_mod(_) => { + item_foreign_mod(ref fm) => { add_to_index(); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); encode_family(ebml_w, 'n'); encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + + // Encode all the items in this module. + for fm.items.iter().advance |foreign_item| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(foreign_item.id))); + ebml_w.end_tag(); + } + ebml_w.end_tag(); } item_ty(_, ref generics) => { @@ -898,23 +963,6 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - // If this is a tuple- or enum-like struct, encode the type of the - // constructor. - if struct_def.fields.len() > 0 && - struct_def.fields[0].node.kind == ast::unnamed_field { - let ctor_id = match struct_def.ctor_id { - Some(ctor_id) => ctor_id, - None => ecx.tcx.sess.bug("struct def didn't have ctor id"), - }; - - encode_info_for_struct_ctor(ecx, - ebml_w, - path, - item.ident, - ctor_id, - index); - } - encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); @@ -944,6 +992,23 @@ fn encode_info_for_item(ecx: &EncodeContext, let bkts = create_index(idx); encode_index(ebml_w, bkts, write_int); ebml_w.end_tag(); + + // If this is a tuple- or enum-like struct, encode the type of the + // constructor. + if struct_def.fields.len() > 0 && + struct_def.fields[0].node.kind == ast::unnamed_field { + let ctor_id = match struct_def.ctor_id { + Some(ctor_id) => ctor_id, + None => ecx.tcx.sess.bug("struct def didn't have ctor id"), + }; + + encode_info_for_struct_ctor(ecx, + ebml_w, + path, + item.ident, + ctor_id, + index); + } } item_impl(ref generics, opt_trait, ty, ref methods) => { add_to_index(); @@ -979,7 +1044,7 @@ fn encode_info_for_item(ecx: &EncodeContext, // >:-< let mut impl_path = vec::append(~[], path); - impl_path += [ast_map::path_name(item.ident)]; + impl_path.push(ast_map::path_name(item.ident)); for methods.iter().advance |m| { index.push(entry {val: m.id, pos: ebml_w.writer.tell()}); @@ -1008,6 +1073,10 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w.start_tag(tag_item_trait_method); encode_def_id(ebml_w, method_def_id); ebml_w.end_tag(); + + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(method_def_id)); + ebml_w.end_tag(); } encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); for super_traits.iter().advance |ast_trait_ref| { @@ -1092,7 +1161,6 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, index: @mut ~[entry<int>], path: ast_map::path, abi: AbiSet) { - if !reachable(ecx, nitem.id) { return; } index.push(entry { val: nitem.id, pos: ebml_w.writer.tell() }); ebml_w.start_tag(tag_items_data_item); @@ -1102,6 +1170,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, encode_family(ebml_w, purity_fn_family(purity)); encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); + encode_name(ecx, ebml_w, nitem.ident); if abi.is_intrinsic() { (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_foreign(nitem)); } else { @@ -1118,6 +1187,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, } encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); encode_symbol(ecx, ebml_w, nitem.id); + encode_name(ecx, ebml_w, nitem.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident)); } } @@ -1131,9 +1201,13 @@ fn encode_info_for_items(ecx: &EncodeContext, let index = @mut ~[]; ebml_w.start_tag(tag_items_data); index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() }); - encode_info_for_mod(ecx, ebml_w, &crate.node.module, - crate_node_id, [], - syntax::parse::token::special_idents::invalid); + encode_info_for_mod(ecx, + ebml_w, + &crate.node.module, + crate_node_id, + [], + syntax::parse::token::special_idents::invalid, + public); let items = ecx.tcx.items; // See comment in `encode_side_tables_for_ii` in astencode @@ -1162,6 +1236,12 @@ fn encode_info_for_items(ecx: &EncodeContext, visit::visit_foreign_item(ni, (cx, v)); match items.get_copy(&ni.id) { ast_map::node_foreign_item(_, abi, _, pt) => { + debug!("writing foreign item %s::%s", + ast_map::path_to_str( + *pt, + token::get_ident_interner()), + token::ident_to_str(&ni.ident)); + let mut ebml_w = copy ebml_w; // See above let ecx : &EncodeContext = unsafe { cast::transmute(ecx_ptr) }; @@ -1421,6 +1501,30 @@ fn encode_link_args(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.end_tag(); } +fn encode_misc_info(ecx: &EncodeContext, + crate: &crate, + ebml_w: &mut writer::Encoder) { + ebml_w.start_tag(tag_misc_info); + ebml_w.start_tag(tag_misc_info_crate_items); + for crate.node.module.items.iter().advance |&item| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(item.id))); + ebml_w.end_tag(); + + for each_auxiliary_node_id(item) |auxiliary_node_id| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(auxiliary_node_id))); + ebml_w.end_tag(); + } + } + + // Encode reexports for the root module. + encode_reexports(ecx, ebml_w, 0, []); + + ebml_w.end_tag(); + ebml_w.end_tag(); +} + fn encode_crate_dep(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, dep: decoder::crate_dep) { @@ -1460,29 +1564,39 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { dep_bytes: 0, lang_item_bytes: 0, link_args_bytes: 0, + misc_bytes: 0, item_bytes: 0, index_bytes: 0, zero_bytes: 0, total_bytes: 0, n_inlines: 0 }; - let EncodeParams{item_symbols, diag, tcx, reachable, reexports2, - discrim_symbols, cstore, encode_inlined_item, - link_meta, _} = parms; + let EncodeParams { + item_symbols, + diag, + tcx, + reexports2, + discrim_symbols, + cstore, + encode_inlined_item, + link_meta, + reachable, + _ + } = parms; let type_abbrevs = @mut HashMap::new(); let stats = @mut stats; let ecx = EncodeContext { diag: diag, tcx: tcx, stats: stats, - reachable: reachable, reexports2: reexports2, item_symbols: item_symbols, discrim_symbols: discrim_symbols, link_meta: link_meta, cstore: cstore, encode_inlined_item: encode_inlined_item, - type_abbrevs: type_abbrevs + type_abbrevs: type_abbrevs, + reachable: reachable, }; let mut ebml_w = writer::Encoder(wr as @io::Writer); @@ -1508,6 +1622,11 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { encode_link_args(&ecx, &mut ebml_w); ecx.stats.link_args_bytes = *wr.pos - i; + // Encode miscellaneous info. + i = *wr.pos; + encode_misc_info(&ecx, crate, &mut ebml_w); + ecx.stats.misc_bytes = *wr.pos - i; + // Encode and index the items. ebml_w.start_tag(tag_items); i = *wr.pos; @@ -1535,6 +1654,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { io::println(fmt!(" dep bytes: %u", ecx.stats.dep_bytes)); io::println(fmt!(" lang item bytes: %u", ecx.stats.lang_item_bytes)); io::println(fmt!(" link args bytes: %u", ecx.stats.link_args_bytes)); + io::println(fmt!(" misc bytes: %u", ecx.stats.misc_bytes)); io::println(fmt!(" item bytes: %u", ecx.stats.item_bytes)); io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes)); io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes)); @@ -1557,7 +1677,6 @@ pub fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str { diag: tcx.diag, ds: def_to_str, tcx: tcx, - reachable: |_id| false, abbrevs: tyencode::ac_no_abbrevs}; do io::with_str_writer |wr| { tyencode::enc_ty(wr, cx, t); diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 6268932ba99..abfb5f7d4d4 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -48,7 +48,7 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, debug!("filesearch: searching additional lib search paths [%?]", self.addl_lib_search_paths.len()); // a little weird - self.addl_lib_search_paths.iter().advance(f); + self.addl_lib_search_paths.iter().advance(|path| f(path)); debug!("filesearch: searching target lib path"); if !f(&make_target_lib_path(self.sysroot, diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index c3840c9c87f..22786581073 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -20,7 +20,6 @@ use middle::ty; use core::str; use core::uint; -use core::vec; use syntax::abi::AbiSet; use syntax::abi; use syntax::ast; @@ -190,11 +189,11 @@ fn parse_trait_store(st: &mut PState) -> ty::TraitStore { fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs { let self_r = parse_opt(st, |st| parse_region(st) ); - let self_ty = parse_opt(st, |st| parse_ty(st, conv) ); + let self_ty = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)) ); assert_eq!(next(st), '['); let mut params: ~[ty::t] = ~[]; - while peek(st) != ']' { params.push(parse_ty(st, conv)); } + while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); } st.pos = st.pos + 1u; return ty::substs { @@ -262,15 +261,17 @@ fn parse_opt<T>(st: &mut PState, f: &fn(&mut PState) -> T) -> Option<T> { fn parse_str(st: &mut PState, term: char) -> ~str { let mut result = ~""; while peek(st) != term { - result += str::from_byte(next_byte(st)); + unsafe { + str::raw::push_byte(&mut result, next_byte(st)); + } } next(st); return result; } fn parse_trait_ref(st: &mut PState, conv: conv_did) -> ty::TraitRef { - let def = parse_def(st, NominalType, conv); - let substs = parse_substs(st, conv); + let def = parse_def(st, NominalType, |x,y| conv(x,y)); + let substs = parse_substs(st, |x,y| conv(x,y)); ty::TraitRef {def_id: def, substs: substs} } @@ -300,18 +301,18 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { 'c' => return ty::mk_char(), 't' => { assert_eq!(next(st), '['); - let def = parse_def(st, NominalType, conv); - let substs = parse_substs(st, conv); + let def = parse_def(st, NominalType, |x,y| conv(x,y)); + let substs = parse_substs(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_enum(st.tcx, def, substs); } 'x' => { assert_eq!(next(st), '['); - let def = parse_def(st, NominalType, conv); - let substs = parse_substs(st, conv); + let def = parse_def(st, NominalType, |x,y| conv(x,y)); + let substs = parse_substs(st, |x,y| conv(x,y)); let store = parse_trait_store(st); let mt = parse_mutability(st); - let bounds = parse_bounds(st, conv); + let bounds = parse_bounds(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_trait(st.tcx, def, substs, store, mt, bounds.builtin_bounds); } @@ -345,7 +346,7 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { 'T' => { assert_eq!(next(st), '['); let mut params = ~[]; - while peek(st) != ']' { params.push(parse_ty(st, conv)); } + while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); } st.pos = st.pos + 1u; return ty::mk_tup(st.tcx, params); } @@ -379,15 +380,15 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { } } '"' => { - let _ = parse_def(st, TypeWithId, conv); - let inner = parse_ty(st, conv); + let _ = parse_def(st, TypeWithId, |x,y| conv(x,y)); + let inner = parse_ty(st, |x,y| conv(x,y)); inner } 'B' => ty::mk_opaque_box(st.tcx), 'a' => { assert_eq!(next(st), '['); - let did = parse_def(st, NominalType, conv); - let substs = parse_substs(st, conv); + let did = parse_def(st, NominalType, |x,y| conv(x,y)); + let substs = parse_substs(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_struct(st.tcx, did, substs); } @@ -472,8 +473,8 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy { let purity = parse_purity(next(st)); let onceness = parse_onceness(next(st)); let region = parse_region(st); - let bounds = parse_bounds(st, conv); - let sig = parse_sig(st, conv); + let bounds = parse_bounds(st, |x,y| conv(x,y)); + let sig = parse_sig(st, |x,y| conv(x,y)); ty::ClosureTy { purity: purity, sigil: sigil, @@ -499,7 +500,7 @@ fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig { assert_eq!(next(st), '['); let mut inputs = ~[]; while peek(st) != ']' { - inputs.push(parse_ty(st, conv)); + inputs.push(parse_ty(st, |x,y| conv(x,y))); } st.pos += 1u; // eat the ']' let ret_ty = parse_ty(st, conv); @@ -518,8 +519,8 @@ pub fn parse_def_id(buf: &[u8]) -> ast::def_id { fail!(); } - let crate_part = vec::slice(buf, 0u, colon_idx); - let def_part = vec::slice(buf, colon_idx + 1u, len); + let crate_part = buf.slice(0u, colon_idx); + let def_part = buf.slice(colon_idx + 1u, len); let crate_num = match uint::parse_bytes(crate_part, 10u) { Some(cn) => cn as int, @@ -543,8 +544,8 @@ pub fn parse_type_param_def_data(data: &[u8], start: uint, } fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef { - ty::TypeParameterDef {def_id: parse_def(st, NominalType, conv), - bounds: @parse_bounds(st, conv)} + ty::TypeParameterDef {def_id: parse_def(st, NominalType, |x,y| conv(x,y)), + bounds: @parse_bounds(st, |x,y| conv(x,y))} } fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds { @@ -555,13 +556,13 @@ fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds { loop { match next(st) { 'S' => { - param_bounds.builtin_bounds.add(ty::BoundOwned); + param_bounds.builtin_bounds.add(ty::BoundSend); } 'C' => { param_bounds.builtin_bounds.add(ty::BoundCopy); } 'K' => { - param_bounds.builtin_bounds.add(ty::BoundConst); + param_bounds.builtin_bounds.add(ty::BoundFreeze); } 'O' => { param_bounds.builtin_bounds.add(ty::BoundStatic); @@ -570,7 +571,7 @@ fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds { param_bounds.builtin_bounds.add(ty::BoundSized); } 'I' => { - param_bounds.trait_bounds.push(@parse_trait_ref(st, conv)); + param_bounds.trait_bounds.push(@parse_trait_ref(st, |x,y| conv(x,y))); } '.' => { return param_bounds; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 37fedc16122..fb72617b743 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -31,7 +31,6 @@ pub struct ctxt { ds: @fn(def_id) -> ~str, // The type context. tcx: ty::ctxt, - reachable: @fn(node_id) -> bool, abbrevs: abbrev_ctxt } @@ -401,9 +400,9 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) { fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: &ty::ParamBounds) { for bs.builtin_bounds.each |bound| { match bound { - ty::BoundOwned => w.write_char('S'), + ty::BoundSend => w.write_char('S'), ty::BoundCopy => w.write_char('C'), - ty::BoundConst => w.write_char('K'), + ty::BoundFreeze => w.write_char('K'), ty::BoundStatic => w.write_char('O'), ty::BoundSized => w.write_char('Z'), } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index fb8238b84d6..16e3bd34cdd 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -368,14 +368,17 @@ impl tr for ast::def { ast::def_static_method(did.tr(xcx), did2_opt.map(|did2| did2.tr(xcx)), p) - }, - ast::def_self_ty(nid) => ast::def_self_ty(xcx.tr_id(nid)), - ast::def_self(nid, i) => ast::def_self(xcx.tr_id(nid), i), - ast::def_mod(did) => ast::def_mod(did.tr(xcx)), - ast::def_foreign_mod(did) => ast::def_foreign_mod(did.tr(xcx)), - ast::def_static(did, m) => ast::def_static(did.tr(xcx), m), - ast::def_arg(nid, b) => ast::def_arg(xcx.tr_id(nid), b), - ast::def_local(nid, b) => ast::def_local(xcx.tr_id(nid), b), + } + ast::def_method(did0, did1) => { + ast::def_method(did0.tr(xcx), did1.map(|did1| did1.tr(xcx))) + } + ast::def_self_ty(nid) => { ast::def_self_ty(xcx.tr_id(nid)) } + ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) } + ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) } + ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) } + ast::def_static(did, m) => { ast::def_static(did.tr(xcx), m) } + ast::def_arg(nid, b) => { ast::def_arg(xcx.tr_id(nid), b) } + ast::def_local(nid, b) => { ast::def_local(xcx.tr_id(nid), b) } ast::def_variant(e_did, v_did) => { ast::def_variant(e_did.tr(xcx), v_did.tr(xcx)) }, @@ -596,8 +599,10 @@ fn encode_vtable_res(ecx: &e::EncodeContext, // ty::t doesn't work, and there is no way (atm) to have // hand-written encoding routines combine with auto-generated // ones. perhaps we should fix this. - do ebml_w.emit_from_vec(*dr) |ebml_w, vtable_origin| { - encode_vtable_origin(ecx, ebml_w, vtable_origin) + do ebml_w.emit_from_vec(*dr) |ebml_w, param_tables| { + do ebml_w.emit_from_vec(**param_tables) |ebml_w, vtable_origin| { + encode_vtable_origin(ecx, ebml_w, vtable_origin) + } } } @@ -629,6 +634,13 @@ fn encode_vtable_origin(ecx: &e::EncodeContext, } } } + typeck::vtable_self(def_id) => { + do ebml_w.emit_enum_variant("vtable_self", 2u, 1u) |ebml_w| { + do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { + ebml_w.emit_def_id(def_id) + } + } + } } } } @@ -643,13 +655,17 @@ trait vtable_decoder_helpers { impl vtable_decoder_helpers for reader::Decoder { fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_res { - @self.read_to_vec(|this| this.read_vtable_origin(xcx)) + @self.read_to_vec(|this| + @this.read_to_vec(|this| + this.read_vtable_origin(xcx))) } fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_origin { do self.read_enum("vtable_origin") |this| { - do this.read_enum_variant(["vtable_static", "vtable_param"]) + do this.read_enum_variant(["vtable_static", + "vtable_param", + "vtable_self"]) |this, i| { match i { 0 => { @@ -675,6 +691,13 @@ impl vtable_decoder_helpers for reader::Decoder { } ) } + 2 => { + typeck::vtable_self( + do this.read_enum_variant_arg(0u) |this| { + this.read_def_id(xcx) + } + ) + } // hard to avoid - user input _ => fail!("bad enum variant") } @@ -692,12 +715,12 @@ trait get_ty_str_ctxt { impl<'self> get_ty_str_ctxt for e::EncodeContext<'self> { fn ty_str_ctxt(&self) -> @tyencode::ctxt { - let r = self.reachable; - @tyencode::ctxt {diag: self.tcx.sess.diagnostic(), - ds: e::def_to_str, - tcx: self.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(self.type_abbrevs)} + @tyencode::ctxt { + diag: self.tcx.sess.diagnostic(), + ds: e::def_to_str, + tcx: self.tcx, + abbrevs: tyencode::ac_use_abbrevs(self.type_abbrevs) + } } } diff --git a/src/librustc/middle/borrowck/doc.rs b/src/librustc/middle/borrowck/doc.rs index cb3983117e9..8bb5c4620ef 100644 --- a/src/librustc/middle/borrowck/doc.rs +++ b/src/librustc/middle/borrowck/doc.rs @@ -359,7 +359,7 @@ of its owner: LIFETIME(LV.f, LT, MQ) // L-Field LIFETIME(LV, LT, MQ) - LIFETIME(*LV, LT, MQ) // L-Deref-Owned + LIFETIME(*LV, LT, MQ) // L-Deref-Send TYPE(LV) = ~Ty LIFETIME(LV, LT, MQ) @@ -504,7 +504,7 @@ must prevent the owned pointer `LV` from being mutated, which means that we always add `MUTATE` and `CLAIM` to the restriction set imposed on `LV`: - RESTRICTIONS(*LV, ACTIONS) = RS, (*LV, ACTIONS) // R-Deref-Owned-Pointer + RESTRICTIONS(*LV, ACTIONS) = RS, (*LV, ACTIONS) // R-Deref-Send-Pointer TYPE(LV) = ~Ty RESTRICTIONS(LV, ACTIONS|MUTATE|CLAIM) = RS @@ -539,14 +539,14 @@ mutable borrowed pointers. ### Restrictions for loans of const aliasable pointees -Const pointers are read-only. There may be `&mut` or `&` aliases, and +Freeze pointers are read-only. There may be `&mut` or `&` aliases, and we can not prevent *anything* but moves in that case. So the `RESTRICTIONS` function is only defined if `ACTIONS` is the empty set. Because moves from a `&const` or `@const` lvalue are never legal, it is not necessary to add any restrictions at all to the final result. - RESTRICTIONS(*LV, []) = [] // R-Deref-Const-Borrowed + RESTRICTIONS(*LV, []) = [] // R-Deref-Freeze-Borrowed TYPE(LV) = &const Ty or @const Ty ### Restrictions for loans of mutable borrowed pointees diff --git a/src/librustc/middle/borrowck/gather_loans/gather_moves.rs b/src/librustc/middle/borrowck/gather_loans/gather_moves.rs index c7bad60e90e..e950610cce6 100644 --- a/src/librustc/middle/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc/middle/borrowck/gather_loans/gather_moves.rs @@ -101,9 +101,7 @@ fn check_is_legal_to_move_from(bccx: @BorrowckCtxt, cmt0: mc::cmt, cmt: mc::cmt) -> bool { match cmt.cat { - mc::cat_stack_upvar(*) | mc::cat_implicit_self(*) | - mc::cat_copied_upvar(*) | mc::cat_deref(_, _, mc::region_ptr(*)) | mc::cat_deref(_, _, mc::gc_ptr(*)) | mc::cat_deref(_, _, mc::unsafe_ptr(*)) => { @@ -114,6 +112,27 @@ fn check_is_legal_to_move_from(bccx: @BorrowckCtxt, false } + // These are separate from the above cases for a better error message. + mc::cat_stack_upvar(*) | + mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, _ }) => { + let once_hint = if bccx.tcx.sess.once_fns() { + " (unless the destination closure type is `once fn')" + } else { + "" + }; + bccx.span_err( + cmt0.span, + fmt!("cannot move out of %s%s", bccx.cmt_to_str(cmt), once_hint)); + false + } + + // Can move out of captured upvars only if the destination closure + // type is 'once'. 1-shot stack closures emit the copied_upvar form + // (see mem_categorization.rs). + mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Once, _ }) => { + true + } + // It seems strange to allow a move out of a static item, // but what happens in practice is that you have a // reference to a constant with a type that should be diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 9455340268e..131ee5aa067 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -109,7 +109,7 @@ impl GuaranteeLifetimeContext { } mc::cat_downcast(base) | - mc::cat_deref(base, _, mc::uniq_ptr(*)) | // L-Deref-Owned + mc::cat_deref(base, _, mc::uniq_ptr(*)) | // L-Deref-Send mc::cat_interior(base, _) => { // L-Field self.check(base, discr_scope) } diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index bedb465c5c1..5f4251ad0a4 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -103,7 +103,7 @@ impl RestrictionsContext { } mc::cat_deref(cmt_base, _, mc::uniq_ptr(*)) => { - // R-Deref-Owned-Pointer + // R-Deref-Send-Pointer // // When we borrow the interior of an owned pointer, we // cannot permit the base to be mutated, because that @@ -125,7 +125,7 @@ impl RestrictionsContext { mc::cat_deref(_, _, mc::region_ptr(m_const, _)) | mc::cat_deref(_, _, mc::gc_ptr(m_const)) => { - // R-Deref-Const-Borrowed + // R-Deref-Freeze-Borrowed self.check_no_mutability_control(cmt, restrictions); Safe } diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index 7396dc1bd7b..623dbbd61b2 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -411,7 +411,7 @@ impl MoveData { let mut p = self.path(index).first_child; while p != InvalidMovePathIndex { - if !self.each_extending_path(p, f) { + if !self.each_extending_path(p, |x| f(x)) { return false; } p = self.path(p).next_sibling; diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index acd47eca726..93202f3fd55 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -132,7 +132,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { debug!("add_gen(id=%?, bit=%?)", id, bit); let (start, end) = self.compute_id_range(id); { - let gens = vec::mut_slice(self.gens, start, end); + let gens = self.gens.mut_slice(start, end); set_bit(gens, bit); } } @@ -143,7 +143,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { debug!("add_kill(id=%?, bit=%?)", id, bit); let (start, end) = self.compute_id_range(id); { - let kills = vec::mut_slice(self.kills, start, end); + let kills = self.kills.mut_slice(start, end); set_bit(kills, bit); } } @@ -216,7 +216,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { return true; } let (start, end) = self.compute_id_range_frozen(id); - let on_entry = vec::slice(self.on_entry, start, end); + let on_entry = self.on_entry.slice(start, end); debug!("each_bit_on_entry_frozen(id=%?, on_entry=%s)", id, bits_to_str(on_entry)); self.each_bit(on_entry, f) @@ -229,7 +229,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { //! Only useful after `propagate()` has been called. let (start, end) = self.compute_id_range(id); - let on_entry = vec::slice(self.on_entry, start, end); + let on_entry = self.on_entry.slice(start, end); debug!("each_bit_on_entry(id=%?, on_entry=%s)", id, bits_to_str(on_entry)); self.each_bit(on_entry, f) @@ -241,7 +241,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { //! Iterates through each bit in the gen set for `id`. let (start, end) = self.compute_id_range(id); - let gens = vec::slice(self.gens, start, end); + let gens = self.gens.slice(start, end); debug!("each_gen_bit(id=%?, gens=%s)", id, bits_to_str(gens)); self.each_bit(gens, f) @@ -255,7 +255,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { return true; } let (start, end) = self.compute_id_range_frozen(id); - let gens = vec::slice(self.gens, start, end); + let gens = self.gens.slice(start, end); debug!("each_gen_bit(id=%?, gens=%s)", id, bits_to_str(gens)); self.each_bit(gens, f) @@ -338,17 +338,17 @@ impl<O:DataFlowOperator+Copy+'static> DataFlowContext<O> { if self.nodeid_to_bitset.contains_key(&id) { let (start, end) = self.compute_id_range_frozen(id); - let on_entry = vec::slice(self.on_entry, start, end); + let on_entry = self.on_entry.slice(start, end); let entry_str = bits_to_str(on_entry); - let gens = vec::slice(self.gens, start, end); + let gens = self.gens.slice(start, end); let gens_str = if gens.iter().any_(|&u| u != 0) { fmt!(" gen: %s", bits_to_str(gens)) } else { ~"" }; - let kills = vec::slice(self.kills, start, end); + let kills = self.kills.slice(start, end); let kills_str = if kills.iter().any_(|&u| u != 0) { fmt!(" kill: %s", bits_to_str(kills)) } else { @@ -953,7 +953,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { id, bits_to_str(pred_bits)); let (start, end) = self.dfcx.compute_id_range(id); let changed = { // FIXME(#5074) awkward construction - let on_entry = vec::mut_slice(self.dfcx.on_entry, start, end); + let on_entry = self.dfcx.on_entry.mut_slice(start, end); join_bits(&self.dfcx.oper, pred_bits, on_entry) }; if changed { @@ -970,7 +970,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { id, mut_bits_to_str(pred_bits)); let (start, end) = self.dfcx.compute_id_range(id); let changed = { // FIXME(#5074) awkward construction - let on_entry = vec::mut_slice(self.dfcx.on_entry, start, end); + let on_entry = self.dfcx.on_entry.mut_slice(start, end); let changed = join_bits(&self.dfcx.oper, reslice(pred_bits), on_entry); copy_bits(reslice(on_entry), pred_bits); changed diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index ef96fa97972..d4b91ed589d 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -31,21 +31,21 @@ use syntax::{visit, ast_util}; // // send: Things that can be sent on channels or included in spawned closures. // copy: Things that can be copied. -// const: Things thare are deeply immutable. They are guaranteed never to +// freeze: Things thare are deeply immutable. They are guaranteed never to // change, and can be safely shared without copying between tasks. -// owned: Things that do not contain borrowed pointers. +// 'static: Things that do not contain borrowed pointers. // // Send includes scalar types as well as classes and unique types containing // only sendable types. // // Copy includes boxes, closure and unique types containing copyable types. // -// Const include scalar types, things without non-const fields, and pointers -// to const things. +// Freeze include scalar types, things without non-const fields, and pointers +// to freezable things. // // This pass ensures that type parameters are only instantiated with types // whose kinds are equal or less general than the way the type parameter was -// annotated (with the `send`, `copy` or `const` keyword). +// annotated (with the `Send`, `Copy` or `Freeze` bound). // // It also verifies that noncopyable kinds are not copied. Sendability is not // applied, since none of our language primitives send. Instead, the sending @@ -90,10 +90,10 @@ fn check_struct_safe_for_destructor(cx: Context, self_ty: None, tps: ~[] }); - if !ty::type_is_owned(cx.tcx, struct_ty) { + if !ty::type_is_sendable(cx.tcx, struct_ty) { cx.tcx.sess.span_err(span, - "cannot implement a destructor on a struct \ - that is not Owned"); + "cannot implement a destructor on a \ + structure that does not satisfy Send"); cx.tcx.sess.span_note(span, "use \"#[unsafe_destructor]\" on the \ implementation to force the compiler to \ @@ -101,7 +101,7 @@ fn check_struct_safe_for_destructor(cx: Context, } } else { cx.tcx.sess.span_err(span, - "cannot implement a destructor on a struct \ + "cannot implement a destructor on a structure \ with type parameters"); cx.tcx.sess.span_note(span, "use \"#[unsafe_destructor]\" on the \ @@ -171,7 +171,7 @@ fn with_appropriate_checker(cx: Context, id: node_id, // 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); + check_freevar_bounds(cx, fv.span, var_t, bounds, None); } fn check_for_box(cx: Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) { @@ -182,13 +182,18 @@ fn with_appropriate_checker(cx: Context, id: node_id, // 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); + check_freevar_bounds(cx, fv.span, var_t, bounds, None); } - fn check_for_block(cx: Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) { + fn check_for_block(cx: Context, fv: &freevar_entry, + bounds: ty::BuiltinBounds, region: ty::Region) { 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); + // FIXME(#3569): Figure out whether the implicit borrow is actually + // mutable. Currently we assume all upvars are referenced mutably. + let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, region, var_t); + check_freevar_bounds(cx, fv.span, implicit_borrowed_type, + bounds, Some(var_t)); } fn check_for_bare(cx: Context, fv: @freevar_entry) { @@ -205,8 +210,9 @@ fn with_appropriate_checker(cx: Context, id: node_id, 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, bounds: bounds, _}) => { - b(|cx, fv| check_for_block(cx, fv, bounds)) + ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, bounds: bounds, + region: region, _}) => { + b(|cx, fv| check_for_block(cx, fv, bounds, region)) } ty::ty_bare_fn(_) => { b(check_for_bare) @@ -366,14 +372,21 @@ pub fn check_typaram_bounds(cx: Context, } pub fn check_freevar_bounds(cx: Context, sp: span, ty: ty::t, - bounds: ty::BuiltinBounds) + bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>) { 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))); + // Will be Some if the freevar is implicitly borrowed (stack closure). + // Emit a less mysterious error message in this case. + match referenced_ty { + Some(rty) => cx.tcx.sess.span_err(sp, + fmt!("cannot implicitly borrow variable of type `%s` in a bounded \ + stack closure (implicit reference does not fulfill `%s`)", + ty_to_str(cx.tcx, rty), missing.user_string(cx.tcx))), + None => 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`", @@ -438,10 +451,10 @@ fn check_copy(cx: Context, ty: ty::t, sp: span, reason: &str) { } } -pub fn check_owned(cx: Context, ty: ty::t, sp: span) -> bool { - if !ty::type_is_owned(cx.tcx, ty) { +pub fn check_send(cx: Context, ty: ty::t, sp: span) -> bool { + if !ty::type_is_sendable(cx.tcx, ty) { cx.tcx.sess.span_err( - sp, fmt!("value has non-owned type `%s`", + sp, fmt!("value has non-sendable type `%s`", ty_to_str(cx.tcx, ty))); false } else { @@ -489,7 +502,7 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool { /// `deque<T>`, then whatever borrowed ptrs may appear in `T` also /// appear in `deque<T>`. /// -/// (3) The type parameter is owned (and therefore does not contain +/// (3) The type parameter is sendable (and therefore does not contain /// borrowed ptrs). /// /// FIXME(#5723)---This code should probably move into regionck. @@ -528,7 +541,7 @@ pub fn check_cast_for_escaping_regions( } // Assuming the trait instance can escape, then ensure that each parameter - // either appears in the trait type or is owned. + // either appears in the trait type or is sendable. let target_params = ty::param_tys_in_type(target_ty); let source_ty = ty::expr_ty(cx.tcx, source); ty::walk_regions_and_ty( @@ -574,3 +587,4 @@ pub fn check_cast_for_escaping_regions( cx.tcx.region_maps.is_subregion_of(r_sub, r_sup) } } + diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index cd6070cc638..08e55df5b36 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -13,9 +13,9 @@ // Language items are items that represent concepts intrinsic to the language // itself. Examples are: // -// * Traits that specify "kinds"; e.g. "const", "copy", "owned". +// * Traits that specify "kinds"; e.g. "Freeze", "Copy", "Send". // -// * Traits that represent operators; e.g. "add", "sub", "index". +// * Traits that represent operators; e.g. "Add", "Sub", "Index". // // * Functions called by the compiler itself. @@ -33,9 +33,9 @@ use syntax::visit::visit_crate; use core::hashmap::HashMap; pub enum LangItem { - ConstTraitLangItem, // 0 + FreezeTraitLangItem, // 0 CopyTraitLangItem, // 1 - OwnedTraitLangItem, // 2 + SendTraitLangItem, // 2 SizedTraitLangItem, // 3 DropTraitLangItem, // 4 @@ -99,9 +99,9 @@ impl LanguageItems { pub fn item_name(index: uint) -> &'static str { match index { - 0 => "const", + 0 => "freeze", 1 => "copy", - 2 => "owned", + 2 => "send", 3 => "sized", 4 => "drop", @@ -152,14 +152,14 @@ impl LanguageItems { // FIXME #4621: Method macros sure would be nice here. - pub fn const_trait(&const self) -> def_id { - self.items[ConstTraitLangItem as uint].get() + pub fn freeze_trait(&const self) -> def_id { + self.items[FreezeTraitLangItem as uint].get() } pub fn copy_trait(&const self) -> def_id { self.items[CopyTraitLangItem as uint].get() } - pub fn owned_trait(&const self) -> def_id { - self.items[OwnedTraitLangItem as uint].get() + pub fn send_trait(&const self) -> def_id { + self.items[SendTraitLangItem as uint].get() } pub fn sized_trait(&const self) -> def_id { self.items[SizedTraitLangItem as uint].get() @@ -291,13 +291,13 @@ struct LanguageItemCollector<'self> { } impl<'self> LanguageItemCollector<'self> { - - pub fn new<'a>(crate: &'a crate, session: Session) -> LanguageItemCollector<'a> { + pub fn new<'a>(crate: &'a crate, session: Session) + -> LanguageItemCollector<'a> { let mut item_refs = HashMap::new(); - item_refs.insert(@"const", ConstTraitLangItem as uint); + item_refs.insert(@"freeze", FreezeTraitLangItem as uint); item_refs.insert(@"copy", CopyTraitLangItem as uint); - item_refs.insert(@"owned", OwnedTraitLangItem as uint); + item_refs.insert(@"send", SendTraitLangItem as uint); item_refs.insert(@"sized", SizedTraitLangItem as uint); item_refs.insert(@"drop", DropTraitLangItem as uint); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index f93cb265d78..ad5951b3976 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -78,7 +78,7 @@ pub enum categorization { } #[deriving(Eq)] -struct CopiedUpvar { +pub struct CopiedUpvar { upvar_id: ast::node_id, onceness: ast::Onceness, } @@ -452,7 +452,7 @@ impl mem_categorization_ctxt { ast::def_trait(_) | ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty_param(*) | ast::def_struct(*) | ast::def_typaram_binder(*) | ast::def_region(_) | - ast::def_label(_) | ast::def_self_ty(*) => { + ast::def_label(_) | ast::def_self_ty(*) | ast::def_method(*) => { @cmt_ { id:id, span:span, @@ -507,30 +507,41 @@ impl mem_categorization_ctxt { let ty = ty::node_id_to_type(self.tcx, fn_node_id); match ty::get(ty).sty { ty::ty_closure(ref closure_ty) => { - let sigil = closure_ty.sigil; - match sigil { - ast::BorrowedSigil => { - let upvar_cmt = - self.cat_def(id, span, expr_ty, *inner); - @cmt_ { - id:id, - span:span, - cat:cat_stack_upvar(upvar_cmt), - mutbl:upvar_cmt.mutbl.inherit(), - ty:upvar_cmt.ty - } + // Decide whether to use implicit reference or by copy/move + // capture for the upvar. This, combined with the onceness, + // determines whether the closure can move out of it. + let var_is_refd = match (closure_ty.sigil, closure_ty.onceness) { + // Many-shot stack closures can never move out. + (ast::BorrowedSigil, ast::Many) => true, + // 1-shot stack closures can move out with "-Z once-fns". + (ast::BorrowedSigil, ast::Once) + if self.tcx.sess.once_fns() => false, + (ast::BorrowedSigil, ast::Once) => true, + // Heap closures always capture by copy/move, and can + // move out iff they are once. + (ast::OwnedSigil, _) | (ast::ManagedSigil, _) => false, + + }; + if var_is_refd { + let upvar_cmt = + self.cat_def(id, span, expr_ty, *inner); + @cmt_ { + id:id, + span:span, + cat:cat_stack_upvar(upvar_cmt), + mutbl:upvar_cmt.mutbl.inherit(), + ty:upvar_cmt.ty } - ast::OwnedSigil | ast::ManagedSigil => { - // FIXME #2152 allow mutation of moved upvars - @cmt_ { - id:id, - span:span, - cat:cat_copied_upvar(CopiedUpvar { - upvar_id: upvar_id, - onceness: closure_ty.onceness}), - mutbl:McImmutable, - ty:expr_ty - } + } else { + // FIXME #2152 allow mutation of moved upvars + @cmt_ { + id:id, + span:span, + cat:cat_copied_upvar(CopiedUpvar { + upvar_id: upvar_id, + onceness: closure_ty.onceness}), + mutbl:McImmutable, + ty:expr_ty } } } @@ -890,7 +901,7 @@ impl mem_categorization_ctxt { pat, downcast_cmt, subpat_ty, InteriorField(PositionalField(i))); - self.cat_pattern(subcmt, subpat, op); + self.cat_pattern(subcmt, subpat, |x,y| op(x,y)); } } Some(&ast::def_fn(*)) | @@ -901,12 +912,12 @@ impl mem_categorization_ctxt { self.cat_imm_interior( pat, cmt, subpat_ty, InteriorField(PositionalField(i))); - self.cat_pattern(cmt_field, subpat, op); + self.cat_pattern(cmt_field, subpat, |x,y| op(x,y)); } } Some(&ast::def_static(*)) => { for subpats.iter().advance |&subpat| { - self.cat_pattern(cmt, subpat, op); + self.cat_pattern(cmt, subpat, |x,y| op(x,y)); } } _ => { @@ -930,7 +941,7 @@ impl mem_categorization_ctxt { for field_pats.iter().advance |fp| { let field_ty = self.pat_ty(fp.pat); // see (*) let cmt_field = self.cat_field(pat, cmt, fp.ident, field_ty); - self.cat_pattern(cmt_field, fp.pat, op); + self.cat_pattern(cmt_field, fp.pat, |x,y| op(x,y)); } } @@ -942,7 +953,7 @@ impl mem_categorization_ctxt { self.cat_imm_interior( pat, cmt, subpat_ty, InteriorField(PositionalField(i))); - self.cat_pattern(subcmt, subpat, op); + self.cat_pattern(subcmt, subpat, |x,y| op(x,y)); } } @@ -956,15 +967,15 @@ impl mem_categorization_ctxt { ast::pat_vec(ref before, slice, ref after) => { let elt_cmt = self.cat_index(pat, cmt, 0); for before.iter().advance |&before_pat| { - self.cat_pattern(elt_cmt, before_pat, op); + self.cat_pattern(elt_cmt, before_pat, |x,y| op(x,y)); } for slice.iter().advance |&slice_pat| { let slice_ty = self.pat_ty(slice_pat); let slice_cmt = self.cat_rvalue(pat, slice_ty); - self.cat_pattern(slice_cmt, slice_pat, op); + self.cat_pattern(slice_cmt, slice_pat, |x,y| op(x,y)); } for after.iter().advance |&after_pat| { - self.cat_pattern(elt_cmt, after_pat, op); + self.cat_pattern(elt_cmt, after_pat, |x,y| op(x,y)); } } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index 68307a49d3b..cd9d8738026 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -183,6 +183,7 @@ struct VisitContext { move_maps: MoveMaps } +#[deriving(Eq)] enum UseMode { Move, // This value or something owned by it is moved. Read // Read no matter what the type. @@ -335,7 +336,27 @@ impl VisitContext { } expr_call(callee, ref args, _) => { // callee(args) - self.use_expr(callee, Read, visitor); + // Figure out whether the called function is consumed. + let mode = match ty::get(ty::expr_ty(self.tcx, callee)).sty { + ty::ty_closure(ref cty) => { + match cty.onceness { + Once => Move, + Many => Read, + } + }, + ty::ty_bare_fn(*) => Read, + ref x => + self.tcx.sess.span_bug(callee.span, + fmt!("non-function type in moves for expr_call: %?", x)), + }; + // Note we're not using consume_expr, which uses type_moves_by_default + // to determine the mode, for this. The reason is that while stack + // closures should be noncopyable, they shouldn't move by default; + // calling a closure should only consume it if it's once. + if mode == Move { + self.move_maps.moves_map.insert(callee.id); + } + self.use_expr(callee, mode, visitor); self.use_fn_args(callee.id, *args, visitor); } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs new file mode 100644 index 00000000000..88bd9c1f6f4 --- /dev/null +++ b/src/librustc/middle/reachable.rs @@ -0,0 +1,438 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Finds items that are externally reachable, to determine which items +// need to have their metadata (and possibly their AST) serialized. +// All items that can be referred to through an exported name are +// reachable, and when a reachable thing is inline or generic, it +// makes all other generics or inline functions that it references +// reachable as well. + +use core::prelude::*; +use core::iterator::IteratorUtil; + +use middle::resolve; +use middle::ty; +use middle::typeck; + +use core::hashmap::HashSet; +use syntax::ast::*; +use syntax::ast; +use syntax::ast_map; +use syntax::ast_util::def_id_of_def; +use syntax::attr; +use syntax::codemap; +use syntax::parse::token; +use syntax::visit::Visitor; +use syntax::visit; + +// Returns true if the given set of attributes contains the `#[inline]` +// attribute. +fn attributes_specify_inlining(attrs: &[attribute]) -> bool { + attr::attrs_contains_name(attrs, "inline") +} + +// Returns true if the given set of generics implies that the item it's +// associated with must be inlined. +fn generics_require_inlining(generics: &Generics) -> bool { + !generics.ty_params.is_empty() +} + +// Returns true if the given item must be inlined because it may be +// monomorphized or it was marked with `#[inline]`. This will only return +// true for functions. +fn item_might_be_inlined(item: @item) -> bool { + if attributes_specify_inlining(item.attrs) { + return true + } + + match item.node { + item_fn(_, _, _, ref generics, _) => { + generics_require_inlining(generics) + } + _ => false, + } +} + +// Returns true if the given type method must be inlined because it may be +// monomorphized or it was marked with `#[inline]`. +fn ty_method_might_be_inlined(ty_method: &ty_method) -> bool { + attributes_specify_inlining(ty_method.attrs) || + generics_require_inlining(&ty_method.generics) +} + +// Returns true if the given trait method must be inlined because it may be +// monomorphized or it was marked with `#[inline]`. +fn trait_method_might_be_inlined(trait_method: &trait_method) -> bool { + match *trait_method { + required(ref ty_method) => ty_method_might_be_inlined(ty_method), + provided(_) => true + } +} + +// The context we're in. If we're in a public context, then public symbols are +// marked reachable. If we're in a private context, then only trait +// implementations are marked reachable. +#[deriving(Eq)] +enum PrivacyContext { + PublicContext, + PrivateContext, +} + +// Information needed while computing reachability. +struct ReachableContext { + // The type context. + tcx: ty::ctxt, + // The method map, which links node IDs of method call expressions to the + // methods they've been resolved to. + method_map: typeck::method_map, + // The set of items which must be exported in the linkage sense. + reachable_symbols: @mut HashSet<node_id>, + // A worklist of item IDs. Each item ID in this worklist will be inlined + // and will be scanned for further references. + worklist: @mut ~[node_id], +} + +impl ReachableContext { + // Creates a new reachability computation context. + fn new(tcx: ty::ctxt, method_map: typeck::method_map) + -> ReachableContext { + ReachableContext { + tcx: tcx, + method_map: method_map, + reachable_symbols: @mut HashSet::new(), + worklist: @mut ~[], + } + } + + // Step 1: Mark all public symbols, and add all public symbols that might + // be inlined to a worklist. + fn mark_public_symbols(&self, crate: @crate) { + let reachable_symbols = self.reachable_symbols; + let worklist = self.worklist; + let visitor = visit::mk_vt(@Visitor { + visit_item: |item, (privacy_context, visitor): + (PrivacyContext, visit::vt<PrivacyContext>)| { + match item.node { + item_fn(*) => { + if privacy_context == PublicContext { + reachable_symbols.insert(item.id); + } + if item_might_be_inlined(item) { + worklist.push(item.id) + } + } + item_struct(ref struct_def, _) => { + match struct_def.ctor_id { + Some(ctor_id) if + privacy_context == PublicContext => { + reachable_symbols.insert(ctor_id); + } + Some(_) | None => {} + } + } + item_enum(ref enum_def, _) => { + if privacy_context == PublicContext { + for enum_def.variants.iter().advance |variant| { + reachable_symbols.insert(variant.node.id); + } + } + } + item_impl(ref generics, trait_ref, _, ref methods) => { + // XXX(pcwalton): We conservatively assume any methods + // on a trait implementation are reachable, when this + // is not the case. We could be more precise by only + // treating implementations of reachable or cross- + // crate traits as reachable. + + let should_be_considered_public = |method: @method| { + (method.vis == public && + privacy_context == PublicContext) || + trait_ref.is_some() + }; + + // Mark all public methods as reachable. + for methods.iter().advance |&method| { + if should_be_considered_public(method) { + reachable_symbols.insert(method.id); + } + } + + if generics_require_inlining(generics) { + // If the impl itself has generics, add all public + // symbols to the worklist. + for methods.iter().advance |&method| { + if should_be_considered_public(method) { + worklist.push(method.id) + } + } + } else { + // Otherwise, add only public methods that have + // generics to the worklist. + for methods.iter().advance |method| { + let generics = &method.generics; + let attrs = &method.attrs; + if generics_require_inlining(generics) || + attributes_specify_inlining(*attrs) || + should_be_considered_public(*method) { + worklist.push(method.id) + } + } + } + } + item_trait(_, _, ref trait_methods) => { + // Mark all provided methods as reachable. + if privacy_context == PublicContext { + for trait_methods.iter().advance |trait_method| { + match *trait_method { + provided(method) => { + reachable_symbols.insert(method.id); + worklist.push(method.id) + } + required(_) => {} + } + } + } + } + _ => {} + } + + if item.vis == public && privacy_context == PublicContext { + visit::visit_item(item, (PublicContext, visitor)) + } else { + visit::visit_item(item, (PrivateContext, visitor)) + } + }, + .. *visit::default_visitor() + }); + + visit::visit_crate(crate, (PublicContext, visitor)) + } + + // Returns true if the given def ID represents a local item that is + // eligible for inlining and false otherwise. + fn def_id_represents_local_inlined_item(tcx: ty::ctxt, def_id: def_id) + -> bool { + if def_id.crate != local_crate { + return false + } + + let node_id = def_id.node; + match tcx.items.find(&node_id) { + Some(&ast_map::node_item(item, _)) => { + match item.node { + item_fn(*) => item_might_be_inlined(item), + _ => false, + } + } + Some(&ast_map::node_trait_method(trait_method, _, _)) => { + match *trait_method { + required(_) => false, + provided(_) => true, + } + } + Some(&ast_map::node_method(method, impl_did, _)) => { + if generics_require_inlining(&method.generics) || + attributes_specify_inlining(method.attrs) { + true + } else { + // Check the impl. If the generics on the self type of the + // impl require inlining, this method does too. + assert!(impl_did.crate == local_crate); + match tcx.items.find(&impl_did.node) { + Some(&ast_map::node_item(item, _)) => { + match item.node { + item_impl(ref generics, _, _, _) => { + generics_require_inlining(generics) + } + _ => false + } + } + Some(_) => { + tcx.sess.span_bug(method.span, + "method is not inside an \ + impl?!") + } + None => { + tcx.sess.span_bug(method.span, + "the impl that this method is \ + supposedly inside of doesn't \ + exist in the AST map?!") + } + } + } + } + Some(_) => false, + None => false // This will happen for default methods. + } + } + + // Helper function to set up a visitor for `propagate()` below. + fn init_visitor(&self) -> visit::vt<()> { + let (worklist, method_map) = (self.worklist, self.method_map); + let (tcx, reachable_symbols) = (self.tcx, self.reachable_symbols); + visit::mk_vt(@visit::Visitor { + visit_expr: |expr, (_, visitor)| { + match expr.node { + expr_path(_) => { + let def = match tcx.def_map.find(&expr.id) { + Some(&def) => def, + None => { + tcx.sess.span_bug(expr.span, + "def ID not in def map?!") + } + }; + + let def_id = def_id_of_def(def); + if ReachableContext:: + def_id_represents_local_inlined_item(tcx, + def_id) { + worklist.push(def_id.node) + } + reachable_symbols.insert(def_id.node); + } + expr_method_call(*) => { + match method_map.find(&expr.id) { + Some(&typeck::method_map_entry { + origin: typeck::method_static(def_id), + _ + }) => { + if ReachableContext:: + def_id_represents_local_inlined_item( + tcx, + def_id) { + worklist.push(def_id.node) + } + reachable_symbols.insert(def_id.node); + } + Some(_) => {} + None => { + tcx.sess.span_bug(expr.span, + "method call expression \ + not in method map?!") + } + } + } + _ => {} + } + + visit::visit_expr(expr, ((), visitor)) + }, + ..*visit::default_visitor() + }) + } + + // Step 2: Mark all symbols that the symbols on the worklist touch. + fn propagate(&self) { + let visitor = self.init_visitor(); + let mut scanned = HashSet::new(); + while self.worklist.len() > 0 { + let search_item = self.worklist.pop(); + if scanned.contains(&search_item) { + loop + } + scanned.insert(search_item); + self.reachable_symbols.insert(search_item); + + // Find the AST block corresponding to the item and visit it, + // marking all path expressions that resolve to something + // interesting. + match self.tcx.items.find(&search_item) { + Some(&ast_map::node_item(item, _)) => { + match item.node { + item_fn(_, _, _, _, ref search_block) => { + visit::visit_block(search_block, ((), visitor)) + } + _ => { + self.tcx.sess.span_bug(item.span, + "found non-function item \ + in worklist?!") + } + } + } + Some(&ast_map::node_trait_method(trait_method, _, _)) => { + match *trait_method { + required(ref ty_method) => { + self.tcx.sess.span_bug(ty_method.span, + "found required method in \ + worklist?!") + } + provided(ref method) => { + visit::visit_block(&method.body, ((), visitor)) + } + } + } + Some(&ast_map::node_method(ref method, _, _)) => { + visit::visit_block(&method.body, ((), visitor)) + } + Some(_) => { + let ident_interner = token::get_ident_interner(); + let desc = ast_map::node_id_to_str(self.tcx.items, + search_item, + ident_interner); + self.tcx.sess.bug(fmt!("found unexpected thingy in \ + worklist: %s", + desc)) + } + None => { + self.tcx.sess.bug(fmt!("found unmapped ID in worklist: \ + %d", + search_item)) + } + } + } + } + + // Step 3: Mark all destructors as reachable. + // + // XXX(pcwalton): This is a conservative overapproximation, but fixing + // this properly would result in the necessity of computing *type* + // reachability, which might result in a compile time loss. + fn mark_destructors_reachable(&self) { + for self.tcx.destructor_for_type.iter().advance + |(_, destructor_def_id)| { + if destructor_def_id.crate == local_crate { + self.reachable_symbols.insert(destructor_def_id.node); + } + } + } +} + +pub fn find_reachable(tcx: ty::ctxt, + method_map: typeck::method_map, + crate: @crate) + -> @mut HashSet<node_id> { + // XXX(pcwalton): We only need to mark symbols that are exported. But this + // is more complicated than just looking at whether the symbol is `pub`, + // because it might be the target of a `pub use` somewhere. For now, I + // think we are fine, because you can't `pub use` something that wasn't + // exported due to the bug whereby `use` only looks through public + // modules even if you're inside the module the `use` appears in. When + // this bug is fixed, however, this code will need to be updated. Probably + // the easiest way to fix this (although a conservative overapproximation) + // is to have the name resolution pass mark all targets of a `pub use` as + // "must be reachable". + + let reachable_context = ReachableContext::new(tcx, method_map); + + // Step 1: Mark all public symbols, and add all public symbols that might + // be inlined to a worklist. + reachable_context.mark_public_symbols(crate); + + // Step 2: Mark all symbols that the symbols on the worklist touch. + reachable_context.propagate(); + + // Step 3: Mark all destructors as reachable. + reachable_context.mark_destructors_reachable(); + + // Return the set of reachable symbols. + reachable_context.reachable_symbols +} + diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index e06fd8f9717..b2bfd9d1661 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -652,19 +652,17 @@ impl NameBindings { match self.type_def { None => None, Some(ref type_def) => { - // FIXME (#3784): This is reallllly questionable. - // Perhaps the right thing to do is to merge def_mod - // and def_ty. match (*type_def).type_def { Some(type_def) => Some(type_def), None => { - match (*type_def).module_def { - Some(module_def) => { - let module_def = &mut *module_def; - module_def.def_id.map(|def_id| - def_mod(*def_id)) + match type_def.module_def { + Some(module) => { + match module.def_id { + Some(did) => Some(def_mod(did)), + None => None, + } } - None => None + None => None, } } } @@ -1230,49 +1228,29 @@ impl Resolver { visit_item(item, (new_parent, visitor)); } - item_impl(_, trait_ref_opt, ty, ref methods) => { - // If this implements an anonymous trait and it has static - // methods, then add all the static methods within to a new - // module, if the type was defined within this module. + item_impl(_, None, ty, ref methods) => { + // If this implements an anonymous trait, then add all the + // methods within to a new module, if the type was defined + // within this module. // // FIXME (#3785): This is quite unsatisfactory. Perhaps we // should modify anonymous traits to only be implementable in // the same module that declared the type. - // Bail out early if there are no static methods. - let mut methods_seen = HashMap::new(); - let mut has_static_methods = false; - for methods.iter().advance |method| { - match method.explicit_self.node { - sty_static => has_static_methods = true, - _ => { - // Make sure you can't define duplicate methods - let ident = method.ident; - let span = method.span; - let old_sp = methods_seen.find_or_insert(ident, span); - if *old_sp != span { - self.session.span_err(span, - fmt!("duplicate definition of method `%s`", - self.session.str_of(ident))); - self.session.span_note(*old_sp, - fmt!("first definition of method `%s` here", - self.session.str_of(ident))); - } - } - } - } - - // If there are static methods, then create the module - // and add them. - match (trait_ref_opt, ty) { - (None, @Ty { node: ty_path(path, _, _), _ }) if - has_static_methods && path.idents.len() == 1 => { + // Create the module and add all methods. + match *ty { + Ty { + node: ty_path(path, _, _), + _ + } if path.idents.len() == 1 => { let name = path_to_ident(path); let new_parent = match parent.children.find(&name) { // It already exists - Some(&child) if child.get_module_if_available().is_some() && - child.get_module().kind == ImplModuleKind => { + Some(&child) if child.get_module_if_available() + .is_some() && + child.get_module().kind == + ImplModuleKind => { ModuleReducedGraphParent(child.get_module()) } // Create the module @@ -1283,8 +1261,8 @@ impl Resolver { ForbidDuplicateModules, sp); - let parent_link = self.get_parent_link(new_parent, - ident); + let parent_link = + self.get_parent_link(new_parent, ident); let def_id = local_def(item.id); name_bindings.define_module(Public, parent_link, @@ -1292,30 +1270,36 @@ impl Resolver { ImplModuleKind, sp); - ModuleReducedGraphParent(name_bindings.get_module()) + ModuleReducedGraphParent( + name_bindings.get_module()) } }; - // For each static method... + // For each method... for methods.iter().advance |method| { - match method.explicit_self.node { + // Add the method to the module. + let ident = method.ident; + let (method_name_bindings, _) = + self.add_child(ident, + new_parent, + ForbidDuplicateValues, + method.span); + let def = match method.explicit_self.node { sty_static => { - // Add the static method to the - // module. - let ident = method.ident; - let (method_name_bindings, _) = - self.add_child( - ident, - new_parent, - ForbidDuplicateValues, - method.span); - let def = def_fn(local_def(method.id), - method.purity); - method_name_bindings.define_value( - Public, def, method.span); + // Static methods become `def_fn`s. + def_fn(local_def(method.id), + method.purity) } - _ => {} - } + _ => { + // Non-static methods become + // `def_method`s. + def_method(local_def(method.id), None) + } + }; + + method_name_bindings.define_value(Public, + def, + method.span); } } _ => {} @@ -1324,41 +1308,23 @@ impl Resolver { visit_item(item, (parent, visitor)); } + item_impl(_, Some(_), ty, ref methods) => { + visit_item(item, (parent, visitor)); + } + item_trait(_, _, ref methods) => { let (name_bindings, new_parent) = self.add_child(ident, parent, ForbidDuplicateTypes, sp); - // If the trait has static methods, then add all the static - // methods within to a new module. - // - // We only need to create the module if the trait has static - // methods, so check that first. - let mut has_static_methods = false; - for (*methods).iter().advance |method| { - let ty_m = trait_method_to_ty_method(method); - match ty_m.explicit_self.node { - sty_static => { - has_static_methods = true; - break; - } - _ => {} - } - } - - // Create the module if necessary. - let module_parent_opt; - if has_static_methods { - let parent_link = self.get_parent_link(parent, ident); - name_bindings.define_module(privacy, - parent_link, - Some(local_def(item.id)), - TraitModuleKind, - sp); - module_parent_opt = Some(ModuleReducedGraphParent( - name_bindings.get_module())); - } else { - module_parent_opt = None; - } + // Add all the methods within to a new module. + let parent_link = self.get_parent_link(parent, ident); + name_bindings.define_module(privacy, + parent_link, + Some(local_def(item.id)), + TraitModuleKind, + sp); + let module_parent = ModuleReducedGraphParent(name_bindings. + get_module()); // Add the names of all the methods to the trait info. let mut method_names = HashMap::new(); @@ -1366,35 +1332,34 @@ impl Resolver { let ty_m = trait_method_to_ty_method(method); let ident = ty_m.ident; - // Add it to the trait info if not static, - // add it as a name in the trait module otherwise. - match ty_m.explicit_self.node { - sty_static => { - let def = def_static_method( - local_def(ty_m.id), - Some(local_def(item.id)), - ty_m.purity); - let (method_name_bindings, _) = - self.add_child(ident, - module_parent_opt.get(), - ForbidDuplicateValues, - ty_m.span); - method_name_bindings.define_value(Public, - def, - ty_m.span); + // Add it as a name in the trait module. + let def = match ty_m.explicit_self.node { + sty_static => { + // Static methods become `def_static_method`s. + def_static_method(local_def(ty_m.id), + Some(local_def(item.id)), + ty_m.purity) } _ => { - // Make sure you can't define duplicate methods - let old_sp = method_names.find_or_insert(ident, ty_m.span); - if *old_sp != ty_m.span { - self.session.span_err(ty_m.span, - fmt!("duplicate definition of method `%s`", - self.session.str_of(ident))); - self.session.span_note(*old_sp, - fmt!("first definition of method `%s` here", - self.session.str_of(ident))); - } + // Non-static methods become `def_method`s. + def_method(local_def(ty_m.id), + Some(local_def(item.id))) + } + }; + + let (method_name_bindings, _) = + self.add_child(ident, + module_parent, + ForbidDuplicateValues, + ty_m.span); + method_name_bindings.define_value(Public, def, ty_m.span); + + // Add it to the trait info if not static. + match ty_m.explicit_self.node { + sty_static => {} + _ => { + method_names.insert(ident, ()); } } } @@ -1751,6 +1716,9 @@ impl Resolver { child_name_bindings.define_type(privacy, def, dummy_sp()); self.structs.insert(def_id); } + def_method(*) => { + // Ignored; handled elsewhere. + } def_self(*) | def_arg(*) | def_local(*) | def_prim_ty(*) | def_ty_param(*) | def_binding(*) | def_use(*) | def_upvar(*) | def_region(*) | @@ -2091,8 +2059,12 @@ impl Resolver { let mut first = true; let mut result = ~""; for idents.iter().advance |ident| { - if first { first = false; } else { result += "::" }; - result += self.session.str_of(*ident); + if first { + first = false + } else { + result.push_str("::") + } + result.push_str(self.session.str_of(*ident)); }; return result; } @@ -2387,7 +2359,8 @@ impl Resolver { } match type_result { BoundResult(target_module, name_bindings) => { - debug!("(resolving single import) found type target"); + debug!("(resolving single import) found type target: %?", + name_bindings.type_def.get().type_def); import_resolution.type_target = Some(Target(target_module, name_bindings)); import_resolution.type_id = directive.id; @@ -3186,12 +3159,14 @@ impl Resolver { Some(def_id) if def_id.crate == local_crate => { // OK. Continue. debug!("(recording exports for module subtree) recording \ - exports for local module"); + exports for local module `%s`", + self.module_to_str(module_)); } None => { // Record exports for the root module. debug!("(recording exports for module subtree) recording \ - exports for root module"); + exports for root module `%s`", + self.module_to_str(module_)); } Some(_) => { // Bail out. @@ -3265,22 +3240,8 @@ impl Resolver { pub fn add_exports_for_module(@mut self, exports2: &mut ~[Export2], module_: @mut Module) { - for module_.children.iter().advance |(ident, namebindings)| { - debug!("(computing exports) maybe export '%s'", - self.session.str_of(*ident)); - self.add_exports_of_namebindings(&mut *exports2, - *ident, - *namebindings, - TypeNS, - false); - self.add_exports_of_namebindings(&mut *exports2, - *ident, - *namebindings, - ValueNS, - false); - } - - for module_.import_resolutions.iter().advance |(ident, importresolution)| { + for module_.import_resolutions.iter().advance |(ident, + importresolution)| { if importresolution.privacy != Public { debug!("(computing exports) not reexporting private `%s`", self.session.str_of(*ident)); @@ -4514,8 +4475,8 @@ impl Resolver { if path.global { return self.resolve_crate_relative_path(path, - self.xray_context, - namespace); + self.xray_context, + namespace); } if path.idents.len() > 1 { @@ -4862,8 +4823,8 @@ impl Resolver { while j != 0 { j -= 1; for this.value_ribs[j].bindings.each_key |&k| { - vec::push(&mut maybes, this.session.str_of(k)); - vec::push(&mut values, uint::max_value); + maybes.push(this.session.str_of(k)); + values.push(uint::max_value); } } @@ -4882,7 +4843,7 @@ impl Resolver { values[smallest] <= max_distance && name != maybes[smallest] { - Some(vec::swap_remove(&mut maybes, smallest)) + Some(maybes.swap_remove(smallest)) } else { None @@ -4943,6 +4904,22 @@ impl Resolver { // Write the result into the def map. debug!("(resolving expr) resolved `%s`", self.idents_to_str(path.idents)); + + // First-class methods are not supported yet; error + // out here. + match def { + def_method(*) => { + self.session.span_err(expr.span, + "first-class methods \ + are not supported"); + self.session.span_note(expr.span, + "call the method \ + using the `.` \ + syntax"); + } + _ => {} + } + self.record_def(expr.id, def); } None => { @@ -5072,6 +5049,9 @@ impl Resolver { self.trait_map.insert(expr.id, @mut traits); } expr_method_call(_, _, ident, _, _, _) => { + debug!("(recording candidate traits for expr) recording \ + traits for %d", + expr.id); let traits = self.search_for_traits_containing_method(ident); self.trait_map.insert(expr.id, @mut traits); } @@ -5147,7 +5127,6 @@ impl Resolver { debug!("(searching for traits containing method) looking for '%s'", self.session.str_of(name)); - let mut found_traits = ~[]; let mut search_module = self.current_module; match self.method_map.find(&name) { @@ -5411,7 +5390,7 @@ pub fn resolve_crate(session: Session, -> CrateMap { let resolver = @mut Resolver(session, lang_items, crate); resolver.resolve(); - let Resolver{def_map, export_map2, trait_map, _} = copy *resolver; + let Resolver { def_map, export_map2, trait_map, _ } = copy *resolver; CrateMap { def_map: def_map, exp_map2: export_map2, diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index a2cbc4d6fe0..c2e9c7b194b 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -388,9 +388,9 @@ pub fn expand_nested_bindings<'r>(bcx: block, match br.pats[col].node { ast::pat_ident(_, path, Some(inner)) => { let pats = vec::append( - vec::slice(br.pats, 0u, col).to_owned(), + br.pats.slice(0u, col).to_owned(), vec::append(~[inner], - vec::slice(br.pats, col + 1u, + br.pats.slice(col + 1u, br.pats.len()))); let binding_info = @@ -437,8 +437,8 @@ pub fn enter_match<'r>(bcx: block, Some(sub) => { let pats = vec::append( - vec::append(sub, vec::slice(br.pats, 0u, col)), - vec::slice(br.pats, col + 1u, br.pats.len())); + vec::append(sub, br.pats.slice(0u, col)), + br.pats.slice(col + 1u, br.pats.len())); let this = br.pats[col]; match this.node { @@ -1290,7 +1290,7 @@ pub fn compile_submatch(bcx: block, match data.arm.guard { Some(guard_expr) => { bcx = compile_guard(bcx, guard_expr, m[0].data, - vec::slice(m, 1, m.len()), + m.slice(1, m.len()), vals, chk); } _ => () @@ -1309,8 +1309,8 @@ pub fn compile_submatch(bcx: block, } }; - let vals_left = vec::append(vec::slice(vals, 0u, col).to_owned(), - vec::slice(vals, col + 1u, vals.len())); + let vals_left = vec::append(vals.slice(0u, col).to_owned(), + vals.slice(col + 1u, vals.len())); let ccx = bcx.fcx.ccx; let mut pat_id = 0; let mut pat_span = dummy_sp(); diff --git a/src/librustc/middle/trans/asm.rs b/src/librustc/middle/trans/asm.rs index 3c263b1c01e..a1d1b737f31 100644 --- a/src/librustc/middle/trans/asm.rs +++ b/src/librustc/middle/trans/asm.rs @@ -41,6 +41,7 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block { callee::trans_arg_expr(bcx, expr_ty(bcx, out), ty::ByCopy, + ast::sty_static, out, &mut cleanups, None, @@ -56,6 +57,7 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block { callee::trans_arg_expr(bcx, expr_ty(bcx, e), ty::ByCopy, + ast::sty_static, e, &mut cleanups, None, @@ -77,6 +79,7 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block { callee::trans_arg_expr(bcx, expr_ty(bcx, in), ty::ByCopy, + ast::sty_static, in, &mut cleanups, None, @@ -95,15 +98,15 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block { if !ia.clobbers.is_empty() && !clobbers.is_empty() { clobbers = fmt!("%s,%s", ia.clobbers, clobbers); } else { - clobbers += ia.clobbers; + clobbers.push_str(ia.clobbers); }; // Add the clobbers to our constraints list - if !clobbers.is_empty() && !constraints.is_empty() { - constraints += ","; - constraints += clobbers; + if clobbers.len() != 0 && constraints.len() != 0 { + constraints.push_char(','); + constraints.push_str(clobbers); } else { - constraints += clobbers; + constraints.push_str(clobbers); } debug!("Asm Constraints: %?", constraints); diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index a0628bc8e87..d9fea121346 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -54,7 +54,6 @@ use middle::trans::machine; use middle::trans::machine::{llalign_of_min, llsize_of}; use middle::trans::meth; use middle::trans::monomorphize; -use middle::trans::reachable; use middle::trans::tvec; use middle::trans::type_of; use middle::trans::type_of::*; @@ -65,7 +64,7 @@ use util::ppaux::{Repr, ty_to_str}; use middle::trans::type_::Type; use core::hash; -use core::hashmap::{HashMap}; +use core::hashmap::{HashMap, HashSet}; use core::int; use core::io; use core::libc::c_uint; @@ -462,6 +461,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext, &tsubsts, None, None, + None, None); val @@ -674,7 +674,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, int::to_str(variant.disr_val)); let variant_cx = iter_variant(variant_cx, repr, av, *variant, - substs.tps, f); + substs.tps, |x,y,z| f(x,y,z)); match adt::trans_case(cx, repr, variant.disr_val) { _match::single_result(r) => { AddCase(llswitch, r.val, variant_cx.llbb) @@ -1129,15 +1129,10 @@ pub fn new_block(cx: fn_ctxt, parent: Option<block>, kind: block_kind, is_lpad: bool, name: &str, opt_node_info: Option<NodeInfo>) -> block { - let s = if cx.ccx.sess.opts.save_temps || cx.ccx.sess.opts.debuginfo { - (cx.ccx.names)(name) - } else { - special_idents::invalid - }; unsafe { - let llbb = str::as_c_str(cx.ccx.sess.str_of(s), |buf| { + let llbb = do name.as_c_str |buf| { llvm::LLVMAppendBasicBlockInContext(cx.ccx.llcx, cx.llfn, buf) - }); + }; let bcx = mk_block(llbb, parent, kind, @@ -1145,8 +1140,11 @@ pub fn new_block(cx: fn_ctxt, parent: Option<block>, kind: block_kind, opt_node_info, cx); for parent.iter().advance |cx| { - if cx.unreachable { Unreachable(bcx); } - }; + if cx.unreachable { + Unreachable(bcx); + break; + } + } bcx } } @@ -1547,17 +1545,15 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, llfndecl: ValueRef, id: ast::node_id, output_type: ty::t, - impl_id: Option<ast::def_id>, param_substs: Option<@param_substs>, sp: Option<span>) -> fn_ctxt { for param_substs.iter().advance |p| { p.validate(); } - debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \ + debug!("new_fn_ctxt_w_id(path=%s, id=%?, \ param_substs=%s)", path_str(ccx.sess, path), id, - impl_id, param_substs.repr(ccx.tcx)); let llbbs = mk_standard_basic_blocks(llfndecl); @@ -1586,7 +1582,6 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, lllocals: @mut HashMap::new(), llupvars: @mut HashMap::new(), id: id, - impl_id: impl_id, param_substs: param_substs, span: sp, path: path, @@ -1607,7 +1602,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext, output_type: ty::t, sp: Option<span>) -> fn_ctxt { - new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, None, sp) + new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, sp) } // NB: must keep 4 fns in sync: @@ -1680,23 +1675,15 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, let mut bcx = bcx; match fcx.llself { - Some(slf) => { - let self_val = if slf.is_owned - && datum::appropriate_mode(slf.t).is_by_value() { - let tmp = BitCast(bcx, slf.v, type_of(bcx.ccx(), slf.t)); - let alloc = alloc_ty(bcx, slf.t); - Store(bcx, tmp, alloc); - alloc - } else { - PointerCast(bcx, slf.v, type_of(bcx.ccx(), slf.t).ptr_to()) - }; - - fcx.llself = Some(ValSelfData {v: self_val, ..slf}); - if slf.is_owned { - add_clean(bcx, self_val, slf.t); - } - } - _ => {} + Some(slf) => { + let self_val = PointerCast(bcx, slf.v, type_of(bcx.ccx(), slf.t).ptr_to()); + fcx.llself = Some(ValSelfData {v: self_val, ..slf}); + + if slf.is_owned { + add_clean(bcx, slf.v, slf.t); + } + } + _ => {} } for uint::range(0, arg_tys.len()) |arg_n| { @@ -1784,7 +1771,6 @@ pub fn trans_closure(ccx: @mut CrateContext, self_arg: self_arg, param_substs: Option<@param_substs>, id: ast::node_id, - impl_id: Option<ast::def_id>, attributes: &[ast::attribute], output_type: ty::t, maybe_load_env: &fn(fn_ctxt), @@ -1802,7 +1788,6 @@ pub fn trans_closure(ccx: @mut CrateContext, llfndecl, id, output_type, - impl_id, param_substs, Some(body.span)); let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs); @@ -1861,7 +1846,6 @@ pub fn trans_fn(ccx: @mut CrateContext, self_arg: self_arg, param_substs: Option<@param_substs>, id: ast::node_id, - impl_id: Option<ast::def_id>, attrs: &[ast::attribute]) { let do_time = ccx.sess.trans_stats(); let start = if do_time { time::get_time() } @@ -1881,7 +1865,6 @@ pub fn trans_fn(ccx: @mut CrateContext, self_arg, param_substs, id, - impl_id, attrs, output_type, |fcx| { @@ -1931,7 +1914,6 @@ pub fn trans_enum_variant(ccx: @mut CrateContext, llfndecl, variant.node.id, enum_ty, - None, param_substs, None); @@ -2011,7 +1993,6 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, llfndecl, ctor_id, tup_ty, - None, param_substs, None); @@ -2091,7 +2072,6 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) { no_self, None, item.id, - None, item.attrs); } else { for body.node.stmts.iter().advance |stmt| { @@ -2447,7 +2427,6 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef { } } ast_map::node_method(m, _, pth) => { - exprt = true; register_method(ccx, id, pth, m) } ast_map::node_foreign_item(ni, _, _, pth) => { @@ -2521,7 +2500,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef { variant)) } }; - if !(exprt || ccx.reachable.contains(&id)) { + if !exprt && !ccx.reachable.contains(&id) { lib::llvm::SetLinkage(val, lib::llvm::InternalLinkage); } ccx.item_vals.insert(id, val); @@ -2532,12 +2511,15 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef { pub fn register_method(ccx: @mut CrateContext, id: ast::node_id, - pth: @ast_map::path, + path: @ast_map::path, m: @ast::method) -> ValueRef { let mty = ty::node_id_to_type(ccx.tcx, id); - let pth = vec::append(/*bad*/copy *pth, [path_name((ccx.names)("meth")), - path_name(m.ident)]); - let llfn = register_fn_full(ccx, m.span, pth, id, m.attrs, mty); + + let mut path = /*bad*/ copy *path; + path.push(path_name(gensym_name("meth"))); + path.push(path_name(m.ident)); + + let llfn = register_fn_full(ccx, m.span, path, id, m.attrs, mty); set_inline_hint_if_appr(m.attrs, llfn); llfn } @@ -2825,13 +2807,13 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::encode_ encoder::EncodeParams { diag: diag, tcx: cx.tcx, - reachable: cx.reachable, reexports2: cx.exp_map2, item_symbols: item_symbols, discrim_symbols: discrim_symbols, link_meta: link_meta, cstore: cx.sess.cstore, - encode_inlined_item: ie + encode_inlined_item: ie, + reachable: cx.reachable, } } @@ -2897,16 +2879,12 @@ pub fn trans_crate(sess: session::Session, tcx: ty::ctxt, output: &Path, emap2: resolve::ExportMap2, - maps: astencode::Maps) -> (ContextRef, ModuleRef, LinkMeta) { + reachable_map: @mut HashSet<ast::node_id>, + maps: astencode::Maps) + -> (ContextRef, ModuleRef, LinkMeta) { let mut symbol_hasher = hash::default_state(); let link_meta = link::build_link_meta(sess, crate, output, &mut symbol_hasher); - let reachable = reachable::find_reachable( - &crate.node.module, - emap2, - tcx, - maps.method_map - ); // Append ".rc" to crate name as LLVM module identifier. // @@ -2924,8 +2902,15 @@ pub fn trans_crate(sess: session::Session, // sess.bug("couldn't enable multi-threaded LLVM"); // } - let ccx = @mut CrateContext::new(sess, llmod_id, tcx, emap2, maps, - symbol_hasher, link_meta, reachable); + let ccx = @mut CrateContext::new(sess, + llmod_id, + tcx, + emap2, + maps, + symbol_hasher, + link_meta, + reachable_map); + { let _icx = push_ctxt("data"); trans_constants(ccx, crate); diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index 83c1a3c80db..dc32a3b4e2c 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -68,13 +68,13 @@ pub fn count_insn(cx: block, category: &str) { i = 0u; while i < len { i = *mm.get(&v[i]); - s += "/"; - s += v[i]; + s.push_char('/'); + s.push_str(v[i]); i += 1u; } - s += "/"; - s += category; + s.push_char('/'); + s.push_str(category); let n = match h.find(&s) { Some(&n) => n, @@ -610,12 +610,21 @@ pub fn GEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef { // Simple wrapper around GEP that takes an array of ints and wraps them // in C_i32() -// -// FIXME #6571: Use a small-vector optimization to avoid allocations here. +#[inline] pub fn GEPi(cx: block, base: ValueRef, ixs: &[uint]) -> ValueRef { - let v = do vec::map(ixs) |i| { C_i32(*i as i32) }; - count_insn(cx, "gepi"); - return InBoundsGEP(cx, base, v); + // Small vector optimization. This should catch 100% of the cases that + // we care about. + if ixs.len() < 16 { + let mut small_vec = [ C_i32(0), ..16 ]; + for ixs.iter().enumerate().advance |(i, &ix)| { + small_vec[i] = C_i32(ix as i32) + } + InBoundsGEP(cx, base, small_vec.slice(0, ixs.len())) + } else { + let v = do vec::map(ixs) |i| { C_i32(*i as i32) }; + count_insn(cx, "gepi"); + InBoundsGEP(cx, base, v) + } } pub fn InBoundsGEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef { diff --git a/src/librustc/middle/trans/cabi_arm.rs b/src/librustc/middle/trans/cabi_arm.rs index ac51c7efc6f..45fdda1990c 100644 --- a/src/librustc/middle/trans/cabi_arm.rs +++ b/src/librustc/middle/trans/cabi_arm.rs @@ -139,12 +139,14 @@ impl ABIInfo for ARM_ABIInfo { attrs.push(attr); } - let mut (ret_ty, ret_attr) = if ret_def { + let (ret_ty, ret_attr) = if ret_def { classify_ret_ty(rty) } else { (LLVMType { cast: false, ty: Type::void() }, None) }; + let mut ret_ty = ret_ty; + let sret = ret_attr.is_some(); if sret { arg_tys.unshift(ret_ty); diff --git a/src/librustc/middle/trans/cabi_mips.rs b/src/librustc/middle/trans/cabi_mips.rs index 8604ae37f77..47f2fb8634c 100644 --- a/src/librustc/middle/trans/cabi_mips.rs +++ b/src/librustc/middle/trans/cabi_mips.rs @@ -178,12 +178,14 @@ impl ABIInfo for MIPS_ABIInfo { atys: &[Type], rty: Type, ret_def: bool) -> FnType { - let mut (ret_ty, ret_attr) = if ret_def { + let (ret_ty, ret_attr) = if ret_def { classify_ret_ty(rty) } else { (LLVMType { cast: false, ty: Type::void() }, None) }; + let mut ret_ty = ret_ty; + let sret = ret_attr.is_some(); let mut arg_tys = ~[]; let mut attrs = ~[]; diff --git a/src/librustc/middle/trans/cabi_x86_64.rs b/src/librustc/middle/trans/cabi_x86_64.rs index 14ab17f5030..6c264e637a6 100644 --- a/src/librustc/middle/trans/cabi_x86_64.rs +++ b/src/librustc/middle/trans/cabi_x86_64.rs @@ -39,7 +39,11 @@ enum RegClass { Memory } -impl Type { +trait TypeMethods { + fn is_reg_ty(&self) -> bool; +} + +impl TypeMethods for Type { fn is_reg_ty(&self) -> bool { match self.kind() { Integer | Pointer | Float | Double => true, @@ -312,7 +316,7 @@ fn llreg_ty(cls: &[RegClass]) -> Type { tys.push(Type::i64()); } SSEFv => { - let vec_len = llvec_len(vec::tailn(cls, i + 1u)) * 2u; + let vec_len = llvec_len(cls.tailn(i + 1u)) * 2u; let vec_ty = Type::vector(&Type::f32(), vec_len as u64); tys.push(vec_ty); i += vec_len; @@ -360,8 +364,9 @@ fn x86_64_tys(atys: &[Type], arg_tys.push(ty); attrs.push(attr); } - let mut (ret_ty, ret_attr) = x86_64_ty(rty, |cls| cls.is_ret_bysret(), + let (ret_ty, ret_attr) = x86_64_ty(rty, |cls| cls.is_ret_bysret(), StructRetAttribute); + let mut ret_ty = ret_ty; let sret = ret_attr.is_some(); if sret { arg_tys = vec::append(~[ret_ty], arg_tys); diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index cb475550638..4c07f88f16e 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -17,6 +17,7 @@ // closure. use core::prelude::*; +use core::vec; use back::abi; use driver::session; @@ -47,7 +48,6 @@ use util::ppaux::Repr; use middle::trans::type_::Type; -use core::vec; use syntax::ast; use syntax::ast_map; use syntax::visit; @@ -64,6 +64,7 @@ pub struct MethodData { llself: ValueRef, self_ty: ty::t, self_mode: ty::SelfMode, + explicit_self: ast::explicit_self_ } pub enum CalleeData { @@ -146,7 +147,7 @@ pub fn trans(bcx: block, expr: @ast::expr) -> Callee { ast::def_static(*) | ast::def_ty(*) | ast::def_prim_ty(*) | ast::def_use(*) | ast::def_typaram_binder(*) | ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) | - ast::def_self_ty(*) => { + ast::def_self_ty(*) | ast::def_method(*) => { bcx.tcx().sess.span_bug( ref_expr.span, fmt!("Cannot translate def %? \ @@ -194,6 +195,58 @@ pub fn trans_fn_ref_with_vtables_to_callee( type_params, vtables))} } +fn get_impl_resolutions(bcx: block, + impl_id: ast::def_id) + -> typeck::vtable_res { + if impl_id.crate == ast::local_crate { + *bcx.ccx().maps.vtable_map.get(&impl_id.node) + } else { + // XXX: This is a temporary hack to work around not properly + // exporting information about resolutions for impls. + // This doesn't actually work if the trait has param bounds, + // but it does allow us to survive the case when it does not. + let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get(); + @vec::from_elem(trait_ref.substs.tps.len(), @~[]) + } +} + +fn resolve_default_method_vtables(bcx: block, + impl_id: ast::def_id, + method: &ty::Method, + substs: &ty::substs, + impl_vtables: Option<typeck::vtable_res>) + -> typeck::vtable_res { + + // Get the vtables that the impl implements the trait at + let trait_vtables = get_impl_resolutions(bcx, impl_id); + + // Build up a param_substs that we are going to resolve the + // trait_vtables under. + let param_substs = Some(@param_substs { + tys: copy substs.tps, + self_ty: substs.self_ty, + vtables: impl_vtables, + self_vtable: None + }); + + let trait_vtables_fixed = resolve_vtables_under_param_substs( + bcx.tcx(), param_substs, trait_vtables); + + // Now we pull any vtables for parameters on the actual method. + let num_method_vtables = method.generics.type_param_defs.len(); + let method_vtables = match impl_vtables { + Some(vtables) => { + let num_impl_type_parameters = + vtables.len() - num_method_vtables; + vtables.tailn(num_impl_type_parameters).to_owned() + }, + None => vec::from_elem(num_method_vtables, @~[]) + }; + + @(*trait_vtables_fixed + method_vtables) +} + + pub fn trans_fn_ref_with_vtables( bcx: block, // def_id: ast::def_id, // def id of fn @@ -233,15 +286,21 @@ pub fn trans_fn_ref_with_vtables( // Polytype of the function item (may have type params) let fn_tpt = ty::lookup_item_type(tcx, def_id); - let substs = ty::substs { self_r: None, self_ty: None, + // For simplicity, we want to use the Subst trait when composing + // substitutions for default methods. The subst trait does + // substitutions with regions, though, so we put a dummy self + // region parameter in to keep it from failing. This is a hack. + let substs = ty::substs { self_r: Some(ty::re_empty), + self_ty: None, tps: /*bad*/ type_params.to_owned() }; // We need to do a bunch of special handling for default methods. // We need to modify the def_id and our substs in order to monomorphize // the function. - let (def_id, opt_impl_did, substs) = match tcx.provided_method_sources.find(&def_id) { - None => (def_id, None, substs), + let (def_id, opt_impl_did, substs, self_vtable, vtables) = + match tcx.provided_method_sources.find(&def_id) { + None => (def_id, None, substs, None, vtables), Some(source) => { // There are two relevant substitutions when compiling // default methods. First, there is the substitution for @@ -261,20 +320,42 @@ pub fn trans_fn_ref_with_vtables( default methods"); let method = ty::method(tcx, source.method_id); + // Get all of the type params for the receiver + let param_defs = method.generics.type_param_defs; + let receiver_substs = + type_params.initn(param_defs.len()).to_owned(); + let receiver_vtables = match vtables { + None => @~[], + Some(call_vtables) => { + @call_vtables.initn(param_defs.len()).to_owned() + } + }; + + let self_vtable = + typeck::vtable_static(source.impl_id, receiver_substs, + receiver_vtables); // Compute the first substitution let first_subst = make_substs_for_receiver_types( tcx, source.impl_id, trait_ref, method); // And compose them let new_substs = first_subst.subst(tcx, &substs); + + + let vtables = + resolve_default_method_vtables(bcx, source.impl_id, + method, &new_substs, vtables); + debug!("trans_fn_with_vtables - default method: \ substs = %s, trait_subst = %s, \ - first_subst = %s, new_subst = %s", + first_subst = %s, new_subst = %s, \ + self_vtable = %s, vtables = %s", substs.repr(tcx), trait_ref.substs.repr(tcx), - first_subst.repr(tcx), new_substs.repr(tcx)); + first_subst.repr(tcx), new_substs.repr(tcx), + self_vtable.repr(tcx), vtables.repr(tcx)); - - (source.method_id, Some(source.impl_id), new_substs) + (source.method_id, Some(source.impl_id), + new_substs, Some(self_vtable), Some(vtables)) } }; @@ -319,9 +400,11 @@ pub fn trans_fn_ref_with_vtables( // Should be either intra-crate or inlined. assert_eq!(def_id.crate, ast::local_crate); - let mut (val, must_cast) = + let (val, must_cast) = monomorphize::monomorphic_fn(ccx, def_id, &substs, - vtables, opt_impl_did, Some(ref_id)); + vtables, self_vtable, + opt_impl_did, Some(ref_id)); + let mut val = val; if must_cast && ref_id != 0 { // Monotype of the REFERENCE to the function (type params // are subst'd) @@ -503,7 +586,7 @@ pub fn trans_call_inner(in_cx: block, do base::with_scope(in_cx, call_info, "call") |cx| { let ret_in_loop = match args { ArgExprs(args) => { - args.len() > 0u && match vec::last(args).node { + args.len() > 0u && match args.last().node { ast::expr_loop_body(@ast::expr { node: ast::expr_fn_block(_, ref body), _ @@ -566,7 +649,8 @@ pub fn trans_call_inner(in_cx: block, // Now that the arguments have finished evaluating, we need to revoke // the cleanup for the self argument, if it exists match callee.data { - Method(d) if d.self_mode == ty::ByCopy => { + Method(d) if d.self_mode == ty::ByCopy || + d.explicit_self == ast::sty_value => { revoke_clean(bcx, d.llself); } _ => {} @@ -688,6 +772,7 @@ pub fn trans_args(cx: block, trans_arg_expr(bcx, arg_tys[i], ty::ByCopy, + ast::sty_static, *arg_expr, &mut temp_cleanups, if i == last { ret_flag } else { None }, @@ -721,6 +806,7 @@ pub enum AutorefArg { pub fn trans_arg_expr(bcx: block, formal_arg_ty: ty::t, self_mode: ty::SelfMode, + ex_self: ast::explicit_self_, arg_expr: @ast::expr, temp_cleanups: &mut ~[ValueRef], ret_flag: Option<ValueRef>, @@ -728,9 +814,10 @@ pub fn trans_arg_expr(bcx: block, let _icx = push_ctxt("trans_arg_expr"); let ccx = bcx.ccx(); - debug!("trans_arg_expr(formal_arg_ty=(%s), self_mode=%?, arg_expr=%s, \ + debug!("trans_arg_expr(formal_arg_ty=(%s), explicit_self=%? self_mode=%?, arg_expr=%s, \ ret_flag=%?)", formal_arg_ty.repr(bcx.tcx()), + ex_self, self_mode, arg_expr.repr(bcx.tcx()), ret_flag.map(|v| bcx.val_to_str(*v))); @@ -790,8 +877,26 @@ pub fn trans_arg_expr(bcx: block, val = arg_datum.to_ref_llval(bcx); } DontAutorefArg => { - match self_mode { - ty::ByRef => { + match (self_mode, ex_self) { + (ty::ByRef, ast::sty_value) => { + debug!("by value self with type %s, storing to scratch", + bcx.ty_to_str(arg_datum.ty)); + let scratch = scratch_datum(bcx, arg_datum.ty, false); + + arg_datum.store_to_datum(bcx, + arg_expr.id, + INIT, + scratch); + + // Technically, ownership of val passes to the callee. + // However, we must cleanup should we fail before the + // callee is actually invoked. + scratch.add_clean(bcx); + temp_cleanups.push(scratch.val); + + val = scratch.to_ref_llval(bcx); + } + (ty::ByRef, _) => { // This assertion should really be valid, but because // the explicit self code currently passes by-ref, it // does not hold. @@ -802,7 +907,7 @@ pub fn trans_arg_expr(bcx: block, bcx.ty_to_str(arg_datum.ty)); val = arg_datum.to_ref_llval(bcx); } - ty::ByCopy => { + (ty::ByCopy, _) => { if ty::type_needs_drop(bcx.tcx(), arg_datum.ty) || arg_datum.appropriate_mode().is_by_ref() { debug!("by copy arg with type %s, storing to scratch", diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 3ce52a63171..ad68ffb402e 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -444,7 +444,6 @@ pub fn trans_expr_fn(bcx: block, no_self, /*bad*/ copy bcx.fcx.param_substs, user_id, - None, [], real_return_type, |fcx| load_environment(fcx, cdata_ty, cap_vars, diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 79d83fbc857..b255f2ca78c 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -36,6 +36,8 @@ use core::cast; use core::hashmap::{HashMap}; use core::libc::{c_uint, c_longlong, c_ulonglong}; use core::to_bytes; +use core::str; +use core::vec::raw::to_ptr; use core::vec; use syntax::ast::ident; use syntax::ast_map::{path, path_elt}; @@ -45,14 +47,8 @@ use syntax::{ast, ast_map}; pub use middle::trans::context::CrateContext; -// NOTE: this thunk is totally pointless now that we're not passing -// interners around... -pub type namegen = @fn(s: &str) -> ident; -pub fn new_namegen() -> namegen { - let f: @fn(s: &str) -> ident = |prefix| { - token::str_to_ident(fmt!("%s_%u", prefix, token::gensym(prefix))) - }; - f +pub fn gensym_name(name: &str) -> ident { + token::str_to_ident(fmt!("%s_%u", name, token::gensym(name))) } pub struct tydesc_info { @@ -136,9 +132,9 @@ pub struct ValSelfData { // will only be set in the case of default methods. pub struct param_substs { tys: ~[ty::t], + self_ty: Option<ty::t>, vtables: Option<typeck::vtable_res>, - type_param_defs: @~[ty::TypeParameterDef], - self_ty: Option<ty::t> + self_vtable: Option<typeck::vtable_origin> } impl param_substs { @@ -149,10 +145,9 @@ impl param_substs { } fn param_substs_to_str(this: ¶m_substs, tcx: ty::ctxt) -> ~str { - fmt!("param_substs {tys:%s, vtables:%s, type_param_defs:%s}", + fmt!("param_substs {tys:%s, vtables:%s}", this.tys.repr(tcx), - this.vtables.repr(tcx), - this.type_param_defs.repr(tcx)) + this.vtables.repr(tcx)) } impl Repr for param_substs { @@ -229,9 +224,6 @@ pub struct fn_ctxt_ { // a user-defined function. id: ast::node_id, - // The def_id of the impl we're inside, or None if we aren't inside one. - impl_id: Option<ast::def_id>, - // If this function is being monomorphized, this contains the type // substitutions used. param_substs: Option<@param_substs>, @@ -418,10 +410,9 @@ pub fn revoke_clean(cx: block, val: ValueRef) { }); for cleanup_pos.iter().advance |i| { scope_info.cleanups = - vec::append(vec::slice(scope_info.cleanups, 0u, *i).to_owned(), - vec::slice(scope_info.cleanups, - *i + 1u, - scope_info.cleanups.len())); + vec::append(scope_info.cleanups.slice(0u, *i).to_owned(), + scope_info.cleanups.slice(*i + 1u, + scope_info.cleanups.len())); shrink_scope_clean(scope_info, *i); } } @@ -820,8 +811,9 @@ pub fn C_bytes(bytes: &[u8]) -> ValueRef { pub fn C_bytes_plus_null(bytes: &[u8]) -> ValueRef { unsafe { - let ptr = cast::transmute(vec::raw::to_ptr(bytes)); - return llvm::LLVMConstStringInContext(base::task_llcx(), ptr, bytes.len() as c_uint,False); + return llvm::LLVMConstStringInContext(base::task_llcx(), + cast::transmute(vec::raw::to_ptr(bytes)), + bytes.len() as c_uint, False); } } @@ -870,7 +862,7 @@ pub fn is_null(val: ValueRef) -> bool { } // Used to identify cached monomorphized functions and vtables -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub enum mono_param_id { mono_precise(ty::t, Option<@~[mono_id]>), mono_any, @@ -880,7 +872,7 @@ pub enum mono_param_id { datum::DatumMode), } -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub enum MonoDataClass { MonoBits, // Anything not treated differently from arbitrary integer data MonoNonNull, // Non-null pointers (used for optional-pointer optimization) @@ -905,7 +897,7 @@ pub fn mono_data_classify(t: ty::t) -> MonoDataClass { } -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct mono_id_ { def: ast::def_id, params: ~[mono_param_id], @@ -914,40 +906,6 @@ pub struct mono_id_ { pub type mono_id = @mono_id_; -impl to_bytes::IterBytes for mono_param_id { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - mono_precise(t, ref mids) => { - 0u8.iter_bytes(lsb0, f) && - ty::type_id(t).iter_bytes(lsb0, f) && - mids.iter_bytes(lsb0, f) - } - - mono_any => 1u8.iter_bytes(lsb0, f), - - mono_repr(ref a, ref b, ref c, ref d) => { - 2u8.iter_bytes(lsb0, f) && - a.iter_bytes(lsb0, f) && - b.iter_bytes(lsb0, f) && - c.iter_bytes(lsb0, f) && - d.iter_bytes(lsb0, f) - } - } - } -} - -impl to_bytes::IterBytes for MonoDataClass { - fn iter_bytes(&self, lsb0: bool, f:to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for mono_id_ { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.def.iter_bytes(lsb0, f) && self.params.iter_bytes(lsb0, f) - } -} - pub fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef { let cond = build::ICmp(cx, lib::llvm::IntULT, a, b); return build::Select(cx, cond, b, a); @@ -970,9 +928,12 @@ pub fn path_str(sess: session::Session, p: &[path_elt]) -> ~str { for p.iter().advance |e| { match *e { ast_map::path_name(s) | ast_map::path_mod(s) => { - if first { first = false; } - else { r += "::"; } - r += sess.str_of(s); + if first { + first = false + } else { + r.push_str("::") + } + r.push_str(sess.str_of(s)); } } } @@ -984,7 +945,11 @@ pub fn monomorphize_type(bcx: block, t: ty::t) -> ty::t { Some(substs) => { ty::subst_tps(bcx.tcx(), substs.tys, substs.self_ty, t) } - _ => { assert!(!ty::type_has_params(t)); t } + _ => { + assert!(!ty::type_has_params(t)); + assert!(!ty::type_has_self(t)); + t + } } } @@ -1033,17 +998,37 @@ pub fn node_vtables(bcx: block, id: ast::node_id) pub fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res) -> typeck::vtable_res { - @vec::map(*vts, |d| resolve_vtable_in_fn_ctxt(fcx, copy *d)) + resolve_vtables_under_param_substs(fcx.ccx.tcx, + fcx.param_substs, + vts) } +pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt, + param_substs: Option<@param_substs>, + vts: typeck::vtable_res) + -> typeck::vtable_res { + @vec::map(*vts, |ds| + @vec::map(**ds, |d| + resolve_vtable_under_param_substs(tcx, param_substs, copy *d))) +} + + // Apply the typaram substitutions in the fn_ctxt to a vtable. This should // eliminate any vtable_params. pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin) -> typeck::vtable_origin { - let tcx = fcx.ccx.tcx; + resolve_vtable_under_param_substs(fcx.ccx.tcx, + fcx.param_substs, + vt) +} + +pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt, + param_substs: Option<@param_substs>, + vt: typeck::vtable_origin) + -> typeck::vtable_origin { match vt { typeck::vtable_static(trait_id, tys, sub) => { - let tys = match fcx.param_substs { + let tys = match param_substs { Some(substs) => { do vec::map(tys) |t| { ty::subst_tps(tcx, substs.tys, substs.self_ty, *t) @@ -1051,11 +1036,12 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin) } _ => tys }; - typeck::vtable_static(trait_id, tys, - resolve_vtables_in_fn_ctxt(fcx, sub)) + typeck::vtable_static( + trait_id, tys, + resolve_vtables_under_param_substs(tcx, param_substs, sub)) } typeck::vtable_param(n_param, n_bound) => { - match fcx.param_substs { + match param_substs { Some(substs) => { find_vtable(tcx, substs, n_param, n_bound) } @@ -1066,6 +1052,19 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin) } } } + typeck::vtable_self(_trait_id) => { + match param_substs { + Some(@param_substs + {self_vtable: Some(ref self_vtable), _}) => { + copy *self_vtable + } + _ => { + tcx.sess.bug(fmt!( + "resolve_vtable_in_fn_ctxt: asked to lookup but \ + no self_vtable in the fn_ctxt!")) + } + } + } } } @@ -1075,13 +1074,7 @@ pub fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)", n_param, n_bound, ps.repr(tcx)); - // Vtables are stored in a flat array, finding the right one is - // somewhat awkward - let first_n_type_param_defs = ps.type_param_defs.slice(0, n_param); - let vtables_to_skip = - ty::count_traits_and_supertraits(tcx, first_n_type_param_defs); - let vtable_off = vtables_to_skip + n_bound; - /*bad*/ copy ps.vtables.get()[vtable_off] + /*bad*/ copy ps.vtables.get()[n_param][n_bound] } pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs { diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index a0ae579c865..9b81fc406b7 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -21,7 +21,6 @@ use middle::resolve; use middle::trans::adt; use middle::trans::base; use middle::trans::debuginfo; -use middle::trans::reachable; use middle::trans::type_use; use middle::ty; @@ -34,8 +33,7 @@ use core::local_data; use extra::time; use syntax::ast; -use middle::trans::common::{ExternMap,tydesc_info,BuilderRef_res,Stats,namegen}; -use middle::trans::common::{mono_id,new_namegen}; +use middle::trans::common::{mono_id,ExternMap,tydesc_info,BuilderRef_res,Stats}; use middle::trans::base::{decl_crate_map}; @@ -49,7 +47,7 @@ pub struct CrateContext { intrinsics: HashMap<&'static str, ValueRef>, item_vals: HashMap<ast::node_id, ValueRef>, exp_map2: resolve::ExportMap2, - reachable: reachable::map, + reachable: @mut HashSet<ast::node_id>, item_symbols: HashMap<ast::node_id, ~str>, link_meta: LinkMeta, enum_sizes: HashMap<ty::t, uint>, @@ -93,7 +91,6 @@ pub struct CrateContext { lltypes: HashMap<ty::t, Type>, llsizingtypes: HashMap<ty::t, Type>, adt_reprs: HashMap<ty::t, @adt::Repr>, - names: namegen, symbol_hasher: hash::State, type_hashcodes: HashMap<ty::t, @str>, type_short_names: HashMap<ty::t, ~str>, @@ -117,10 +114,15 @@ pub struct CrateContext { } impl CrateContext { - pub fn new(sess: session::Session, name: &str, tcx: ty::ctxt, - emap2: resolve::ExportMap2, maps: astencode::Maps, - symbol_hasher: hash::State, link_meta: LinkMeta, - reachable: reachable::map) -> CrateContext { + pub fn new(sess: session::Session, + name: &str, + tcx: ty::ctxt, + emap2: resolve::ExportMap2, + maps: astencode::Maps, + symbol_hasher: hash::State, + link_meta: LinkMeta, + reachable: @mut HashSet<ast::node_id>) + -> CrateContext { unsafe { let llcx = llvm::LLVMContextCreate(); set_task_llcx(llcx); @@ -194,7 +196,6 @@ impl CrateContext { lltypes: HashMap::new(), llsizingtypes: HashMap::new(), adt_reprs: HashMap::new(), - names: new_namegen(), symbol_hasher: symbol_hasher, type_hashcodes: HashMap::new(), type_short_names: HashMap::new(), diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index dae3d58d2be..22448f577a3 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -56,7 +56,7 @@ use util::ppaux::ty_to_str; use core::hashmap::HashMap; use core::libc; -use core::libc::c_uint; +use core::libc::{c_uint, c_ulonglong}; use core::cmp; use core::ptr; use core::str::as_c_str; @@ -64,6 +64,7 @@ use core::sys; use core::vec; use syntax::codemap::span; use syntax::{ast, codemap, ast_util, ast_map}; +use syntax::parse::token; static DW_LANG_RUST: int = 0x9000; @@ -86,7 +87,6 @@ static DW_ATE_unsigned_char: int = 0x08; /// A context object for maintaining all state needed by the debuginfo module. pub struct DebugContext { - names: namegen, crate_file: ~str, llcontext: ContextRef, builder: DIBuilderRef, @@ -104,7 +104,6 @@ impl DebugContext { // DIBuilder inherits context from the module, so we'd better use the same one let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; return DebugContext { - names: new_namegen(), crate_file: crate, llcontext: llcontext, builder: builder, @@ -211,9 +210,17 @@ pub fn create_arg(bcx: block, arg: ast::arg, span: span) -> Option<DIVariable> { let ident = path.idents.last(); let name: &str = cx.sess.str_of(*ident); let mdnode = do as_c_str(name) |name| { unsafe { - llvm::LLVMDIBuilderCreateLocalVariable(DIB(cx), - ArgVariableTag as u32, context, name, - filemd, loc.line as c_uint, tymd, false, 0, 0) + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), + ArgVariableTag as u32, + context, + name, + filemd, + loc.line as c_uint, + tymd, + false, + 0, + 0) // XXX need to pass in a real argument number }}; @@ -268,7 +275,8 @@ pub fn create_function(fcx: fn_ctxt) -> DISubprogram { ast_map::node_expr(expr) => { match expr.node { ast::expr_fn_block(ref decl, _) => { - ((dbg_cx(cx).names)("fn"), decl.output, expr.id) + let name = gensym_name("fn"); + (name, decl.output, expr.id) } _ => fcx.ccx.sess.span_bug(expr.span, "create_function: expected an expr_fn_block here") @@ -290,16 +298,17 @@ pub fn create_function(fcx: fn_ctxt) -> DISubprogram { let ret_ty_md = if cx.sess.opts.extra_debuginfo { match ret_ty.node { ast::ty_nil => ptr::null(), - _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id), - ret_ty.span) + _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id), ret_ty.span) } } else { ptr::null() }; let fn_ty = unsafe { - llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), - file_md, create_DIArray(DIB(cx), [ret_ty_md])) + llvm::LLVMDIBuilderCreateSubroutineType( + DIB(cx), + file_md, + create_DIArray(DIB(cx), [ret_ty_md])) }; let fn_md = @@ -308,13 +317,19 @@ pub fn create_function(fcx: fn_ctxt) -> DISubprogram { llvm::LLVMDIBuilderCreateFunction( DIB(cx), file_md, - name, linkage, - file_md, loc.line as c_uint, - fn_ty, false, true, + name, + linkage, + file_md, + loc.line as c_uint, + fn_ty, + false, + true, loc.line as c_uint, FlagPrototyped as c_uint, cx.sess.opts.optimize != session::No, - fcx.llfn, ptr::null(), ptr::null()) + fcx.llfn, + ptr::null(), + ptr::null()) }}}; dbg_cx(cx).created_functions.insert(id, fn_md); @@ -337,6 +352,9 @@ fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { fn create_compile_unit(cx: @mut CrateContext) { let dcx = dbg_cx(cx); let crate_name: &str = dcx.crate_file; + + debug!("create_compile_unit: %?", crate_name); + let work_dir = cx.sess.working_dir.to_str(); let producer = fmt!("rustc version %s", env!("CFG_VERSION")); @@ -352,7 +370,7 @@ fn create_compile_unit(cx: @mut CrateContext) { }}}}}}; } -fn create_file(cx: @mut CrateContext, full_path: &str) -> DIFile { +fn create_file(cx: &mut CrateContext, full_path: &str) -> DIFile { match dbg_cx(cx).created_files.find_equiv(&full_path) { Some(file_md) => return *file_md, None => () @@ -422,7 +440,7 @@ fn create_block(bcx: block) -> DILexicalBlock { -fn create_basic_type(cx: @mut CrateContext, t: ty::t, _span: span) -> DIType { +fn create_basic_type(cx: &mut CrateContext, t: ty::t, _span: span) -> DIType { let ty_id = ty::type_id(t); match dbg_cx(cx).created_types.find(&ty_id) { Some(ty_md) => return *ty_md, @@ -460,8 +478,11 @@ fn create_basic_type(cx: @mut CrateContext, t: ty::t, _span: span) -> DIType { let (size, align) = size_and_align_of(cx, t); let ty_md = do as_c_str(name) |name| { unsafe { llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), name, - size * 8 as u64, align * 8 as u64, encoding as c_uint) + DIB(cx), + name, + bytes_to_bits(size), + bytes_to_bits(align), + encoding as c_uint) }}; // One could think that this call is not necessary, as the create_ty() function will insert the @@ -471,12 +492,16 @@ fn create_basic_type(cx: @mut CrateContext, t: ty::t, _span: span) -> DIType { return ty_md; } -fn create_pointer_type(cx: @mut CrateContext, t: ty::t, _span: span, pointee: DIType) -> DIType { +fn create_pointer_type(cx: &mut CrateContext, t: ty::t, _span: span, pointee: DIType) -> DIType { let (size, align) = size_and_align_of(cx, t); let name = ty_to_str(cx.tcx, t); let ptr_md = do as_c_str(name) |name| { unsafe { - llvm::LLVMDIBuilderCreatePointerType(DIB(cx), - pointee, size * 8 as u64, align * 8 as u64, name) + llvm::LLVMDIBuilderCreatePointerType( + DIB(cx), + pointee, + bytes_to_bits(size), + bytes_to_bits(align), + name) }}; return ptr_md; } @@ -492,9 +517,9 @@ struct StructContext { } impl StructContext { - fn new(cx: &CrateContext, name: ~str, file: DIFile, line: uint) -> ~StructContext { + fn new(cx: &CrateContext, name: ~str, file: DIFile, line: uint) -> StructContext { debug!("StructContext::create: %s", name); - let scx = ~StructContext { + return StructContext { builder: DIB(cx), file: file, name: name, @@ -503,18 +528,26 @@ impl StructContext { total_size: 0, align: 1 }; - return scx; } fn add_member(&mut self, name: &str, line: uint, size: uint, align: uint, ty: DIType) { - debug!("StructContext(%s)::add_member: %s, size=%u, align=%u", - self.name, name, size, align); let offset = roundup(self.total_size, align); + + debug!("StructContext(%s)::add_member: %s, size=%u, align=%u, offset=%u", + self.name, name, size, align, offset); + let mem_t = do as_c_str(name) |name| { unsafe { llvm::LLVMDIBuilderCreateMemberType( - self.builder, ptr::null(), name, self.file, line as c_uint, - size * 8 as u64, align * 8 as u64, offset * 8 as u64, - 0, ty) + self.builder, + self.file, + name, + self.file, + line as c_uint, + bytes_to_bits(size), + bytes_to_bits(align), + bytes_to_bits(offset), + 0, + ty) }}; self.members.push(mem_t); self.total_size = offset + size; @@ -522,29 +555,48 @@ impl StructContext { self.align = cmp::max(self.align, align); } + fn get_total_size_with_alignment(&self) -> uint { + roundup(self.total_size, self.align) + } + fn finalize(&self) -> DICompositeType { debug!("StructContext(%s)::finalize: total_size=%u, align=%u", self.name, self.total_size, self.align); let members_md = create_DIArray(self.builder, self.members); + // The size of the struct/tuple must be rounded to the next multiple of its alignment. + // Otherwise gdb has trouble reading the struct correctly when it is embedded into another + // data structure. This is also the value `sizeof` in C would give. + let actual_total_size = self.get_total_size_with_alignment(); + let struct_md = do as_c_str(self.name) |name| { unsafe { llvm::LLVMDIBuilderCreateStructType( - self.builder, self.file, name, - self.file, self.line as c_uint, - self.total_size * 8 as u64, self.align * 8 as u64, 0, ptr::null(), - members_md, 0, ptr::null()) + self.builder, + self.file, + name, + self.file, + self.line as c_uint, + bytes_to_bits(actual_total_size), + bytes_to_bits(self.align), + 0, + ptr::null(), + members_md, + 0, + ptr::null()) }}; return struct_md; } } -fn create_struct(cx: @mut CrateContext, t: ty::t, fields: ~[ty::field], span: span) +fn create_struct(cx: &mut CrateContext, struct_type: ty::t, fields: ~[ty::field], span: span) -> DICompositeType { + debug!("create_struct: %?", ty::get(struct_type)); + let loc = span_start(cx, span); let file_md = create_file(cx, loc.file.name); - let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, t), file_md, loc.line); + let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, struct_type), file_md, loc.line); for fields.iter().advance |field| { let field_t = field.mt.ty; let ty_md = create_ty(cx, field_t, span); @@ -555,22 +607,28 @@ fn create_struct(cx: @mut CrateContext, t: ty::t, fields: ~[ty::field], span: sp } // returns (void* type as a ValueRef, size in bytes, align in bytes) -fn voidptr(cx: @mut CrateContext) -> (DIDerivedType, uint, uint) { +fn voidptr(cx: &mut CrateContext) -> (DIDerivedType, uint, uint) { let size = sys::size_of::<ValueRef>(); let align = sys::min_align_of::<ValueRef>(); let vp = do as_c_str("*void") |name| { unsafe { - llvm::LLVMDIBuilderCreatePointerType(DIB(cx), ptr::null(), - size*8 as u64, align*8 as u64, name) + llvm::LLVMDIBuilderCreatePointerType( + DIB(cx), + ptr::null(), + bytes_to_bits(size), + bytes_to_bits(align), + name) }}; return (vp, size, align); } -fn create_tuple(cx: @mut CrateContext, _t: ty::t, elements: &[ty::t], span: span) +fn create_tuple(cx: &mut CrateContext, tuple_type: ty::t, elements: &[ty::t], span: span) -> DICompositeType { + debug!("create_tuple: %?", ty::get(tuple_type)); + let loc = span_start(cx, span); let file_md = create_file(cx, loc.file.name); - let name = (cx.sess.str_of((dbg_cx(cx).names)("tuple"))).to_owned(); + let name = fmt!("tuple_%u", token::gensym("tuple")); let mut scx = StructContext::new(cx, name, file_md, loc.line); for elements.iter().advance |element| { let ty_md = create_ty(cx, *element, span); @@ -580,8 +638,10 @@ fn create_tuple(cx: @mut CrateContext, _t: ty::t, elements: &[ty::t], span: span return scx.finalize(); } -fn create_boxed_type(cx: @mut CrateContext, contents: ty::t, +fn create_boxed_type(cx: &mut CrateContext, contents: ty::t, span: span, boxed: DIType) -> DICompositeType { + debug!("create_boxed_type: %?", ty::get(contents)); + let loc = span_start(cx, span); let file_md = create_file(cx, loc.file.name); let int_t = ty::mk_int(); @@ -602,8 +662,10 @@ fn create_boxed_type(cx: @mut CrateContext, contents: ty::t, return scx.finalize(); } -fn create_fixed_vec(cx: @mut CrateContext, _vec_t: ty::t, elem_t: ty::t, +fn create_fixed_vec(cx: &mut CrateContext, _vec_t: ty::t, elem_t: ty::t, len: uint, span: span) -> DIType { + debug!("create_fixed_vec: %?", ty::get(_vec_t)); + let elem_ty_md = create_ty(cx, elem_t, span); let (size, align) = size_and_align_of(cx, elem_t); @@ -613,23 +675,40 @@ fn create_fixed_vec(cx: @mut CrateContext, _vec_t: ty::t, elem_t: ty::t, let subscripts = create_DIArray(DIB(cx), [subrange]); return unsafe { - llvm::LLVMDIBuilderCreateArrayType(DIB(cx), - size * len * 8 as u64, align * 8 as u64, elem_ty_md, subscripts) + llvm::LLVMDIBuilderCreateArrayType( + DIB(cx), + bytes_to_bits(size * len), + bytes_to_bits(align), + elem_ty_md, + subscripts) }; } -fn create_boxed_vec(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, +fn create_boxed_vec(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, vec_ty_span: span) -> DICompositeType { + debug!("create_boxed_vec: %?", ty::get(vec_t)); + let loc = span_start(cx, vec_ty_span); let file_md = create_file(cx, loc.file.name); let elem_ty_md = create_ty(cx, elem_t, vec_ty_span); let mut vec_scx = StructContext::new(cx, ty_to_str(cx.tcx, vec_t), file_md, 0); let size_t_type = create_basic_type(cx, ty::mk_uint(), vec_ty_span); - vec_scx.add_member("fill", 0, sys::size_of::<libc::size_t>(), - sys::min_align_of::<libc::size_t>(), size_t_type); - vec_scx.add_member("alloc", 0, sys::size_of::<libc::size_t>(), - sys::min_align_of::<libc::size_t>(), size_t_type); + + vec_scx.add_member( + "fill", + 0, + sys::size_of::<libc::size_t>(), + sys::min_align_of::<libc::size_t>(), + size_t_type); + + vec_scx.add_member( + "alloc", + 0, + sys::size_of::<libc::size_t>(), + sys::min_align_of::<libc::size_t>(), + size_t_type); + let subrange = unsafe { llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0_i64, 0_i64) }; @@ -638,18 +717,32 @@ fn create_boxed_vec(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, let subscripts = create_DIArray(DIB(cx), [subrange]); let data_ptr = unsafe { - llvm::LLVMDIBuilderCreateArrayType(DIB(cx), - arr_size * 8 as u64, arr_align * 8 as u64, elem_ty_md, subscripts) + llvm::LLVMDIBuilderCreateArrayType( + DIB(cx), + bytes_to_bits(arr_size), + bytes_to_bits(arr_align), + elem_ty_md, + subscripts) }; - vec_scx.add_member("data", 0, 0, // clang says the size should be 0 - sys::min_align_of::<u8>(), data_ptr); + vec_scx.add_member( + "data", + 0, + 0, // clang says the size should be 0 + sys::min_align_of::<u8>(), data_ptr); + let vec_md = vec_scx.finalize(); let mut box_scx = StructContext::new(cx, fmt!("box<%s>", name), file_md, 0); let int_t = ty::mk_int(); let refcount_type = create_basic_type(cx, int_t, vec_ty_span); - box_scx.add_member("refcnt", 0, sys::size_of::<uint>(), - sys::min_align_of::<uint>(), refcount_type); + + box_scx.add_member( + "refcnt", + 0, + sys::size_of::<uint>(), + sys::min_align_of::<uint>(), + refcount_type); + let (vp, vpsize, vpalign) = voidptr(cx); box_scx.add_member("tydesc", 0, vpsize, vpalign, vp); box_scx.add_member("prev", 0, vpsize, vpalign, vp); @@ -661,8 +754,10 @@ fn create_boxed_vec(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, return mdval; } -fn create_vec_slice(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: span) +fn create_vec_slice(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: span) -> DICompositeType { + debug!("create_vec_slice: %?", ty::get(vec_t)); + let loc = span_start(cx, span); let file_md = create_file(cx, loc.file.name); let elem_ty_md = create_ty(cx, elem_t, span); @@ -672,13 +767,14 @@ fn create_vec_slice(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: sp let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, vec_t), file_md, 0); let (_, ptr_size, ptr_align) = voidptr(cx); scx.add_member("vec", 0, ptr_size, ptr_align, elem_ptr); - scx.add_member("length", 0, sys::size_of::<uint>(), - sys::min_align_of::<uint>(), uint_type); + scx.add_member("length", 0, sys::size_of::<uint>(), sys::min_align_of::<uint>(), uint_type); return scx.finalize(); } -fn create_fn_ty(cx: @mut CrateContext, _fn_ty: ty::t, inputs: ~[ty::t], output: ty::t, +fn create_fn_ty(cx: &mut CrateContext, _fn_ty: ty::t, inputs: ~[ty::t], output: ty::t, span: span) -> DICompositeType { + debug!("create_fn_ty: %?", ty::get(_fn_ty)); + let loc = span_start(cx, span); let file_md = create_file(cx, loc.file.name); let (vp, _, _) = voidptr(cx); @@ -688,22 +784,29 @@ fn create_fn_ty(cx: @mut CrateContext, _fn_ty: ty::t, inputs: ~[ty::t], output: let members = ~[output_ptr_md, vp] + inputs_vals; return unsafe { - llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_md, + llvm::LLVMDIBuilderCreateSubroutineType( + DIB(cx), + file_md, create_DIArray(DIB(cx), members)) }; } -fn create_unimpl_ty(cx: @mut CrateContext, t: ty::t) -> DIType { +fn create_unimpl_ty(cx: &mut CrateContext, t: ty::t) -> DIType { + debug!("create_unimpl_ty: %?", ty::get(t)); + let name = ty_to_str(cx.tcx, t); let md = do as_c_str(fmt!("NYI<%s>", name)) |name| { unsafe { llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), name, - 0_u64, 8_u64, DW_ATE_unsigned as c_uint) + DIB(cx), + name, + 0_u64, + 8_u64, + DW_ATE_unsigned as c_uint) }}; return md; } -fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType { +fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) -> DIType { let ty_id = ty::type_id(t); match dbg_cx(cx).created_types.find(&ty_id) { Some(ty_md) => return *ty_md, @@ -758,9 +861,9 @@ fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType { let pointee = create_ty(cx, mt.ty, span); create_pointer_type(cx, t, span, pointee) }, - ty::ty_rptr(ref _region, ref _mt) => { - cx.sess.span_note(span, "debuginfo for rptr NYI"); - create_unimpl_ty(cx, t) + ty::ty_rptr(_, ref mt) => { + let pointee = create_ty(cx, mt.ty, span); + create_pointer_type(cx, t, span, pointee) }, ty::ty_bare_fn(ref barefnty) => { let inputs = barefnty.sig.inputs.map(|a| *a); @@ -799,15 +902,15 @@ fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: ui let elems = ~[C_i32(line as i32), C_i32(col as i32), scope, ptr::null()]; unsafe { let dbg_loc = llvm::LLVMMDNodeInContext( - dbg_cx(cx).llcontext, vec::raw::to_ptr(elems), - elems.len() as libc::c_uint); + dbg_cx(cx).llcontext, + vec::raw::to_ptr(elems), + elems.len() as c_uint); + llvm::LLVMSetCurrentDebugLocation(cx.builder.B, dbg_loc); } } - - //=------------------------------------------------------------------------------------------------- // Utility Functions //=------------------------------------------------------------------------------------------------- @@ -819,14 +922,18 @@ fn roundup(x: uint, a: uint) -> uint { /// Return codemap::Loc corresponding to the beginning of the span fn span_start(cx: &CrateContext, span: span) -> codemap::Loc { - return cx.sess.codemap.lookup_char_pos(span.lo); + cx.sess.codemap.lookup_char_pos(span.lo) } -fn size_and_align_of(cx: @mut CrateContext, t: ty::t) -> (uint, uint) { +fn size_and_align_of(cx: &mut CrateContext, t: ty::t) -> (uint, uint) { let llty = type_of::type_of(cx, t); (machine::llsize_of_real(cx, llty), machine::llalign_of_min(cx, llty)) } +fn bytes_to_bits(bytes: uint) -> c_ulonglong { + (bytes * 8) as c_ulonglong +} + #[inline] fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext { cx.dbg_cx.get_mut_ref() diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 02f276cd050..35322730756 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -907,9 +907,12 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { let scaled_ix = Mul(bcx, ix_val, vt.llunit_size); base::maybe_name_value(bcx.ccx(), scaled_ix, "scaled_ix"); - let mut (bcx, base, len) = + let (bcx, base, len) = base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id, 0); + let mut bcx = bcx; + let mut base = base; + let mut len = len; if ty::type_is_str(base_ty) { // acccount for null terminator in the case of string diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 6263ffb318e..7672f3b615d 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -555,7 +555,6 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, decl, item.id, output_type, - None, Some(substs), Some(item.span)); @@ -1183,7 +1182,6 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, no_self, None, id, - None, []); return llfndecl; } diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index 01849ac6e8f..11c02f165b6 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -127,7 +127,6 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id, self_kind, None, mth.id, - Some(impl_did), []); } local_def(mth.id) diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index ebcc3d811eb..0b051662781 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -32,7 +32,6 @@ use util::ppaux::Repr; use middle::trans::type_::Type; -use core::str; use core::vec; use syntax::ast_map::{path, path_mod, path_name}; use syntax::ast_util; @@ -68,8 +67,7 @@ pub fn trans_impl(ccx: @mut CrateContext, path, *method, None, - llfn, - ast_util::local_def(id)); + llfn); } } } @@ -90,8 +88,7 @@ pub fn trans_method(ccx: @mut CrateContext, path: path, method: &ast::method, param_substs: Option<@param_substs>, - llfn: ValueRef, - impl_id: ast::def_id) { + llfn: ValueRef) { // figure out how self is being passed let self_arg = match method.explicit_self.node { ast::sty_static => { @@ -110,9 +107,7 @@ pub fn trans_method(ccx: @mut CrateContext, debug!("calling trans_fn with self_ty %s", self_ty.repr(ccx.tcx)); match method.explicit_self.node { - ast::sty_value => { - impl_owned_self(self_ty) - } + ast::sty_value => impl_owned_self(self_ty), _ => { impl_self(self_ty) } @@ -129,7 +124,6 @@ pub fn trans_method(ccx: @mut CrateContext, self_arg, param_substs, method.id, - Some(impl_id), []); } @@ -141,10 +135,10 @@ pub fn trans_self_arg(bcx: block, // Compute the type of self. let self_ty = monomorphize_type(bcx, mentry.self_ty); - let result = trans_arg_expr(bcx, self_ty, mentry.self_mode, + mentry.explicit_self, base, &mut temp_cleanups, None, @@ -175,21 +169,6 @@ pub fn trans_method_callee(bcx: block, // Replace method_self with method_static here. let mut origin = mentry.origin; match origin { - typeck::method_self(trait_id, method_index) => { - // Get the ID of the impl we're inside. - let impl_def_id = bcx.fcx.impl_id.get(); - - debug!("impl_def_id is %?", impl_def_id); - - // Get the ID of the method we're calling. - let method_name = - ty::trait_method(tcx, trait_id, method_index).ident; - let method_id = - method_with_name_or_default(bcx.ccx(), - impl_def_id, - method_name); - origin = typeck::method_static(method_id); - } typeck::method_super(trait_id, method_index) => { // <self_ty> is the self type for this method call let self_ty = node_id_type(bcx, this.id); @@ -214,6 +193,7 @@ pub fn trans_method_callee(bcx: block, impl_id, method_name)); } + typeck::method_self(*) | typeck::method_static(*) | typeck::method_param(*) | typeck::method_trait(*) => {} } @@ -231,6 +211,7 @@ pub fn trans_method_callee(bcx: block, llself: val, self_ty: node_id_type(bcx, this.id), self_mode: mentry.self_mode, + explicit_self: mentry.explicit_self }) } } @@ -250,6 +231,21 @@ pub fn trans_method_callee(bcx: block, None => fail!("trans_method_callee: missing param_substs") } } + + typeck::method_self(trait_id, method_index) => { + match bcx.fcx.param_substs { + Some(@param_substs + {self_vtable: Some(ref vtbl), _}) => { + trans_monomorphized_callee(bcx, callee_id, this, mentry, + trait_id, method_index, + copy *vtbl) + } + _ => { + fail!("trans_method_callee: missing self_vtable") + } + } + } + typeck::method_trait(_, off, store) => { trans_trait_callee(bcx, callee_id, @@ -258,9 +254,9 @@ pub fn trans_method_callee(bcx: block, store, mentry.explicit_self) } - typeck::method_self(*) | typeck::method_super(*) => { - fail!("method_self or method_super should have been handled \ - above") + typeck::method_super(*) => { + fail!("method_super should have been handled \ + above") } } } @@ -292,15 +288,9 @@ pub fn trans_static_method_callee(bcx: block, // // So when we see a call to this function foo, we have to figure // out which impl the `Trait<T1...Tn>` bound on the type `self` was - // bound to. Due to the fact that we use a flattened list of - // impls, one per bound, this means we have to total up the bounds - // found on the type parametesr T1...Tn to find the index of the - // one we are interested in. - let bound_index = { - let trait_def = ty::lookup_trait_def(bcx.tcx(), trait_id); - ty::count_traits_and_supertraits( - bcx.tcx(), *trait_def.generics.type_param_defs) - }; + // bound to. + let bound_index = ty::lookup_trait_def(bcx.tcx(), trait_id). + generics.type_param_defs.len(); let mname = if method_id.crate == ast::local_crate { match bcx.tcx().items.get_copy(&method_id.node) { @@ -322,17 +312,17 @@ pub fn trans_static_method_callee(bcx: block, let vtbls = resolve_vtables_in_fn_ctxt( bcx.fcx, ccx.maps.vtable_map.get_copy(&callee_id)); - match vtbls[bound_index] { + match vtbls[bound_index][0] { typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => { assert!(rcvr_substs.iter().all(|t| !ty::type_needs_infer(*t))); let mth_id = method_with_name_or_default(bcx.ccx(), impl_did, mname); - let callee_substs = combine_impl_and_methods_tps( - bcx, mth_id, impl_did, callee_id, *rcvr_substs); - let callee_origins = combine_impl_and_methods_origins( - bcx, mth_id, impl_did, callee_id, rcvr_origins); + let (callee_substs, callee_origins) = + combine_impl_and_methods_tps( + bcx, mth_id, impl_did, callee_id, + *rcvr_substs, rcvr_origins); let FnData {llfn: lval} = trans_fn_ref_with_vtables(bcx, @@ -428,10 +418,10 @@ pub fn trans_monomorphized_callee(bcx: block, // create a concatenated set of substitutions which includes // those from the impl and those from the method: - let callee_substs = combine_impl_and_methods_tps( - bcx, mth_id, impl_did, callee_id, *rcvr_substs); - let callee_origins = combine_impl_and_methods_origins( - bcx, mth_id, impl_did, callee_id, rcvr_origins); + let (callee_substs, callee_origins) = + combine_impl_and_methods_tps( + bcx, mth_id, impl_did, callee_id, + *rcvr_substs, rcvr_origins); // translate the function let callee = trans_fn_ref_with_vtables(bcx, @@ -453,12 +443,16 @@ pub fn trans_monomorphized_callee(bcx: block, llself: llself_val, self_ty: node_id_type(bcx, base.id), self_mode: mentry.self_mode, + explicit_self: mentry.explicit_self }) } } typeck::vtable_param(*) => { fail!("vtable_param left in monomorphized function's vtable substs"); } + typeck::vtable_self(*) => { + fail!("vtable_self left in monomorphized function's vtable substs"); + } }; } @@ -467,8 +461,9 @@ pub fn combine_impl_and_methods_tps(bcx: block, mth_did: ast::def_id, impl_did: ast::def_id, callee_id: ast::node_id, - rcvr_substs: &[ty::t]) - -> ~[ty::t] { + rcvr_substs: &[ty::t], + rcvr_origins: typeck::vtable_res) + -> (~[ty::t], typeck::vtable_res) { /*! * * Creates a concatenated set of substitutions which includes @@ -492,58 +487,23 @@ pub fn combine_impl_and_methods_tps(bcx: block, debug!("rcvr_substs=%?", rcvr_substs.map(|t| bcx.ty_to_str(*t))); let ty_substs = vec::append(rcvr_substs.to_owned(), - vec::tailn(node_substs, - node_substs.len() - n_m_tps)); + node_substs.tailn(node_substs.len() - n_m_tps)); debug!("n_m_tps=%?", n_m_tps); debug!("node_substs=%?", node_substs.map(|t| bcx.ty_to_str(*t))); debug!("ty_substs=%?", ty_substs.map(|t| bcx.ty_to_str(*t))); - return ty_substs; -} -pub fn combine_impl_and_methods_origins(bcx: block, - mth_did: ast::def_id, - impl_did: ast::def_id, - callee_id: ast::node_id, - rcvr_origins: typeck::vtable_res) - -> typeck::vtable_res { - /*! - * - * Similar to `combine_impl_and_methods_tps`, but for vtables. - * This is much messier because of the flattened layout we are - * currently using (for some reason that I fail to understand). - * The proper fix is described in #3446. - */ - - - // Find the bounds for the method, which are the tail of the - // bounds found in the item type, as the item type combines the - // rcvr + method bounds. - let ccx = bcx.ccx(); - let tcx = bcx.tcx(); - let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did); - let ty::ty_param_bounds_and_ty { - generics: r_m_generics, - _ - } = ty::lookup_item_type(tcx, mth_did); - let n_r_m_tps = r_m_generics.type_param_defs.len(); // rcvr + method tps - let m_type_param_defs = - vec::slice(*r_m_generics.type_param_defs, n_r_m_tps - n_m_tps, n_r_m_tps); - - // Flatten out to find the number of vtables the method expects. - let m_vtables = ty::count_traits_and_supertraits(tcx, m_type_param_defs); - - // Find the vtables we computed at type check time and monomorphize them + // Now, do the same work for the vtables. The vtables might not + // exist, in which case we need to make them. let r_m_origins = match node_vtables(bcx, callee_id) { Some(vt) => vt, - None => @~[] + None => @vec::from_elem(node_substs.len(), @~[]) }; + let vtables + = @vec::append(rcvr_origins.to_owned(), + r_m_origins.tailn(r_m_origins.len() - n_m_tps)); - // Extract those that belong to method: - let m_origins = vec::tailn(*r_m_origins, r_m_origins.len() - m_vtables); - - // Combine rcvr + method to find the final result: - @vec::append(/*bad*/copy *rcvr_origins, m_origins) + return (ty_substs, vtables); } @@ -693,6 +653,7 @@ pub fn trans_trait_callee_from_llval(bcx: block, llself: llself, self_ty: ty::mk_opaque_box(bcx.tcx()), self_mode: self_mode, + explicit_self: explicit_self /* XXX: Some(llbox) */ }) }; @@ -755,8 +716,8 @@ pub fn make_vtable(ccx: &mut CrateContext, } let tbl = C_struct(components); - let vtable = ccx.sess.str_of((ccx.names)("vtable")); - let vt_gvar = do str::as_c_str(vtable) |buf| { + let vtable = ccx.sess.str_of(gensym_name("vtable")); + let vt_gvar = do vtable.as_c_str |buf| { llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl).to_ref(), buf) }; llvm::LLVMSetInitializer(vt_gvar, tbl); @@ -840,7 +801,7 @@ pub fn trans_trait_cast(bcx: block, bcx = expr::trans_into(bcx, val, SaveIn(llboxdest)); // Store the vtable into the pair or triple. - let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0]; + let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0][0]; let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig); let vtable = get_vtable(bcx, v_ty, orig); Store(bcx, vtable, PointerCast(bcx, diff --git a/src/librustc/middle/trans/mod.rs b/src/librustc/middle/trans/mod.rs index c2a25d80998..64d6bbec87c 100644 --- a/src/librustc/middle/trans/mod.rs +++ b/src/librustc/middle/trans/mod.rs @@ -37,7 +37,6 @@ pub mod foreign; pub mod reflect; pub mod debuginfo; pub mod type_use; -pub mod reachable; pub mod machine; pub mod adt; pub mod asm; diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 1ffe26e3aff..92d8192aee6 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -43,6 +43,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, fn_id: ast::def_id, real_substs: &ty::substs, vtables: Option<typeck::vtable_res>, + self_vtable: Option<typeck::vtable_origin>, impl_did_opt: Option<ast::def_id>, ref_id: Option<ast::node_id>) -> (ValueRef, bool) @@ -161,9 +162,11 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, } ccx.monomorphizing.insert(fn_id, depth + 1); - let pt = vec::append(/*bad*/copy *pt, - [path_name((ccx.names)(ccx.sess.str_of(name)))]); + let elt = path_name(gensym_name(ccx.sess.str_of(name))); + let mut pt = /* bad */copy (*pt); + pt.push(elt); let s = mangle_exported_name(ccx, /*bad*/copy pt, mono_ty); + debug!("monomorphize_fn mangled to %s", s); let mk_lldecl = || { let lldecl = decl_internal_cdecl_fn(ccx.llmod, /*bad*/copy s, llfty); @@ -174,8 +177,8 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, let psubsts = Some(@param_substs { tys: substs, vtables: vtables, - type_param_defs: tpt.generics.type_param_defs, - self_ty: real_substs.self_ty + self_ty: real_substs.self_ty, + self_vtable: self_vtable }); let lldecl = match map_node { @@ -193,7 +196,6 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, no_self, psubsts, fn_id.node, - None, []); d } @@ -221,27 +223,17 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, } d } - ast_map::node_method(mth, supplied_impl_did, _) => { + ast_map::node_method(mth, _, _) => { // XXX: What should the self type be here? let d = mk_lldecl(); set_inline_hint_if_appr(/*bad*/copy mth.attrs, d); - - // Override the impl def ID if necessary. - let impl_did; - match impl_did_opt { - None => impl_did = supplied_impl_did, - Some(override_impl_did) => impl_did = override_impl_did - } - - meth::trans_method(ccx, pt, mth, psubsts, d, impl_did); + meth::trans_method(ccx, pt, mth, psubsts, d); d } ast_map::node_trait_method(@ast::provided(mth), _, pt) => { let d = mk_lldecl(); set_inline_hint_if_appr(/*bad*/copy mth.attrs, d); - debug!("monomorphic_fn impl_did_opt is %?", impl_did_opt); - meth::trans_method(ccx, /*bad*/copy *pt, mth, psubsts, d, - impl_did_opt.get()); + meth::trans_method(ccx, /*bad*/copy *pt, mth, psubsts, d); d } ast_map::node_struct_ctor(struct_def, _, _) => { @@ -336,14 +328,10 @@ pub fn make_mono_id(ccx: @mut CrateContext, param_uses: Option<@~[type_use::type_uses]>) -> mono_id { let precise_param_ids = match vtables { Some(vts) => { - let item_ty = ty::lookup_item_type(ccx.tcx, item); - let mut i = 0; - vec::map_zip(*item_ty.generics.type_param_defs, substs, |type_param_def, subst| { - let mut v = ~[]; - for type_param_def.bounds.trait_bounds.iter().advance |_bound| { - v.push(meth::vtable_id(ccx, &vts[i])); - i += 1; - } + debug!("make_mono_id vtables=%s substs=%s", + vts.repr(ccx.tcx), substs.repr(ccx.tcx)); + vec::map_zip(*vts, substs, |vtable, subst| { + let v = vtable.map(|vt| meth::vtable_id(ccx, vt)); (*subst, if !v.is_empty() { Some(@v) } else { None }) }) } diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs deleted file mode 100644 index e950c24c49e..00000000000 --- a/src/librustc/middle/trans/reachable.rs +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Finds items that are externally reachable, to determine which items -// need to have their metadata (and possibly their AST) serialized. -// All items that can be referred to through an exported name are -// reachable, and when a reachable thing is inline or generic, it -// makes all other generics or inline functions that it references -// reachable as well. - -use core::prelude::*; - -use middle::resolve; -use middle::ty; -use middle::typeck; - -use core::hashmap::HashSet; -use syntax::ast; -use syntax::ast::*; -use syntax::ast_util::def_id_of_def; -use syntax::attr; -use syntax::codemap; -use syntax::print::pprust::expr_to_str; -use syntax::{visit, ast_map}; - -pub type map = @HashSet<node_id>; - -struct ctx<'self> { - exp_map2: resolve::ExportMap2, - tcx: ty::ctxt, - method_map: typeck::method_map, - rmap: &'self mut HashSet<node_id>, -} - -pub fn find_reachable(crate_mod: &_mod, exp_map2: resolve::ExportMap2, - tcx: ty::ctxt, method_map: typeck::method_map) -> map { - let mut rmap = HashSet::new(); - { - let cx = @mut ctx { - exp_map2: exp_map2, - tcx: tcx, - method_map: method_map, - rmap: &mut rmap - }; - traverse_public_mod(cx, ast::crate_node_id, crate_mod); - traverse_all_resources_and_impls(cx, crate_mod); - } - return @rmap; -} - -fn traverse_exports(cx: @mut ctx, mod_id: node_id) -> bool { - let mut found_export = false; - match cx.exp_map2.find(&mod_id) { - Some(ref exp2s) => { - for (*exp2s).iter().advance |e2| { - found_export = true; - traverse_def_id(cx, e2.def_id) - }; - } - None => () - } - return found_export; -} - -fn traverse_def_id(cx: @mut ctx, did: def_id) { - if did.crate != local_crate { return; } - match cx.tcx.items.find(&did.node) { - None => (), // This can happen for self, for example - Some(&ast_map::node_item(item, _)) => traverse_public_item(cx, item), - Some(&ast_map::node_method(_, impl_id, _)) => traverse_def_id(cx, impl_id), - Some(&ast_map::node_foreign_item(item, _, _, _)) => { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - cx.rmap.insert(item.id); - } - Some(&ast_map::node_variant(ref v, _, _)) => { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - cx.rmap.insert(v.node.id); - } - _ => () - } -} - -fn traverse_public_mod(cx: @mut ctx, mod_id: node_id, m: &_mod) { - if !traverse_exports(cx, mod_id) { - // No exports, so every local item is exported - for m.items.iter().advance |item| { - traverse_public_item(cx, *item); - } - } -} - -fn traverse_public_item(cx: @mut ctx, item: @item) { - { - // FIXME #6021: naming rmap shouldn't be necessary - let cx = &mut *cx; - let rmap: &mut HashSet<node_id> = cx.rmap; - if rmap.contains(&item.id) { return; } - rmap.insert(item.id); - } - - match item.node { - item_mod(ref m) => traverse_public_mod(cx, item.id, m), - item_foreign_mod(ref nm) => { - if !traverse_exports(cx, item.id) { - for nm.items.iter().advance |item| { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - cx.rmap.insert(item.id); - } - } - } - item_fn(_, _, _, ref generics, ref blk) => { - if generics.ty_params.len() > 0u || - attr::find_inline_attr(item.attrs) != attr::ia_none { - traverse_inline_body(cx, blk); - } - } - item_impl(ref generics, _, _, ref ms) => { - for ms.iter().advance |m| { - if generics.ty_params.len() > 0u || - m.generics.ty_params.len() > 0u || - attr::find_inline_attr(m.attrs) != attr::ia_none - { - { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - cx.rmap.insert(m.id); - } - traverse_inline_body(cx, &m.body); - } - } - } - item_struct(ref struct_def, _) => { - for struct_def.ctor_id.iter().advance |&ctor_id| { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - cx.rmap.insert(ctor_id); - } - } - item_ty(t, _) => { - traverse_ty(t, (cx, - visit::mk_vt(@visit::Visitor {visit_ty: traverse_ty, - ..*visit::default_visitor()}))) - } - item_static(*) | - item_enum(*) | item_trait(*) => (), - item_mac(*) => fail!("item macros unimplemented") - } -} - -fn traverse_ty<'a>(ty: @Ty, (cx, v): (@mut ctx<'a>, visit::vt<@mut ctx<'a>>)) { - { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - if cx.rmap.contains(&ty.id) { return; } - cx.rmap.insert(ty.id); - } - - match ty.node { - 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 - Some(&def_prim_ty(_)) => { /* do nothing */ } - Some(&d) => traverse_def_id(cx, def_id_of_def(d)), - None => { /* do nothing -- but should we fail here? */ } - } - for p.types.iter().advance |t| { - (v.visit_ty)(*t, (cx, v)); - } - } - _ => visit::visit_ty(ty, (cx, v)) - } -} - -fn traverse_inline_body(cx: @mut ctx, body: &blk) { - fn traverse_expr<'a>(e: @expr, (cx, v): (@mut ctx<'a>, - visit::vt<@mut ctx<'a>>)) { - match e.node { - expr_path(_) => { - match cx.tcx.def_map.find(&e.id) { - Some(&d) => { - traverse_def_id(cx, def_id_of_def(d)); - } - None => cx.tcx.sess.span_bug( - e.span, - fmt!("Unbound node id %? while traversing %s", - e.id, - expr_to_str(e, cx.tcx.sess.intr()))) - } - } - expr_method_call(*) => { - match cx.method_map.find(&e.id) { - Some(&typeck::method_map_entry { - origin: typeck::method_static(did), - _ - }) => { - traverse_def_id(cx, did); - } - Some(_) => {} - None => { - cx.tcx.sess.span_bug(e.span, "expr_method_call not in \ - method map"); - } - } - } - _ => () - } - visit::visit_expr(e, (cx, v)); - } - // Don't ignore nested items: for example if a generic fn contains a - // generic impl (as in deque::create), we need to monomorphize the - // impl as well - fn traverse_item(i: @item, (cx, _v): (@mut ctx, visit::vt<@mut ctx>)) { - traverse_public_item(cx, i); - } - visit::visit_block(body, (cx, visit::mk_vt(@visit::Visitor { - visit_expr: traverse_expr, - visit_item: traverse_item, - ..*visit::default_visitor() - }))); -} - -fn traverse_all_resources_and_impls(cx: @mut ctx, crate_mod: &_mod) { - visit::visit_mod( - crate_mod, - codemap::dummy_sp(), - 0, - (cx, - visit::mk_vt(@visit::Visitor { - visit_expr: |_e, (_cx, _v)| { }, - visit_item: |i, (cx, v)| { - visit::visit_item(i, (cx, v)); - match i.node { - item_impl(*) => { - traverse_public_item(cx, i); - } - _ => () - } - }, - ..*visit::default_visitor() - }))); -} diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d34befddad5..b8ee1eee26e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -52,7 +52,7 @@ use syntax; // Data types -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct field { ident: ast::ident, mt: mt @@ -96,13 +96,13 @@ impl Method { } } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct mt { ty: t, mutbl: ast::mutability, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable, IterBytes)] pub enum vstore { vstore_fixed(uint), vstore_uniq, @@ -133,7 +133,7 @@ pub struct field_ty { // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct creader_cache_key { cnum: int, pos: uint, @@ -142,14 +142,6 @@ pub struct creader_cache_key { type creader_cache = @mut HashMap<creader_cache_key, t>; -impl to_bytes::IterBytes for creader_cache_key { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.cnum.iter_bytes(lsb0, f) && - self.pos.iter_bytes(lsb0, f) && - self.len.iter_bytes(lsb0, f) - } -} - struct intern_key { sty: *sty, } @@ -168,6 +160,8 @@ impl cmp::Eq for intern_key { } } +// NB: Do not replace this with #[deriving(IterBytes)], as above. (Figured +// this out the hard way.) impl to_bytes::IterBytes for intern_key { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { unsafe { @@ -372,14 +366,14 @@ pub fn type_has_regions(t: t) -> bool { } pub fn type_id(t: t) -> uint { get(t).id } -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct BareFnTy { purity: ast::purity, abis: AbiSet, sig: FnSig } -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct ClosureTy { purity: ast::purity, sigil: ast::Sigil, @@ -396,32 +390,13 @@ pub struct ClosureTy { * - `lifetimes` is the list of region names bound in this fn. * - `inputs` is the list of arguments and their modes. * - `output` is the return type. */ -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct FnSig { bound_lifetime_names: OptVec<ast::ident>, inputs: ~[t], output: t } -impl to_bytes::IterBytes for BareFnTy { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.purity.iter_bytes(lsb0, f) && - self.abis.iter_bytes(lsb0, f) && - self.sig.iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for ClosureTy { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.purity.iter_bytes(lsb0, f) && - 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.bounds.iter_bytes(lsb0, f) - } -} - #[deriving(Eq, IterBytes)] pub struct param_ty { idx: uint, @@ -526,7 +501,7 @@ type opt_region = Option<Region>; * - `self_ty` is the type to which `self` should be remapped, if any. The * `self` type is rather funny in that it can only appear on traits and is * always substituted away to the implementing type for a trait. */ -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct substs { self_r: opt_region, self_ty: Option<ty::t>, @@ -582,7 +557,7 @@ mod primitives { // NB: If you change this, you'll probably want to change the corresponding // AST structure in libsyntax/ast.rs as well. -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub enum sty { ty_nil, ty_bot, @@ -686,8 +661,8 @@ pub type BuiltinBounds = EnumSet<BuiltinBound>; pub enum BuiltinBound { BoundCopy, BoundStatic, - BoundOwned, - BoundConst, + BoundSend, + BoundFreeze, BoundSized, } @@ -699,8 +674,8 @@ pub fn AllBuiltinBounds() -> BuiltinBounds { let mut set = EnumSet::empty(); set.add(BoundCopy); set.add(BoundStatic); - set.add(BoundOwned); - set.add(BoundConst); + set.add(BoundSend); + set.add(BoundFreeze); set.add(BoundSized); set } @@ -714,62 +689,33 @@ impl CLike for BuiltinBound { } } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct TyVid(uint); -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct IntVid(uint); -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct FloatVid(uint); -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable, IterBytes)] pub struct RegionVid { id: uint } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub enum InferTy { TyVar(TyVid), IntVar(IntVid), FloatVar(FloatVid) } -impl to_bytes::IterBytes for InferTy { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - TyVar(ref tv) => { - 0u8.iter_bytes(lsb0, f) && tv.iter_bytes(lsb0, f) - } - IntVar(ref iv) => { - 1u8.iter_bytes(lsb0, f) && iv.iter_bytes(lsb0, f) - } - FloatVar(ref fv) => { - 2u8.iter_bytes(lsb0, f) && fv.iter_bytes(lsb0, f) - } - } - } -} - -#[deriving(Encodable, Decodable)] +#[deriving(Encodable, Decodable, IterBytes)] pub enum InferRegion { ReVar(RegionVid), ReSkolemized(uint, bound_region) } -impl to_bytes::IterBytes for InferRegion { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - ReVar(ref rv) => { - 0u8.iter_bytes(lsb0, f) && rv.iter_bytes(lsb0, f) - } - ReSkolemized(ref v, _) => { - 1u8.iter_bytes(lsb0, f) && v.iter_bytes(lsb0, f) - } - } - } -} - impl cmp::Eq for InferRegion { fn eq(&self, other: &InferRegion) -> bool { match ((*self), *other) { @@ -849,30 +795,6 @@ impl ToStr for IntVarValue { } } -impl to_bytes::IterBytes for TyVid { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.to_uint().iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for IntVid { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.to_uint().iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for FloatVid { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.to_uint().iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for RegionVid { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.to_uint().iter_bytes(lsb0, f) - } -} - pub struct TypeParameterDef { def_id: ast::def_id, bounds: @ParamBounds @@ -1319,15 +1241,15 @@ pub fn maybe_walk_ty(ty: t, f: &fn(t) -> bool) { } ty_enum(_, ref substs) | ty_struct(_, ref substs) | ty_trait(_, ref substs, _, _, _) => { - for (*substs).tps.iter().advance |subty| { maybe_walk_ty(*subty, f); } + for (*substs).tps.iter().advance |subty| { maybe_walk_ty(*subty, |x| f(x)); } } - ty_tup(ref ts) => { for ts.iter().advance |tt| { maybe_walk_ty(*tt, f); } } + ty_tup(ref ts) => { for ts.iter().advance |tt| { maybe_walk_ty(*tt, |x| f(x)); } } ty_bare_fn(ref ft) => { - for ft.sig.inputs.iter().advance |a| { maybe_walk_ty(*a, f); } + for ft.sig.inputs.iter().advance |a| { maybe_walk_ty(*a, |x| f(x)); } maybe_walk_ty(ft.sig.output, f); } ty_closure(ref ft) => { - for ft.sig.inputs.iter().advance |a| { maybe_walk_ty(*a, f); } + for ft.sig.inputs.iter().advance |a| { maybe_walk_ty(*a, |x| f(x)); } maybe_walk_ty(ft.sig.output, f); } } @@ -1409,7 +1331,7 @@ fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty { // Folds types from the bottom up. pub fn fold_ty(cx: ctxt, t0: t, fldop: &fn(t) -> t) -> t { - let sty = fold_sty(&get(t0).sty, |t| fold_ty(cx, fldop(t), fldop)); + let sty = fold_sty(&get(t0).sty, |t| fold_ty(cx, fldop(t), |t| fldop(t))); fldop(mk_t(cx, sty)) } @@ -1423,8 +1345,8 @@ pub fn walk_regions_and_ty( fold_regions_and_ty( cx, ty, |r| { walkr(r); r }, - |t| { walk_regions_and_ty(cx, t, walkr, walkt); t }, - |t| { walk_regions_and_ty(cx, t, walkr, walkt); t }); + |t| { walk_regions_and_ty(cx, t, |r| walkr(r), |t| walkt(t)); t }, + |t| { walk_regions_and_ty(cx, t, |r| walkr(r), |t| walkt(t)); t }); } } @@ -1504,8 +1426,8 @@ pub fn fold_regions( fold_regions_and_ty( cx, ty, |r| fldr(r, in_fn), - |t| do_fold(cx, t, true, fldr), - |t| do_fold(cx, t, in_fn, fldr)) + |t| do_fold(cx, t, true, |r,b| fldr(r,b)), + |t| do_fold(cx, t, in_fn, |r,b| fldr(r,b))) } do_fold(cx, ty, false, fldr) } @@ -1838,8 +1760,8 @@ impl TypeContents { match bb { BoundCopy => self.is_copy(cx), BoundStatic => self.is_static(cx), - BoundConst => self.is_const(cx), - BoundOwned => self.is_owned(cx), + BoundFreeze => self.is_freezable(cx), + BoundSend => self.is_sendable(cx), BoundSized => self.is_sized(cx), } } @@ -1865,23 +1787,23 @@ impl TypeContents { TC_BORROWED_POINTER } - pub fn is_owned(&self, cx: ctxt) -> bool { - !self.intersects(TypeContents::nonowned(cx)) + pub fn is_sendable(&self, cx: ctxt) -> bool { + !self.intersects(TypeContents::nonsendable(cx)) } - pub fn nonowned(_cx: ctxt) -> TypeContents { - TC_MANAGED + TC_BORROWED_POINTER + TC_NON_OWNED + pub fn nonsendable(_cx: ctxt) -> TypeContents { + TC_MANAGED + TC_BORROWED_POINTER + TC_NON_SENDABLE } pub fn contains_managed(&self) -> bool { self.intersects(TC_MANAGED) } - pub fn is_const(&self, cx: ctxt) -> bool { - !self.intersects(TypeContents::nonconst(cx)) + pub fn is_freezable(&self, cx: ctxt) -> bool { + !self.intersects(TypeContents::nonfreezable(cx)) } - pub fn nonconst(_cx: ctxt) -> TypeContents { + pub fn nonfreezable(_cx: ctxt) -> TypeContents { TC_MUTABLE } @@ -1906,14 +1828,16 @@ impl TypeContents { // Currently all noncopyable existentials are 2nd-class types // behind owned pointers. With dynamically-sized types, remove // this assertion. - assert!(self.intersects(TC_OWNED_POINTER)); + assert!(self.intersects(TC_OWNED_POINTER) || + // (...or stack closures without a copy bound.) + self.intersects(TC_BORROWED_POINTER)); } - let tc = TC_MANAGED + TC_DTOR + TypeContents::owned(cx); + let tc = TC_MANAGED + TC_DTOR + TypeContents::sendable(cx); self.intersects(tc) } - pub fn owned(_cx: ctxt) -> TypeContents { - //! Any kind of owned contents. + pub fn sendable(_cx: ctxt) -> TypeContents { + //! Any kind of sendable contents. TC_OWNED_POINTER + TC_OWNED_VEC } } @@ -1969,8 +1893,8 @@ static TC_ONCE_CLOSURE: TypeContents = TypeContents{bits: 0b0001_0000_0000}; /// An enum with no variants. static TC_EMPTY_ENUM: TypeContents = TypeContents{bits: 0b0010_0000_0000}; -/// Contains a type marked with `#[non_owned]` -static TC_NON_OWNED: TypeContents = TypeContents{bits: 0b0100_0000_0000}; +/// Contains a type marked with `#[no_send]` +static TC_NON_SENDABLE: TypeContents = TypeContents{bits: 0b0100_0000_0000}; /// Is a bare vector, str, function, trait, etc (only relevant at top level). static TC_DYNAMIC_SIZE: TypeContents = TypeContents{bits: 0b1000_0000_0000}; @@ -1986,12 +1910,12 @@ pub fn type_is_static(cx: ctxt, t: ty::t) -> bool { type_contents(cx, t).is_static(cx) } -pub fn type_is_owned(cx: ctxt, t: ty::t) -> bool { - type_contents(cx, t).is_owned(cx) +pub fn type_is_sendable(cx: ctxt, t: ty::t) -> bool { + type_contents(cx, t).is_sendable(cx) } -pub fn type_is_const(cx: ctxt, t: ty::t) -> bool { - type_contents(cx, t).is_const(cx) +pub fn type_is_freezable(cx: ctxt, t: ty::t) -> bool { + type_contents(cx, t).is_freezable(cx) } pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { @@ -2045,7 +1969,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { let _i = indenter(); let result = match get(ty).sty { - // Scalar and unique types are sendable, constant, and owned + // Scalar and unique types are sendable, freezable, and durable ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(_) | ty_ptr(_) => { TC_NONE @@ -2060,7 +1984,8 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } ty_box(mt) => { - TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache))) + TC_MANAGED + + statically_sized(nonsendable(tc_mt(cx, mt, cache))) } ty_trait(_, _, store, mutbl, bounds) => { @@ -2069,7 +1994,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { ty_rptr(r, mt) => { borrowed_contents(r, mt.mutbl) + - statically_sized(nonowned(tc_mt(cx, mt, cache))) + statically_sized(nonsendable(tc_mt(cx, mt, cache))) } ty_uniq(mt) => { @@ -2081,12 +2006,13 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } ty_evec(mt, vstore_box) => { - TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache))) + TC_MANAGED + + statically_sized(nonsendable(tc_mt(cx, mt, cache))) } ty_evec(mt, vstore_slice(r)) => { borrowed_contents(r, mt.mutbl) + - statically_sized(nonowned(tc_mt(cx, mt, cache))) + statically_sized(nonsendable(tc_mt(cx, mt, cache))) } ty_evec(mt, vstore_fixed(_)) => { @@ -2118,7 +2044,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { TC_NONE, |tc, f| tc + tc_mt(cx, f.mt, cache)); if ty::has_dtor(cx, did) { - res += TC_DTOR; + res = res + TC_DTOR; } apply_tc_attr(cx, did, res) } @@ -2202,11 +2128,11 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } fn apply_tc_attr(cx: ctxt, did: def_id, mut tc: TypeContents) -> TypeContents { - if has_attr(cx, did, "mutable") { - tc += TC_MUTABLE; + if has_attr(cx, did, "no_freeze") { + tc = tc + TC_MUTABLE; } - if has_attr(cx, did, "non_owned") { - tc += TC_NON_OWNED; + if has_attr(cx, did, "no_send") { + tc = tc + TC_NON_SENDABLE; } tc } @@ -2227,7 +2153,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { mc + rc } - fn nonowned(pointee: TypeContents) -> TypeContents { + fn nonsendable(pointee: TypeContents) -> TypeContents { /*! * * Given a non-owning pointer to some type `T` with @@ -2270,7 +2196,14 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { ast::Once => TC_ONCE_CLOSURE, ast::Many => TC_NONE }; - st + rt + ot + // Prevent noncopyable types captured in the environment from being copied. + let ct = if cty.bounds.contains_elem(BoundCopy) || + cty.sigil == ast::ManagedSigil { + TC_NONE + } else { + TC_NONCOPY_TRAIT + }; + st + rt + ot + ct } fn trait_contents(store: TraitStore, mutbl: ast::mutability, @@ -2291,11 +2224,11 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { BoundCopy if store == UniqTraitStore => TC_NONCOPY_TRAIT, BoundCopy => TC_NONE, // @Trait/&Trait are copyable either way - BoundStatic if bounds.contains_elem(BoundOwned) - => TC_NONE, // Owned bound implies static bound. + BoundStatic if bounds.contains_elem(BoundSend) + => TC_NONE, // Send bound implies static bound. BoundStatic => TC_BORROWED_POINTER, // Useful for "@Trait:'static" - BoundOwned => TC_NON_OWNED, - BoundConst => TC_MUTABLE, + BoundSend => TC_NON_SENDABLE, + BoundFreeze => TC_MUTABLE, BoundSized => TC_NONE, // don't care if interior is sized }; } @@ -2314,8 +2247,8 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { tc = tc - match bound { BoundCopy => TypeContents::noncopyable(cx), BoundStatic => TypeContents::nonstatic(cx), - BoundOwned => TypeContents::nonowned(cx), - BoundConst => TypeContents::nonconst(cx), + BoundSend => TypeContents::nonsendable(cx), + BoundFreeze => TypeContents::nonfreezable(cx), // The dynamic-size bit can be removed at pointer-level, etc. BoundSized => TypeContents::dynamically_sized(cx), }; @@ -2450,7 +2383,7 @@ pub fn type_structurally_contains(cx: ctxt, for (*enum_variants(cx, did)).iter().advance |variant| { for variant.args.iter().advance |aty| { let sty = subst(cx, substs, *aty); - if type_structurally_contains(cx, sty, test) { return true; } + if type_structurally_contains(cx, sty, |x| test(x)) { return true; } } } return false; @@ -2459,14 +2392,14 @@ pub fn type_structurally_contains(cx: ctxt, let r = lookup_struct_fields(cx, did); for r.iter().advance |field| { let ft = lookup_field_type(cx, did, field.id, substs); - if type_structurally_contains(cx, ft, test) { return true; } + if type_structurally_contains(cx, ft, |x| test(x)) { return true; } } return false; } ty_tup(ref ts) => { for ts.iter().advance |tt| { - if type_structurally_contains(cx, *tt, test) { return true; } + if type_structurally_contains(cx, *tt, |x| test(x)) { return true; } } return false; } @@ -2742,123 +2675,6 @@ impl cmp::TotalEq for bound_region { } } -impl to_bytes::IterBytes for vstore { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - vstore_fixed(ref u) => { - 0u8.iter_bytes(lsb0, f) && u.iter_bytes(lsb0, f) - } - vstore_uniq => 1u8.iter_bytes(lsb0, f), - vstore_box => 2u8.iter_bytes(lsb0, f), - - vstore_slice(ref r) => { - 3u8.iter_bytes(lsb0, f) && r.iter_bytes(lsb0, f) - } - } - } -} - -impl to_bytes::IterBytes for substs { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.self_r.iter_bytes(lsb0, f) && - self.self_ty.iter_bytes(lsb0, f) && - self.tps.iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for mt { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.ty.iter_bytes(lsb0, f) && self.mutbl.iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for field { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.ident.iter_bytes(lsb0, f) && self.mt.iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for FnSig { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.inputs.iter_bytes(lsb0, f) && self.output.iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for sty { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - ty_nil => 0u8.iter_bytes(lsb0, f), - ty_bool => 1u8.iter_bytes(lsb0, f), - - ty_int(ref t) => 2u8.iter_bytes(lsb0, f) && t.iter_bytes(lsb0, f), - - ty_uint(ref t) => 3u8.iter_bytes(lsb0, f) && t.iter_bytes(lsb0, f), - - ty_float(ref t) => 4u8.iter_bytes(lsb0, f) && t.iter_bytes(lsb0, f), - - ty_estr(ref v) => 5u8.iter_bytes(lsb0, f) && v.iter_bytes(lsb0, f), - - ty_enum(ref did, ref substs) => { - 6u8.iter_bytes(lsb0, f) && - did.iter_bytes(lsb0, f) && - substs.iter_bytes(lsb0, f) - } - - ty_box(ref mt) => 7u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f), - - ty_evec(ref mt, ref v) => { - 8u8.iter_bytes(lsb0, f) && - mt.iter_bytes(lsb0, f) && - v.iter_bytes(lsb0, f) - } - - ty_unboxed_vec(ref mt) => 9u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f), - - ty_tup(ref ts) => 10u8.iter_bytes(lsb0, f) && ts.iter_bytes(lsb0, f), - - ty_bare_fn(ref ft) => 12u8.iter_bytes(lsb0, f) && ft.iter_bytes(lsb0, f), - - ty_self(ref did) => 13u8.iter_bytes(lsb0, f) && did.iter_bytes(lsb0, f), - - ty_infer(ref v) => 14u8.iter_bytes(lsb0, f) && v.iter_bytes(lsb0, f), - - ty_param(ref p) => 15u8.iter_bytes(lsb0, f) && p.iter_bytes(lsb0, f), - - ty_type => 16u8.iter_bytes(lsb0, f), - ty_bot => 17u8.iter_bytes(lsb0, f), - - ty_ptr(ref mt) => 18u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f), - - ty_uniq(ref mt) => 19u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f), - - 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) && - bounds.iter_bytes(lsb0, f) - } - - ty_opaque_closure_ptr(ref ck) => 21u8.iter_bytes(lsb0, f) && ck.iter_bytes(lsb0, f), - - ty_opaque_box => 22u8.iter_bytes(lsb0, f), - - ty_struct(ref did, ref substs) => { - 23u8.iter_bytes(lsb0, f) && did.iter_bytes(lsb0, f) && substs.iter_bytes(lsb0, f) - } - - ty_rptr(ref r, ref mt) => { - 24u8.iter_bytes(lsb0, f) && r.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f) - } - - ty_err => 25u8.iter_bytes(lsb0, f), - - ty_closure(ref ct) => 26u8.iter_bytes(lsb0, f) && ct.iter_bytes(lsb0, f), - } - } -} - pub fn node_id_to_trait_ref(cx: ctxt, id: ast::node_id) -> @ty::TraitRef { match cx.trait_refs.find(&id) { Some(&t) => t, @@ -3904,7 +3720,7 @@ impl DtorKind { pub fn ty_dtor(cx: ctxt, struct_id: def_id) -> DtorKind { match cx.destructor_for_type.find(&struct_id) { Some(&method_def_id) => { - let flag = !has_attr(cx, struct_id, "no_drop_flag"); + let flag = !has_attr(cx, struct_id, "unsafe_no_drop_flag"); TraitDtor(method_def_id, flag) } @@ -3954,7 +3770,7 @@ pub fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path { } ast_map::node_variant(ref variant, _, path) => { - vec::append_one(vec::to_owned(vec::init(*path)), + vec::append_one(vec::to_owned(path.init()), ast_map::path_name((*variant).node.name)) } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index b7242e64f23..07fb23fea48 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -753,7 +753,7 @@ fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBou //! Converts a list of bounds from the AST into a `BuiltinBounds` //! struct. Reports an error if any of the bounds that appear //! in the AST refer to general traits and not the built-in traits - //! like `Copy` or `Owned`. Used to translate the bounds that + //! like `Copy` or `Send`. Used to translate the bounds that //! appear in closure and trait types, where only builtin bounds are //! legal. //! If no bounds were specified, we choose a "default" bound based on @@ -788,9 +788,9 @@ fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBou } builtin_bounds }, - // ~Trait is sugar for ~Trait:Owned. + // ~Trait is sugar for ~Trait:Send. (&None, ty::UniqTraitStore) => { - let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundOwned); set + let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundSend); set } // @Trait is sugar for @Trait:'static. // &'static Trait is sugar for &'static Trait:'static. @@ -807,19 +807,19 @@ pub fn try_add_builtin_trait(tcx: ty::ctxt, trait_def_id: ast::def_id, builtin_bounds: &mut ty::BuiltinBounds) -> bool { //! Checks whether `trait_ref` refers to one of the builtin - //! traits, like `Copy` or `Owned`, and adds the corresponding + //! traits, like `Copy` or `Send`, and adds the corresponding //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref` //! is a builtin trait. let li = &tcx.lang_items; - if trait_def_id == li.owned_trait() { - builtin_bounds.add(ty::BoundOwned); + if trait_def_id == li.send_trait() { + builtin_bounds.add(ty::BoundSend); true } else if trait_def_id == li.copy_trait() { builtin_bounds.add(ty::BoundCopy); true - } else if trait_def_id == li.const_trait() { - builtin_bounds.add(ty::BoundConst); + } else if trait_def_id == li.freeze_trait() { + builtin_bounds.add(ty::BoundFreeze); true } else if trait_def_id == li.sized_trait() { builtin_bounds.add(ty::BoundSized); diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index de6b792032b..58a527f3501 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -538,7 +538,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { check_pointer_pat(pcx, Managed, inner, pat.id, pat.span, expected); } ast::pat_uniq(inner) => { - check_pointer_pat(pcx, Owned, inner, pat.id, pat.span, expected); + check_pointer_pat(pcx, Send, inner, pat.id, pat.span, expected); } ast::pat_region(inner) => { check_pointer_pat(pcx, Borrowed, inner, pat.id, pat.span, expected); @@ -624,7 +624,7 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, ty::ty_box(e_inner) if pointer_kind == Managed => { check_inner(e_inner); } - ty::ty_uniq(e_inner) if pointer_kind == Owned => { + ty::ty_uniq(e_inner) if pointer_kind == Send => { check_inner(e_inner); } ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => { @@ -641,7 +641,7 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, Some(expected), fmt!("%s pattern", match pointer_kind { Managed => "an @-box", - Owned => "a ~-box", + Send => "a ~-box", Borrowed => "an &-pointer" }), None); @@ -651,4 +651,4 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, } #[deriving(Eq)] -enum PointerKind { Managed, Owned, Borrowed } +enum PointerKind { Managed, Send, Borrowed } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 777b11186c6..4bebca3c9a8 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -976,7 +976,9 @@ impl<'self> LookupContext<'self> { let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {sig: fn_sig, ..bare_fn_ty}); debug!("after replacing bound regions, fty=%s", self.ty_to_str(fty)); - let self_mode = get_mode_from_explicit_self(candidate.method_ty.explicit_self); + // FIXME(#7411): We always pass self by-ref since we stuff it in the environment slot. + // Eventually that should not be the case + let self_mode = ty::ByRef; // before we only checked whether self_ty could be a subtype // of rcvr_ty; now we actually make it so (this may cause @@ -1086,16 +1088,19 @@ impl<'self> LookupContext<'self> { _ => {} } - return match candidate.method_ty.explicit_self { + let result = match candidate.method_ty.explicit_self { sty_static => { + debug!("(is relevant?) explicit self is static"); false } sty_value => { + debug!("(is relevant?) explicit self is by-value"); self.fcx.can_mk_subty(rcvr_ty, candidate.rcvr_ty).is_ok() } sty_region(_, m) => { + debug!("(is relevant?) explicit self is a region"); match ty::get(rcvr_ty).sty { ty::ty_rptr(_, mt) => { mutability_matches(mt.mutbl, m) && @@ -1107,6 +1112,7 @@ impl<'self> LookupContext<'self> { } sty_box(m) => { + debug!("(is relevant?) explicit self is a box"); match ty::get(rcvr_ty).sty { ty::ty_box(mt) => { mutability_matches(mt.mutbl, m) && @@ -1118,6 +1124,7 @@ impl<'self> LookupContext<'self> { } sty_uniq(m) => { + debug!("(is relevant?) explicit self is a unique pointer"); match ty::get(rcvr_ty).sty { ty::ty_uniq(mt) => { mutability_matches(mt.mutbl, m) && @@ -1129,6 +1136,10 @@ impl<'self> LookupContext<'self> { } }; + debug!("(is relevant?) %s", if result { "yes" } else { "no" }); + + return result; + fn mutability_matches(self_mutbl: ast::mutability, candidate_mutbl: ast::mutability) -> bool { //! True if `self_mutbl <: candidate_mutbl` @@ -1242,10 +1253,3 @@ impl<'self> LookupContext<'self> { self.tcx().sess.bug(s) } } - -pub fn get_mode_from_explicit_self(explicit_self: ast::explicit_self_) -> SelfMode { - match explicit_self { - sty_value => ty::ByCopy, - _ => ty::ByRef, - } -} diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 97e0cd4baf8..23266767124 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -213,6 +213,13 @@ impl PurityState { } } +/// Whether `check_binop` allows overloaded operators to be invoked. +#[deriving(Eq)] +enum AllowOverloadedOperatorsFlag { + AllowOverloadedOperators, + DontAllowOverloadedOperators, +} + pub struct FnCtxt { // Number of errors that had been reported when we started // checking this function. On exit, if we find that *more* errors @@ -602,6 +609,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { for ms.iter().advance |m| { check_method(ccx, *m); } + vtable::resolve_impl(ccx, it); } ast::item_trait(_, _, ref trait_methods) => { for (*trait_methods).iter().advance |trait_method| { @@ -784,10 +792,6 @@ impl FnCtxt { ast_ty_to_ty(self, self, ast_t) } - pub fn expr_to_str(&self, expr: @ast::expr) -> ~str { - expr.repr(self.tcx()) - } - pub fn pat_to_str(&self, pat: @ast::pat) -> ~str { pat.repr(self.tcx()) } @@ -796,9 +800,8 @@ impl FnCtxt { match self.inh.node_types.find(&ex.id) { Some(&t) => t, None => { - self.tcx().sess.bug( - fmt!("no type for %s in fcx %s", - self.expr_to_str(ex), self.tag())); + self.tcx().sess.bug(fmt!("no type for expr in fcx %s", + self.tag())); } } } @@ -1138,7 +1141,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, expr: @ast::expr, expected: Option<ty::t>, unifier: &fn()) { - debug!(">> typechecking %s", fcx.expr_to_str(expr)); + debug!(">> typechecking"); fn check_method_argument_types( fcx: @mut FnCtxt, @@ -1391,6 +1394,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, method_map.insert(expr.id, (*entry)); } None => { + debug!("(checking method call) failing expr is %d", expr.id); + fcx.type_error_message(expr.span, |actual| { fmt!("type `%s` does not implement any method in scope \ @@ -1487,7 +1492,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, lhs: @ast::expr, rhs: @ast::expr, // Used only in the error case - expected_result: Option<ty::t> + expected_result: Option<ty::t>, + allow_overloaded_operators: AllowOverloadedOperatorsFlag ) { let tcx = fcx.ccx.tcx; @@ -1537,8 +1543,30 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } - let result_t = check_user_binop(fcx, callee_id, expr, lhs, lhs_t, op, rhs, - expected_result); + // Check for overloaded operators if allowed. + let result_t; + if allow_overloaded_operators == AllowOverloadedOperators { + result_t = check_user_binop(fcx, + callee_id, + expr, + lhs, + lhs_t, + op, + rhs, + expected_result); + } else { + fcx.type_error_message(expr.span, + |actual| { + fmt!("binary operation %s cannot be \ + applied to type `%s`", + ast_util::binop_to_str(op), + actual) + }, + lhs_t, + None); + result_t = ty::mk_err(); + } + fcx.write_ty(expr.id, result_t); if ty::type_is_error(result_t) { fcx.write_ty(rhs.id, result_t); @@ -1704,8 +1732,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, ty::mk_closure(tcx, fn_ty_copy) }; - debug!("check_expr_fn_with_unifier %s fty=%s", - fcx.expr_to_str(expr), + debug!("check_expr_fn_with_unifier fty=%s", fcx.infcx().ty_to_str(fty)); fcx.write_ty(expr.id, fty); @@ -2229,7 +2256,15 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fcx.write_ty(id, typ); } ast::expr_binary(callee_id, op, lhs, rhs) => { - check_binop(fcx, callee_id, expr, op, lhs, rhs, expected); + check_binop(fcx, + callee_id, + expr, + op, + lhs, + rhs, + expected, + AllowOverloadedOperators); + let lhs_ty = fcx.expr_ty(lhs); let rhs_ty = fcx.expr_ty(rhs); if ty::type_is_error(lhs_ty) || @@ -2242,7 +2277,15 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } ast::expr_assign_op(callee_id, op, lhs, rhs) => { - check_binop(fcx, callee_id, expr, op, lhs, rhs, expected); + check_binop(fcx, + callee_id, + expr, + op, + lhs, + rhs, + expected, + DontAllowOverloadedOperators); + let lhs_t = fcx.expr_ty(lhs); let result_t = fcx.expr_ty(expr); demand::suptype(fcx, expr.span, result_t, lhs_t); @@ -3247,6 +3290,9 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, ast::def_self_ty(*) => { fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty"); } + ast::def_method(*) => { + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method"); + } } } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 69d4d82d15f..df81ebd48aa 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -230,7 +230,7 @@ fn constrain_bindings_in_pat(pat: @ast::pat, rcx: @mut Rcx) { } fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) { - debug!("regionck::visit_expr(e=%s)", rcx.fcx.expr_to_str(expr)); + debug!("regionck::visit_expr(e=?)"); let has_method_map = rcx.fcx.inh.method_map.contains_key(&expr.id); @@ -520,8 +520,7 @@ fn constrain_derefs(rcx: @mut Rcx, let tcx = rcx.fcx.tcx(); let r_deref_expr = ty::re_scope(deref_expr.id); for uint::range(0, derefs) |i| { - debug!("constrain_derefs(deref_expr=%s, derefd_ty=%s, derefs=%?/%?", - rcx.fcx.expr_to_str(deref_expr), + debug!("constrain_derefs(deref_expr=?, derefd_ty=%s, derefs=%?/%?", rcx.fcx.infcx().ty_to_str(derefd_ty), i, derefs); @@ -576,8 +575,7 @@ fn constrain_index(rcx: @mut Rcx, let tcx = rcx.fcx.tcx(); - debug!("constrain_index(index_expr=%s, indexed_ty=%s", - rcx.fcx.expr_to_str(index_expr), + debug!("constrain_index(index_expr=?, indexed_ty=%s", rcx.fcx.infcx().ty_to_str(indexed_ty)); let r_index_expr = ty::re_scope(index_expr.id); @@ -808,7 +806,7 @@ pub mod guarantor { * to the lifetime of its guarantor (if any). */ - debug!("guarantor::for_addr_of(base=%s)", rcx.fcx.expr_to_str(base)); + debug!("guarantor::for_addr_of(base=?)"); let guarantor = guarantor(rcx, base); link(rcx, expr.span, expr.id, guarantor); @@ -842,8 +840,7 @@ pub mod guarantor { * region pointers. */ - debug!("guarantor::for_autoref(expr=%s, autoref=%?)", - rcx.fcx.expr_to_str(expr), autoref); + debug!("guarantor::for_autoref(autoref=%?)", autoref); let mut expr_ct = categorize_unadjusted(rcx, expr); debug!(" unadjusted cat=%?", expr_ct.cat); @@ -970,7 +967,7 @@ pub mod guarantor { * `&expr`). */ - debug!("guarantor(expr=%s)", rcx.fcx.expr_to_str(expr)); + debug!("guarantor()"); match expr.node { ast::expr_unary(_, ast::deref, b) => { let cat = categorize(rcx, b); @@ -1034,7 +1031,7 @@ pub mod guarantor { } fn categorize(rcx: @mut Rcx, expr: @ast::expr) -> ExprCategorization { - debug!("categorize(expr=%s)", rcx.fcx.expr_to_str(expr)); + debug!("categorize()"); let mut expr_ct = categorize_unadjusted(rcx, expr); debug!("before adjustments, cat=%?", expr_ct.cat); @@ -1086,7 +1083,7 @@ pub mod guarantor { fn categorize_unadjusted(rcx: @mut Rcx, expr: @ast::expr) -> ExprCategorizationType { - debug!("categorize_unadjusted(expr=%s)", rcx.fcx.expr_to_str(expr)); + debug!("categorize_unadjusted()"); let guarantor = { if rcx.fcx.inh.method_map.contains_key(&expr.id) { diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index 160737142c8..fb79a7c3c99 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -112,7 +112,7 @@ pub fn replace_bound_regions_in_fn_sig( // kinds of types. This had already caused me several // bugs so I decided to switch over. do ty::fold_regions(tcx, *ty) |r, in_fn| { - if !in_fn { isr = append_isr(isr, to_r, r); } + if !in_fn { isr = append_isr(isr, |br| to_r(br), r); } r }; @@ -211,18 +211,18 @@ pub fn relate_nested_regions( match ty::get(ty).sty { ty::ty_rptr(r, ref mt) | ty::ty_evec(ref mt, ty::vstore_slice(r)) => { - relate(*the_stack, r, relate_op); + relate(*the_stack, r, |x,y| relate_op(x,y)); the_stack.push(r); - walk_ty(tcx, the_stack, mt.ty, relate_op); + walk_ty(tcx, the_stack, mt.ty, |x,y| relate_op(x,y)); the_stack.pop(); } _ => { ty::fold_regions_and_ty( tcx, ty, - |r| { relate(*the_stack, r, relate_op); r }, - |t| { walk_ty(tcx, the_stack, t, relate_op); t }, - |t| { walk_ty(tcx, the_stack, t, relate_op); t }); + |r| { relate( *the_stack, r, |x,y| relate_op(x,y)); r }, + |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t }, + |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t }); } } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index bd78e9cc5fb..0bf20f9fbcb 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -17,8 +17,8 @@ use middle::typeck::check::{structurally_resolved_type}; use middle::typeck::infer::fixup_err_to_str; use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; use middle::typeck::infer; -use middle::typeck::{CrateCtxt, vtable_origin, vtable_param, vtable_res}; -use middle::typeck::vtable_static; +use middle::typeck::{CrateCtxt, vtable_origin, vtable_res}; +use middle::typeck::{vtable_static, vtable_param, vtable_self}; use middle::subst::Subst; use util::common::indenter; use util::ppaux::tys_to_str; @@ -90,6 +90,7 @@ fn lookup_vtables(vcx: &VtableContext, let mut i = 0u; for substs.tps.iter().advance |ty| { // ty is the value supplied for the type parameter A... + let mut param_result = ~[]; for ty::each_bound_trait_and_supertraits( tcx, type_param_defs[i].bounds) |trait_ref| @@ -106,7 +107,7 @@ fn lookup_vtables(vcx: &VtableContext, debug!("after subst: %s", trait_ref.repr(tcx)); match lookup_vtable(vcx, location_info, *ty, &trait_ref, is_early) { - Some(vtable) => result.push(vtable), + Some(vtable) => param_result.push(vtable), None => { vcx.tcx().sess.span_fatal( location_info.span, @@ -117,6 +118,7 @@ fn lookup_vtables(vcx: &VtableContext, } } } + result.push(@param_result); i += 1u; } debug!("lookup_vtables result(\ @@ -237,6 +239,17 @@ fn lookup_vtable(vcx: &VtableContext, } } + ty::ty_self(trait_id) => { + debug!("trying to find %? vtable for type %?", + trait_ref.def_id, trait_id); + + if trait_id == trait_ref.def_id { + let vtable = vtable_self(trait_id); + debug!("found self vtable: %?", vtable); + return Some(vtable); + } + } + _ => { let mut found = ~[]; @@ -467,6 +480,12 @@ pub fn location_info_for_expr(expr: @ast::expr) -> LocationInfo { id: expr.id } } +pub fn location_info_for_item(item: @ast::item) -> LocationInfo { + LocationInfo { + span: item.span, + id: item.id + } +} pub fn early_resolve_expr(ex: @ast::expr, fcx: @mut FnCtxt, @@ -583,7 +602,8 @@ pub fn early_resolve_expr(ex: @ast::expr, // vtable (that is: "ex has vtable // <vtable>") if !is_early { - insert_vtables(fcx, ex.id, @~[vtable]); + insert_vtables(fcx, ex.id, + @~[@~[vtable]]); } } None => { @@ -650,6 +670,27 @@ fn resolve_expr(ex: @ast::expr, visit::visit_expr(ex, (fcx, v)); } +pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { + let def_id = ast_util::local_def(impl_item.id); + match ty::impl_trait_ref(ccx.tcx, def_id) { + None => {}, + Some(trait_ref) => { + let infcx = infer::new_infer_ctxt(ccx.tcx); + let vcx = VtableContext { ccx: ccx, infcx: infcx }; + let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id); + + let vtbls = lookup_vtables(&vcx, + &location_info_for_item(impl_item), + *trait_def.generics.type_param_defs, + &trait_ref.substs, + false); + + // FIXME(#7450): Doesn't work cross crate + ccx.vtable_map.insert(impl_item.id, vtbls); + } + } +} + // Detect points where a trait-bounded type parameter is // instantiated, resolve the impls for the parameters. pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::blk) { diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index dd9d68beb1f..e2efdc51fca 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -20,7 +20,8 @@ use middle::typeck::check::{FnCtxt, SelfInfo}; use middle::typeck::infer::{force_all, resolve_all, resolve_region}; use middle::typeck::infer::resolve_type; use middle::typeck::infer; -use middle::typeck::{vtable_origin, vtable_static, vtable_param}; +use middle::typeck::{vtable_res, vtable_origin}; +use middle::typeck::{vtable_static, vtable_param, vtable_self}; use middle::typeck::method_map_entry; use middle::typeck::write_substs_to_tcx; use middle::typeck::write_ty_to_tcx; @@ -84,7 +85,7 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { match fcx.inh.vtable_map.find(&id) { None => {} Some(origins) => { - let r_origins = @origins.map(|o| resolve_origin(fcx, sp, o)); + let r_origins = resolve_origins(fcx, sp, *origins); let vtable_map = fcx.ccx.vtable_map; vtable_map.insert(id, r_origins); debug!("writeback::resolve_vtable_map_entry(id=%d, vtables=%?)", @@ -92,18 +93,26 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { } } + fn resolve_origins(fcx: @mut FnCtxt, sp: span, + vtbls: vtable_res) -> vtable_res { + @vtbls.map(|os| @os.map(|o| resolve_origin(fcx, sp, o))) + } + fn resolve_origin(fcx: @mut FnCtxt, sp: span, origin: &vtable_origin) -> vtable_origin { match origin { &vtable_static(def_id, ref tys, origins) => { let r_tys = resolve_type_vars_in_types(fcx, sp, *tys); - let r_origins = @origins.map(|o| resolve_origin(fcx, sp, o)); + let r_origins = resolve_origins(fcx, sp, origins); vtable_static(def_id, r_tys, r_origins) } &vtable_param(n, b) => { vtable_param(n, b) } + &vtable_self(def_id) => { + vtable_self(def_id) + } } } } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 6da9895534b..a537d0cc72c 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -17,7 +17,7 @@ use core::prelude::*; use metadata::csearch::{each_path, get_impl_trait}; -use metadata::csearch::{get_impls_for_mod}; +use metadata::csearch; use metadata::cstore::{CStore, iter_crate_data}; use metadata::decoder::{dl_def, dl_field, dl_impl}; use middle::resolve::{Impl, MethodInfo}; @@ -788,7 +788,7 @@ impl CoherenceChecker { `%s` to impl", provided_method.method_info .ident.repr(self.crate_context.tcx)); - vec::push(all_methods, provided_method.method_info); + all_methods.push(provided_method.method_info); } } } @@ -855,92 +855,81 @@ impl CoherenceChecker { // External crate handling - pub fn add_impls_for_module(&self, - impls_seen: &mut HashSet<def_id>, - crate_store: @mut CStore, - module_def_id: def_id) { - let implementations = get_impls_for_mod(crate_store, - module_def_id, - None); - for implementations.iter().advance |implementation| { - debug!("coherence: adding impl from external crate: %s", - ty::item_path_str(self.crate_context.tcx, - implementation.did)); - - // Make sure we don't visit the same implementation - // multiple times. - if !impls_seen.insert(implementation.did) { - // Skip this one. - loop; - } - // Good. Continue. + pub fn add_external_impl(&self, + impls_seen: &mut HashSet<def_id>, + crate_store: @mut CStore, + impl_def_id: def_id) { + let implementation = csearch::get_impl(crate_store, impl_def_id); - let self_type = lookup_item_type(self.crate_context.tcx, - implementation.did); - let associated_traits = get_impl_trait(self.crate_context.tcx, - implementation.did); + debug!("coherence: adding impl from external crate: %s", + ty::item_path_str(self.crate_context.tcx, implementation.did)); - // Do a sanity check to make sure that inherent methods have base - // types. + // Make sure we don't visit the same implementation multiple times. + if !impls_seen.insert(implementation.did) { + // Skip this one. + return + } + // Good. Continue. - if associated_traits.is_none() { - match get_base_type_def_id(self.inference_context, - dummy_sp(), - self_type.ty) { - None => { - let session = self.crate_context.tcx.sess; - session.bug(fmt!( - "no base type for external impl \ - with no trait: %s (type %s)!", - session.str_of(implementation.ident), - ty_to_str(self.crate_context.tcx,self_type.ty))); - } - Some(_) => { - // Nothing to do. - } + let self_type = lookup_item_type(self.crate_context.tcx, + implementation.did); + let associated_traits = get_impl_trait(self.crate_context.tcx, + implementation.did); + + // Do a sanity check to make sure that inherent methods have base + // types. + if associated_traits.is_none() { + match get_base_type_def_id(self.inference_context, + dummy_sp(), + self_type.ty) { + None => { + let session = self.crate_context.tcx.sess; + session.bug(fmt!("no base type for external impl with no \ + trait: %s (type %s)!", + session.str_of(implementation.ident), + ty_to_str(self.crate_context.tcx, + self_type.ty))); } + Some(_) => {} // Nothing to do. } + } - let mut implementation = *implementation; - - // Record all the trait methods. - for associated_traits.iter().advance |trait_ref| { - self.instantiate_default_methods(implementation.did, - &**trait_ref); - // Could we avoid these copies when we don't need them? - let mut methods = /*bad?*/ copy implementation.methods; - self.add_provided_methods_to_impl( - &mut methods, - &trait_ref.def_id, - &implementation.did); - implementation = @Impl { methods: methods, - .. *implementation }; - - - self.add_trait_method(trait_ref.def_id, implementation); - } + // Record all the trait methods. + let mut implementation = @implementation; + for associated_traits.iter().advance |trait_ref| { + self.instantiate_default_methods(implementation.did, + *trait_ref); + + // XXX(sully): We could probably avoid this copy if there are no + // default methods. + let mut methods = copy implementation.methods; + self.add_provided_methods_to_impl(&mut methods, + &trait_ref.def_id, + &implementation.did); + implementation = @Impl { + methods: methods, + ..*implementation + }; - // Add the implementation to the mapping from - // implementation to base type def ID, if there is a base - // type for this implementation. + self.add_trait_method(trait_ref.def_id, implementation); + } - match get_base_type_def_id(self.inference_context, - dummy_sp(), - self_type.ty) { - None => { - // Nothing to do. + // Add the implementation to the mapping from implementation to base + // type def ID, if there is a base type for this implementation. + match get_base_type_def_id(self.inference_context, + dummy_sp(), + self_type.ty) { + None => {} // Nothing to do. + Some(base_type_def_id) => { + // inherent methods apply to `impl Type` but not + // `impl Trait for Type`: + if associated_traits.is_none() { + self.add_inherent_method(base_type_def_id, + implementation); } - Some(base_type_def_id) => { - // inherent methods apply to `impl Type` but not - // `impl Trait for Type`: - if associated_traits.is_none() { - self.add_inherent_method(base_type_def_id, - implementation); - } - self.base_type_def_ids.insert(implementation.did, - base_type_def_id); - } + self.base_type_def_ids.insert(implementation.did, + base_type_def_id); } } } @@ -952,22 +941,14 @@ impl CoherenceChecker { let crate_store = self.crate_context.tcx.sess.cstore; do iter_crate_data(crate_store) |crate_number, _crate_metadata| { - self.add_impls_for_module(&mut impls_seen, - crate_store, - def_id { crate: crate_number, - node: 0 }); - for each_path(crate_store, crate_number) |_, def_like, _| { match def_like { - dl_def(def_mod(def_id)) => { - self.add_impls_for_module(&mut impls_seen, - crate_store, - def_id); - } - dl_def(_) | dl_impl(_) | dl_field => { - // Skip this. - loop; + dl_impl(def_id) => { + self.add_external_impl(&mut impls_seen, + crate_store, + def_id) } + dl_def(_) | dl_field => loop, // Skip this. } } } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 0e118adb8f4..5065a475a40 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -81,10 +81,20 @@ pub fn collect_item_types(ccx: @mut CrateCtxt, crate: &ast::crate) { }))); } -impl CrateCtxt { +pub trait ToTy { fn to_ty<RS:region_scope + Copy + 'static>( - &self, rs: &RS, ast_ty: &ast::Ty) -> ty::t - { + &self, + rs: &RS, + ast_ty: &ast::Ty) + -> ty::t; +} + +impl ToTy for CrateCtxt { + fn to_ty<RS:region_scope + Copy + 'static>( + &self, + rs: &RS, + ast_ty: &ast::Ty) + -> ty::t { ast_ty_to_ty(self, rs, ast_ty) } } @@ -1165,7 +1175,7 @@ pub fn ty_generics(ccx: &CrateCtxt, * enum consisting of a newtyped Ty or a region) to ty's * notion of ty param bounds, which can either be user-defined * traits, or one of the four built-in traits (formerly known - * as kinds): Const, Copy, and Send. + * as kinds): Freeze, Copy, and Send. */ let mut param_bounds = ty::ParamBounds { diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 884f72b57f0..7a4ea0999ef 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -64,7 +64,8 @@ use middle::typeck::infer::glb::Glb; use middle::typeck::infer::lub::Lub; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; -use middle::typeck::infer::{cres, InferCtxt, ures}; +use middle::typeck::infer::unify::{InferCtxtMethods, UnifyInferCtxtMethods}; +use middle::typeck::infer::{InferCtxt, cres, ures}; use util::common::indent; use core::result::{iter_vec2, map_vec2}; diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs index 658fd67ee58..ed19310d5d6 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/typeck/infer/lattice.rs @@ -71,15 +71,53 @@ impl LatticeValue for ty::t { } } -impl CombineFields { - pub fn var_sub_var<T:Copy + InferStr + LatticeValue, - V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>(&self, - a_id: - V, - b_id: - V) - -> - ures { +pub trait CombineFieldsLatticeMethods { + fn var_sub_var<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>(&self, + a_id: V, + b_id: V) + -> ures; + /// make variable a subtype of T + fn var_sub_t<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>( + &self, + a_id: V, + b: T) + -> ures; + fn t_sub_var<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>( + &self, + a: T, + b_id: V) + -> ures; + fn merge_bnd<T:Copy + InferStr + LatticeValue>( + &self, + a: &Bound<T>, + b: &Bound<T>, + lattice_op: LatticeOp<T>) + -> cres<Bound<T>>; + fn set_var_to_merged_bounds<T:Copy + InferStr + LatticeValue, + V:Copy+Eq+ToStr+Vid+UnifyVid<Bounds<T>>>( + &self, + v_id: V, + a: &Bounds<T>, + b: &Bounds<T>, + rank: uint) + -> ures; + fn bnds<T:Copy + InferStr + LatticeValue>( + &self, + a: &Bound<T>, + b: &Bound<T>) + -> ures; +} + +impl CombineFieldsLatticeMethods for CombineFields { + fn var_sub_var<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>( + &self, + a_id: V, + b_id: V) + -> ures { /*! * * Make one variable a subtype of another variable. This is a @@ -127,12 +165,12 @@ impl CombineFields { } /// make variable a subtype of T - pub fn var_sub_t<T:Copy + InferStr + LatticeValue, - V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>(&self, - a_id: V, - b: T) - -> ures - { + fn var_sub_t<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>( + &self, + a_id: V, + b: T) + -> ures { /*! * * Make a variable (`a_id`) a subtype of the concrete type `b` */ @@ -151,12 +189,12 @@ impl CombineFields { a_id, a_bounds, b_bounds, node_a.rank) } - pub fn t_sub_var<T:Copy + InferStr + LatticeValue, - V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>(&self, - a: T, - b_id: V) - -> ures - { + fn t_sub_var<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>( + &self, + a: T, + b_id: V) + -> ures { /*! * * Make a concrete type (`a`) a subtype of the variable `b_id` */ @@ -175,12 +213,12 @@ impl CombineFields { b_id, a_bounds, b_bounds, node_b.rank) } - pub fn merge_bnd<T:Copy + InferStr + LatticeValue>(&self, - a: &Bound<T>, - b: &Bound<T>, - lattice_op: - LatticeOp<T>) - -> cres<Bound<T>> { + fn merge_bnd<T:Copy + InferStr + LatticeValue>( + &self, + a: &Bound<T>, + b: &Bound<T>, + lattice_op: LatticeOp<T>) + -> cres<Bound<T>> { /*! * * Combines two bounds into a more general bound. */ @@ -202,14 +240,14 @@ impl CombineFields { } } - pub fn set_var_to_merged_bounds<T:Copy + InferStr + LatticeValue, - V:Copy+Eq+ToStr+Vid+UnifyVid<Bounds<T>>>( - &self, - v_id: V, - a: &Bounds<T>, - b: &Bounds<T>, - rank: uint) - -> ures { + fn set_var_to_merged_bounds<T:Copy + InferStr + LatticeValue, + V:Copy+Eq+ToStr+Vid+UnifyVid<Bounds<T>>>( + &self, + v_id: V, + a: &Bounds<T>, + b: &Bounds<T>, + rank: uint) + -> ures { /*! * * Updates the bounds for the variable `v_id` to be the intersection @@ -264,10 +302,10 @@ impl CombineFields { uok() } - pub fn bnds<T:Copy + InferStr + LatticeValue>(&self, - a: &Bound<T>, - b: &Bound<T>) - -> ures { + fn bnds<T:Copy + InferStr + LatticeValue>(&self, + a: &Bound<T>, + b: &Bound<T>) + -> ures { debug!("bnds(%s <: %s)", a.inf_str(self.infcx), b.inf_str(self.infcx)); let _r = indenter(); diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 1bfe452f25e..3e2d4a71dfb 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -582,7 +582,7 @@ impl InferCtxt { debug!("commit()"); do indent { - let r = self.try(f); + let r = self.try(|| f()); self.ty_var_bindings.bindings.truncate(0); self.int_var_bindings.bindings.truncate(0); @@ -836,6 +836,6 @@ pub fn fold_regions_in_sig( fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnSig { do ty::fold_sig(fn_sig) |t| { - ty::fold_regions(tcx, t, fldr) + ty::fold_regions(tcx, t, |r, in_fn| fldr(r, in_fn)) } } diff --git a/src/librustc/middle/typeck/infer/region_inference.rs b/src/librustc/middle/typeck/infer/region_inference.rs index 0aad161a678..4380711b78e 100644 --- a/src/librustc/middle/typeck/infer/region_inference.rs +++ b/src/librustc/middle/typeck/infer/region_inference.rs @@ -548,43 +548,18 @@ use util::ppaux::note_and_explain_region; use core::cell::Cell; use core::hashmap::{HashMap, HashSet}; -use core::to_bytes; use core::uint; use core::vec; use syntax::codemap::span; use syntax::ast; -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] enum Constraint { ConstrainVarSubVar(RegionVid, RegionVid), ConstrainRegSubVar(Region, RegionVid), ConstrainVarSubReg(RegionVid, Region) } -impl to_bytes::IterBytes for Constraint { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - ConstrainVarSubVar(ref v0, ref v1) => { - 0u8.iter_bytes(lsb0, f) && - v0.iter_bytes(lsb0, f) && - v1.iter_bytes(lsb0, f) - } - - ConstrainRegSubVar(ref ra, ref va) => { - 1u8.iter_bytes(lsb0, f) && - ra.iter_bytes(lsb0, f) && - va.iter_bytes(lsb0, f) - } - - ConstrainVarSubReg(ref va, ref ra) => { - 2u8.iter_bytes(lsb0, f) && - va.iter_bytes(lsb0, f) && - ra.iter_bytes(lsb0, f) - } - } - } -} - #[deriving(Eq, IterBytes)] struct TwoRegions { a: Region, diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index ab52ef36978..1311907eed2 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -54,7 +54,7 @@ use middle::ty; use middle::typeck::infer::{Bounds, cyclic_ty, fixup_err, fres, InferCtxt}; use middle::typeck::infer::{region_var_bound_by_region_var, unresolved_ty}; use middle::typeck::infer::to_str::InferStr; -use middle::typeck::infer::unify::Root; +use middle::typeck::infer::unify::{Root, UnifyInferCtxtMethods}; use util::common::{indent, indenter}; use util::ppaux::ty_to_str; diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 4462d43015c..eb912aa2dda 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -18,6 +18,7 @@ use middle::typeck::infer::combine::*; use middle::typeck::infer::cres; use middle::typeck::infer::glb::Glb; use middle::typeck::infer::InferCtxt; +use middle::typeck::infer::lattice::CombineFieldsLatticeMethods; use middle::typeck::infer::lub::Lub; use middle::typeck::infer::to_str::InferStr; use util::common::{indent, indenter}; diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index 371d389f712..a185633a7ac 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -40,9 +40,31 @@ pub trait UnifyVid<T> { -> &'v mut ValsAndBindings<Self, T>; } -impl InferCtxt { - pub fn get<T:Copy, V:Copy+Eq+Vid+UnifyVid<T>>(&mut self, vid: V) - -> Node<V, T> { +pub trait UnifyInferCtxtMethods { + fn get<T:Copy, + V:Copy + Eq + Vid + UnifyVid<T>>( + &mut self, + vid: V) + -> Node<V, T>; + fn set<T:Copy + InferStr, + V:Copy + Vid + ToStr + UnifyVid<T>>( + &mut self, + vid: V, + new_v: VarValue<V, T>); + fn unify<T:Copy + InferStr, + V:Copy + Vid + ToStr + UnifyVid<T>>( + &mut self, + node_a: &Node<V, T>, + node_b: &Node<V, T>) + -> (V, uint); +} + +impl UnifyInferCtxtMethods for InferCtxt { + fn get<T:Copy, + V:Copy + Eq + Vid + UnifyVid<T>>( + &mut self, + vid: V) + -> Node<V, T> { /*! * * Find the root node for `vid`. This uses the standard @@ -84,10 +106,11 @@ impl InferCtxt { } } - pub fn set<T:Copy + InferStr, - V:Copy + Vid + ToStr + UnifyVid<T>>(&mut self, - vid: V, - new_v: VarValue<V, T>) { + fn set<T:Copy + InferStr, + V:Copy + Vid + ToStr + UnifyVid<T>>( + &mut self, + vid: V, + new_v: VarValue<V, T>) { /*! * * Sets the value for `vid` to `new_v`. `vid` MUST be a root node! @@ -102,11 +125,12 @@ impl InferCtxt { vb.vals.insert(vid.to_uint(), new_v); } - pub fn unify<T:Copy + InferStr, - V:Copy + Vid + ToStr + UnifyVid<T>>(&mut self, - node_a: &Node<V, T>, - node_b: &Node<V, T>) - -> (V, uint) { + fn unify<T:Copy + InferStr, + V:Copy + Vid + ToStr + UnifyVid<T>>( + &mut self, + node_a: &Node<V, T>, + node_b: &Node<V, T>) + -> (V, uint) { // Rank optimization: if you don't know what it is, check // out <http://en.wikipedia.org/wiki/Disjoint-set_data_structure> @@ -155,14 +179,31 @@ pub fn mk_err<T:SimplyUnifiable>(a_is_expected: bool, } } -impl InferCtxt { - pub fn simple_vars<T:Copy+Eq+InferStr+SimplyUnifiable, - V:Copy+Eq+Vid+ToStr+UnifyVid<Option<T>>>(&mut self, - a_is_expected: - bool, - a_id: V, - b_id: V) - -> ures { +pub trait InferCtxtMethods { + fn simple_vars<T:Copy + Eq + InferStr + SimplyUnifiable, + V:Copy + Eq + Vid + ToStr + UnifyVid<Option<T>>>( + &mut self, + a_is_expected: bool, + a_id: V, + b_id: V) + -> ures; + fn simple_var_t<T:Copy + Eq + InferStr + SimplyUnifiable, + V:Copy + Eq + Vid + ToStr + UnifyVid<Option<T>>>( + &mut self, + a_is_expected: bool, + a_id: V, + b: T) + -> ures; +} + +impl InferCtxtMethods for InferCtxt { + fn simple_vars<T:Copy + Eq + InferStr + SimplyUnifiable, + V:Copy + Eq + Vid + ToStr + UnifyVid<Option<T>>>( + &mut self, + a_is_expected: bool, + a_id: V, + b_id: V) + -> ures { /*! * * Unifies two simple variables. Because simple variables do @@ -194,13 +235,13 @@ impl InferCtxt { return uok(); } - pub fn simple_var_t<T:Copy+Eq+InferStr+SimplyUnifiable, - V:Copy+Eq+Vid+ToStr+UnifyVid<Option<T>>>(&mut self, - a_is_expected - : bool, - a_id: V, - b: T) - -> ures { + fn simple_var_t<T:Copy + Eq + InferStr + SimplyUnifiable, + V:Copy + Eq + Vid + ToStr + UnifyVid<Option<T>>>( + &mut self, + a_is_expected: bool, + a_id: V, + b: T) + -> ures { /*! * * Sets the value of the variable `a_id` to `b`. Because diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index d834998d4ee..98f7af4bfd4 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -135,8 +135,9 @@ pub struct method_map_entry { // of the method to be invoked pub type method_map = @mut HashMap<ast::node_id, method_map_entry>; +pub type vtable_param_res = @~[vtable_origin]; // Resolutions for bounds of all parameters, left to right, for a given path. -pub type vtable_res = @~[vtable_origin]; +pub type vtable_res = @~[vtable_param_res]; pub enum vtable_origin { /* @@ -154,7 +155,12 @@ pub enum vtable_origin { The first uint is the param number (identifying T in the example), and the second is the bound number (identifying baz) */ - vtable_param(uint, uint) + vtable_param(uint, uint), + + /* + Dynamic vtable, comes from self. + */ + vtable_self(ast::def_id) } impl Repr for vtable_origin { @@ -171,6 +177,9 @@ impl Repr for vtable_origin { vtable_param(x, y) => { fmt!("vtable_param(%?, %?)", x, y) } + vtable_self(def_id) => { + fmt!("vtable_self(%?)", def_id) + } } } } diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index a27838b5d11..957cf02ed77 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -80,6 +80,7 @@ pub mod middle { pub mod moves; pub mod entry; pub mod effect; + pub mod reachable; } pub mod front { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 3194df269c0..548eebaea0b 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -488,7 +488,9 @@ pub fn parameterized(cx: ctxt, } }; - strs += vec::map(tps, |t| ty_to_str(cx, *t)); + for tps.iter().advance |t| { + strs.push(ty_to_str(cx, *t)) + } if strs.len() > 0u { fmt!("%s<%s>", base, strs.connect(",")) @@ -575,8 +577,8 @@ impl Repr for ty::ParamBounds { res.push(match b { ty::BoundCopy => ~"Copy", ty::BoundStatic => ~"'static", - ty::BoundOwned => ~"Owned", - ty::BoundConst => ~"Const", + ty::BoundSend => ~"Send", + ty::BoundFreeze => ~"Freeze", ty::BoundSized => ~"Sized", }); } @@ -781,8 +783,8 @@ impl UserString for ty::BuiltinBound { match *self { ty::BoundCopy => ~"Copy", ty::BoundStatic => ~"'static", - ty::BoundOwned => ~"Owned", - ty::BoundConst => ~"Const", + ty::BoundSend => ~"Send", + ty::BoundFreeze => ~"Freeze", ty::BoundSized => ~"Sized", } } diff --git a/src/librustdoc/astsrv.rs b/src/librustdoc/astsrv.rs index 3775aafb569..27ab3aca020 100644 --- a/src/librustdoc/astsrv.rs +++ b/src/librustdoc/astsrv.rs @@ -99,7 +99,7 @@ fn act(po: &Port<Msg>, source: @str, parse: Parser) { } } -pub fn exec<T:Owned>( +pub fn exec<T:Send>( srv: Srv, f: ~fn(ctxt: Ctxt) -> T ) -> T { diff --git a/src/librustdoc/attr_pass.rs b/src/librustdoc/attr_pass.rs index 1c34007c99d..a2e50d37fb6 100644 --- a/src/librustdoc/attr_pass.rs +++ b/src/librustdoc/attr_pass.rs @@ -101,7 +101,7 @@ fn fold_item( } } -fn parse_item_attrs<T:Owned>( +fn parse_item_attrs<T:Send>( srv: astsrv::Srv, id: doc::AstId, parse_attrs: ~fn(a: ~[ast::attribute]) -> T) -> T { diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index 6622ea1551b..e9deef6b223 100644 --- a/src/librustdoc/markdown_pass.rs +++ b/src/librustdoc/markdown_pass.rs @@ -152,7 +152,7 @@ pub fn header_kind(doc: doc::ItemTag) -> ~str { ~"Function" } doc::ConstTag(_) => { - ~"Const" + ~"Freeze" } doc::EnumTag(_) => { ~"Enum" @@ -192,11 +192,11 @@ pub fn header_name(doc: doc::ItemTag) -> ~str { let mut trait_part = ~""; for doc.trait_types.iter().enumerate().advance |(i, trait_type)| { if i == 0 { - trait_part += " of "; + trait_part.push_str(" of "); } else { - trait_part += ", "; + trait_part.push_str(", "); } - trait_part += *trait_type; + trait_part.push_str(*trait_type); } fmt!("%s for %s%s", trait_part, *self_ty, bounds) } @@ -786,7 +786,7 @@ mod test { #[test] fn should_write_const_header() { let markdown = render(~"static a: bool = true;"); - assert!(markdown.contains("## Const `a`\n\n")); + assert!(markdown.contains("## Freeze `a`\n\n")); } #[test] diff --git a/src/librustdoc/markdown_writer.rs b/src/librustdoc/markdown_writer.rs index 35315276326..a093824e453 100644 --- a/src/librustdoc/markdown_writer.rs +++ b/src/librustdoc/markdown_writer.rs @@ -130,7 +130,7 @@ fn generic_writer(process: ~fn(markdown: ~str)) -> Writer { let mut keep_going = true; while keep_going { match po.recv() { - Write(s) => markdown += s, + Write(s) => markdown.push_str(s), Done => keep_going = false } } @@ -214,7 +214,7 @@ fn future_writer() -> (Writer, future::Future<~str>) { let mut res = ~""; loop { match port.recv() { - Write(s) => res += s, + Write(s) => res.push_str(s), Done => break } } diff --git a/src/librustdoc/page_pass.rs b/src/librustdoc/page_pass.rs index 584e6ccc887..35a433ec9de 100644 --- a/src/librustdoc/page_pass.rs +++ b/src/librustdoc/page_pass.rs @@ -70,7 +70,7 @@ fn make_doc_from_pages(page_port: &PagePort) -> doc::Doc { loop { let val = page_port.recv(); if val.is_some() { - pages += [val.unwrap()]; + pages.push(val.unwrap()); } else { break; } diff --git a/src/librusti/rusti.rc b/src/librusti/rusti.rc new file mode 100644 index 00000000000..5873f361ad7 --- /dev/null +++ b/src/librusti/rusti.rc @@ -0,0 +1,666 @@ +// Copyright 2012-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. + +/*! + * rusti - A REPL using the JIT backend + * + * Rusti works by serializing state between lines of input. This means that each + * line can be run in a separate task, and the only limiting factor is that all + * local bound variables are encodable. + * + * This is accomplished by feeding in generated input to rustc for execution in + * the JIT compiler. Currently input actually gets fed in three times to get + * information about the program. + * + * - Pass #1 + * In this pass, the input is simply thrown at the parser and the input comes + * back. This validates the structure of the program, and at this stage the + * global items (fns, structs, impls, traits, etc.) are filtered from the + * input into the "global namespace". These declarations shadow all previous + * declarations of an item by the same name. + * + * - Pass #2 + * After items have been stripped, the remaining input is passed to rustc + * along with all local variables declared (initialized to nothing). This pass + * runs up to typechecking. From this, we can learn about the types of each + * bound variable, what variables are bound, and also ensure that all the + * types are encodable (the input can actually be run). + * + * - Pass #3 + * Finally, a program is generated to deserialize the local variable state, + * run the code input, and then reserialize all bindings back into a local + * hash map. Once this code runs, the input has fully been run and the REPL + * waits for new input. + * + * Encoding/decoding is done with EBML, and there is simply a map of ~str -> + * ~[u8] maintaining the values of each local binding (by name). + */ + +#[link(name = "rusti", + vers = "0.7-pre", + uuid = "7fb5bf52-7d45-4fee-8325-5ad3311149fc", + url = "https://github.com/mozilla/rust/tree/master/src/rusti")]; + +#[license = "MIT/ASL2"]; +#[crate_type = "lib"]; + +extern mod extra; +extern mod rustc; +extern mod syntax; + +use std::{libc, io, os, task, vec}; +use std::cell::Cell; +use extra::rl; + +use rustc::driver::{driver, session}; +use syntax::{ast, diagnostic}; +use syntax::ast_util::*; +use syntax::parse::token; +use syntax::print::pprust; + +use program::Program; +use utils::*; + +mod program; +pub mod utils; + +/** + * A structure shared across REPL instances for storing history + * such as statements and view items. I wish the AST was sendable. + */ +pub struct Repl { + prompt: ~str, + binary: ~str, + running: bool, + lib_search_paths: ~[~str], + + program: Program, +} + +// Action to do after reading a :command +enum CmdAction { + action_none, + action_run_line(~str), +} + +/// Run an input string in a Repl, returning the new Repl. +fn run(mut repl: Repl, input: ~str) -> Repl { + // Build some necessary rustc boilerplate for compiling things + let binary = repl.binary.to_managed(); + let options = @session::options { + crate_type: session::unknown_crate, + binary: binary, + addl_lib_search_paths: @mut repl.lib_search_paths.map(|p| Path(*p)), + jit: true, + .. copy *session::basic_options() + }; + // Because we assume that everything is encodable (and assert so), add some + // extra helpful information if the error crops up. Otherwise people are + // bound to be very confused when they find out code is running that they + // never typed in... + let sess = driver::build_session(options, |cm, msg, lvl| { + diagnostic::emit(cm, msg, lvl); + if msg.contains("failed to find an implementation of trait") && + msg.contains("extra::serialize::Encodable") { + diagnostic::emit(cm, + "Currrently rusti serializes bound locals between \ + different lines of input. This means that all \ + values of local variables need to be encodable, \ + and this type isn't encodable", + diagnostic::note); + } + }); + let intr = token::get_ident_interner(); + + // + // Stage 1: parse the input and filter it into the program (as necessary) + // + debug!("parsing: %s", input); + let crate = parse_input(sess, binary, input); + let mut to_run = ~[]; // statements to run (emitted back into code) + let new_locals = @mut ~[]; // new locals being defined + let mut result = None; // resultant expression (to print via pp) + do find_main(crate, sess) |blk| { + // Fish out all the view items, be sure to record 'extern mod' items + // differently beause they must appear before all 'use' statements + for blk.node.view_items.iter().advance |vi| { + let s = do with_pp(intr) |pp, _| { + pprust::print_view_item(pp, *vi); + }; + match vi.node { + ast::view_item_extern_mod(*) => { + repl.program.record_extern(s); + } + ast::view_item_use(*) => { repl.program.record_view_item(s); } + } + } + + // Iterate through all of the block's statements, inserting them into + // the correct portions of the program + for blk.node.stmts.iter().advance |stmt| { + let s = do with_pp(intr) |pp, _| { pprust::print_stmt(pp, *stmt); }; + match stmt.node { + ast::stmt_decl(d, _) => { + match d.node { + ast::decl_item(it) => { + let name = sess.str_of(it.ident); + match it.node { + // Structs are treated specially because to make + // them at all usable they need to be decorated + // with #[deriving(Encoable, Decodable)] + ast::item_struct(*) => { + repl.program.record_struct(name, s); + } + // Item declarations are hoisted out of main() + _ => { repl.program.record_item(name, s); } + } + } + + // Local declarations must be specially dealt with, + // record all local declarations for use later on + ast::decl_local(l) => { + let mutbl = l.node.is_mutbl; + do each_binding(l) |path, _| { + let s = do with_pp(intr) |pp, _| { + pprust::print_path(pp, path, false); + }; + new_locals.push((s, mutbl)); + } + to_run.push(s); + } + } + } + + // run statements with expressions (they have effects) + ast::stmt_mac(*) | ast::stmt_semi(*) | ast::stmt_expr(*) => { + to_run.push(s); + } + } + } + result = do blk.node.expr.map_consume |e| { + do with_pp(intr) |pp, _| { pprust::print_expr(pp, e); } + }; + } + // return fast for empty inputs + if to_run.len() == 0 && result.is_none() { + return repl; + } + + // + // Stage 2: run everything up to typeck to learn the types of the new + // variables introduced into the program + // + info!("Learning about the new types in the program"); + repl.program.set_cache(); // before register_new_vars (which changes them) + let input = to_run.connect("\n"); + let test = repl.program.test_code(input, &result, *new_locals); + debug!("testing with ^^^^^^ %?", (||{ println(test) })()); + let dinput = driver::str_input(test.to_managed()); + let cfg = driver::build_configuration(sess, binary, &dinput); + let outputs = driver::build_output_filenames(&dinput, &None, &None, [], sess); + let (crate, tcx) = driver::compile_upto(sess, copy cfg, &dinput, + driver::cu_typeck, Some(outputs)); + // Once we're typechecked, record the types of all local variables defined + // in this input + do find_main(crate.expect("crate after cu_typeck"), sess) |blk| { + repl.program.register_new_vars(blk, tcx.expect("tcx after cu_typeck")); + } + + // + // Stage 3: Actually run the code in the JIT + // + info!("actually running code"); + let code = repl.program.code(input, &result); + debug!("actually running ^^^^^^ %?", (||{ println(code) })()); + let input = driver::str_input(code.to_managed()); + let cfg = driver::build_configuration(sess, binary, &input); + let outputs = driver::build_output_filenames(&input, &None, &None, [], sess); + let sess = driver::build_session(options, diagnostic::emit); + driver::compile_upto(sess, cfg, &input, driver::cu_everything, + Some(outputs)); + + // + // Stage 4: Inform the program that computation is done so it can update all + // local variable bindings. + // + info!("cleaning up after code"); + repl.program.consume_cache(); + + return repl; + + fn parse_input(sess: session::Session, binary: @str, + input: &str) -> @ast::crate { + let code = fmt!("fn main() {\n %s \n}", input); + let input = driver::str_input(code.to_managed()); + let cfg = driver::build_configuration(sess, binary, &input); + let outputs = driver::build_output_filenames(&input, &None, &None, [], sess); + let (crate, _) = driver::compile_upto(sess, cfg, &input, + driver::cu_parse, Some(outputs)); + crate.expect("parsing should return a crate") + } + + fn find_main(crate: @ast::crate, sess: session::Session, + f: &fn(&ast::blk)) { + for crate.node.module.items.iter().advance |item| { + match item.node { + ast::item_fn(_, _, _, _, ref blk) => { + if item.ident == sess.ident_of("main") { + return f(blk); + } + } + _ => {} + } + } + fail!("main function was expected somewhere..."); + } +} + +// Compiles a crate given by the filename as a library if the compiled +// version doesn't exist or is older than the source file. Binary is +// the name of the compiling executable. Returns Some(true) if it +// successfully compiled, Some(false) if the crate wasn't compiled +// because it already exists and is newer than the source file, or +// None if there were compile errors. +fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> { + match do task::try { + let src_path = Path(src_filename); + let binary = binary.to_managed(); + let options = @session::options { + binary: binary, + addl_lib_search_paths: @mut ~[os::getcwd()], + .. copy *session::basic_options() + }; + let input = driver::file_input(copy src_path); + let sess = driver::build_session(options, diagnostic::emit); + *sess.building_library = true; + let cfg = driver::build_configuration(sess, binary, &input); + let outputs = driver::build_output_filenames( + &input, &None, &None, [], sess); + // If the library already exists and is newer than the source + // file, skip compilation and return None. + let mut should_compile = true; + let dir = os::list_dir_path(&Path(outputs.out_filename.dirname())); + let maybe_lib_path = do dir.iter().find_ |file| { + // The actual file's name has a hash value and version + // number in it which is unknown at this time, so looking + // for a file that matches out_filename won't work, + // instead we guess which file is the library by matching + // the prefix and suffix of out_filename to files in the + // directory. + let file_str = file.filename().get(); + file_str.starts_with(outputs.out_filename.filestem().get()) + && file_str.ends_with(outputs.out_filename.filetype().get()) + }; + match maybe_lib_path { + Some(lib_path) => { + let (src_mtime, _) = src_path.get_mtime().get(); + let (lib_mtime, _) = lib_path.get_mtime().get(); + if lib_mtime >= src_mtime { + should_compile = false; + } + }, + None => { }, + } + if (should_compile) { + println(fmt!("compiling %s...", src_filename)); + driver::compile_upto(sess, cfg, &input, driver::cu_everything, + Some(outputs)); + true + } else { false } + } { + Ok(true) => Some(true), + Ok(false) => Some(false), + Err(_) => None, + } +} + +/// Tries to get a line from rl after outputting a prompt. Returns +/// None if no input was read (e.g. EOF was reached). +fn get_line(use_rl: bool, prompt: &str) -> Option<~str> { + if use_rl { + let result = unsafe { rl::read(prompt) }; + + match result { + None => None, + Some(line) => { + unsafe { rl::add_history(line) }; + Some(line) + } + } + } else { + if io::stdin().eof() { + None + } else { + Some(io::stdin().read_line()) + } + } +} + +/// Run a command, e.g. :clear, :exit, etc. +fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer, + cmd: ~str, args: ~[~str], use_rl: bool) -> CmdAction { + let mut action = action_none; + match cmd { + ~"exit" => repl.running = false, + ~"clear" => { + repl.program.clear(); + + // XXX: Win32 version of linenoise can't do this + //rl::clear(); + } + ~"help" => { + println( + ":{\\n ..lines.. \\n:}\\n - execute multiline command\n\ + :load <crate> ... - loads given crates as dynamic libraries\n\ + :clear - clear the bindings\n\ + :exit - exit from the repl\n\ + :help - show this message"); + } + ~"load" => { + let mut loaded_crates: ~[~str] = ~[]; + for args.iter().advance |arg| { + let (crate, filename) = + if arg.ends_with(".rs") || arg.ends_with(".rc") { + (arg.slice_to(arg.len() - 3).to_owned(), copy *arg) + } else { + (copy *arg, *arg + ".rs") + }; + match compile_crate(filename, copy repl.binary) { + Some(_) => loaded_crates.push(crate), + None => { } + } + } + for loaded_crates.iter().advance |crate| { + let crate_path = Path(*crate); + let crate_dir = crate_path.dirname(); + repl.program.record_extern(fmt!("extern mod %s;", *crate)); + if !repl.lib_search_paths.iter().any_(|x| x == &crate_dir) { + repl.lib_search_paths.push(crate_dir); + } + } + if loaded_crates.is_empty() { + println("no crates loaded"); + } else { + println(fmt!("crates loaded: %s", + loaded_crates.connect(", "))); + } + } + ~"{" => { + let mut multiline_cmd = ~""; + let mut end_multiline = false; + while (!end_multiline) { + match get_line(use_rl, "rusti| ") { + None => fail!("unterminated multiline command :{ .. :}"), + Some(line) => { + if line.trim() == ":}" { + end_multiline = true; + } else { + multiline_cmd.push_str(line); + multiline_cmd.push_char('\n'); + } + } + } + } + action = action_run_line(multiline_cmd); + } + _ => println(~"unknown cmd: " + cmd) + } + return action; +} + +/// Executes a line of input, which may either be rust code or a +/// :command. Returns a new Repl if it has changed. +pub fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str, + use_rl: bool) + -> Option<Repl> { + if line.starts_with(":") { + // drop the : and the \n (one byte each) + let full = line.slice(1, line.len()); + let split: ~[~str] = full.word_iter().transform(|s| s.to_owned()).collect(); + let len = split.len(); + + if len > 0 { + let cmd = copy split[0]; + + if !cmd.is_empty() { + let args = if len > 1 { + vec::slice(split, 1, len).to_owned() + } else { ~[] }; + + match run_cmd(repl, in, out, cmd, args, use_rl) { + action_none => { } + action_run_line(multiline_cmd) => { + if !multiline_cmd.is_empty() { + return run_line(repl, in, out, multiline_cmd, use_rl); + } + } + } + return None; + } + } + } + + let line = Cell::new(line); + let r = Cell::new(copy *repl); + let result = do task::try { + run(r.take(), line.take()) + }; + + if result.is_ok() { + return Some(result.get()); + } + return None; +} + +pub fn main() { + let args = os::args(); + let in = io::stdin(); + let out = io::stdout(); + let mut repl = Repl { + prompt: ~"rusti> ", + binary: copy args[0], + running: true, + lib_search_paths: ~[], + + program: Program::new(), + }; + + let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0; + + // only print this stuff if the user is actually typing into rusti + if istty { + println("WARNING: The Rust REPL is experimental and may be"); + println("unstable. If you encounter problems, please use the"); + println("compiler instead. Type :help for help."); + + unsafe { + do rl::complete |line, suggest| { + if line.starts_with(":") { + suggest(~":clear"); + suggest(~":exit"); + suggest(~":help"); + suggest(~":load"); + } + } + } + } + + while repl.running { + match get_line(istty, repl.prompt) { + None => break, + Some(line) => { + if line.is_empty() { + if istty { + println("()"); + } + loop; + } + match run_line(&mut repl, in, out, line, istty) { + Some(new_repl) => repl = new_repl, + None => { } + } + } + } + } +} + +#[cfg(test)] +mod tests { + use std::io; + use std::iterator::IteratorUtil; + use program::Program; + use super::*; + + fn repl() -> Repl { + Repl { + prompt: ~"rusti> ", + binary: ~"rusti", + running: true, + lib_search_paths: ~[], + program: Program::new(), + } + } + + fn run_program(prog: &str) { + let mut r = repl(); + for prog.split_iter('\n').advance |cmd| { + let result = run_line(&mut r, io::stdin(), io::stdout(), + cmd.to_owned(), false); + r = result.expect(fmt!("the command '%s' failed", cmd)); + } + } + + #[test] + // FIXME: #7220 rusti on 32bit mac doesn't work. + #[cfg(not(target_word_size="32", + target_os="macos"))] + fn run_all() { + // FIXME(#7071): + // By default, unit tests are run in parallel. Rusti, on the other hand, + // does not enjoy doing this. I suspect that it is because the LLVM + // bindings are not thread-safe (when running parallel tests, some tests + // were triggering assertions in LLVM (or segfaults). Hence, this + // function exists to run everything serially (sadface). + // + // To get some interesting output, run with RUST_LOG=rusti::tests + + debug!("hopefully this runs"); + run_program(""); + + debug!("regression test for #5937"); + run_program("use std::hashmap;"); + + debug!("regression test for #5784"); + run_program("let a = 3;"); + + // XXX: can't spawn new tasks because the JIT code is cleaned up + // after the main function is done. + // debug!("regression test for #5803"); + // run_program(" + // spawn( || println(\"Please don't segfault\") ); + // do spawn { println(\"Please?\"); } + // "); + + debug!("inferred integers are usable"); + run_program("let a = 2;\n()\n"); + run_program(" + let a = 3; + let b = 4u; + assert!((a as uint) + b == 7) + "); + + debug!("local variables can be shadowed"); + run_program(" + let a = 3; + let a = 5; + assert!(a == 5) + "); + + debug!("strings are usable"); + run_program(" + let a = ~\"\"; + let b = \"\"; + let c = @\"\"; + let d = a + b + c; + assert!(d.len() == 0); + "); + + debug!("vectors are usable"); + run_program(" + let a = ~[1, 2, 3]; + let b = &[1, 2, 3]; + let c = @[1, 2, 3]; + let d = a + b + c; + assert!(d.len() == 9); + let e: &[int] = []; + "); + + debug!("structs are usable"); + run_program(" + struct A{ a: int } + let b = A{ a: 3 }; + assert!(b.a == 3) + "); + + debug!("mutable variables"); + run_program(" + let mut a = 3; + a = 5; + let mut b = std::hashmap::HashSet::new::<int>(); + b.insert(a); + assert!(b.contains(&5)) + assert!(b.len() == 1) + "); + + debug!("functions are cached"); + run_program(" + fn fib(x: int) -> int { if x < 2 {x} else { fib(x - 1) + fib(x - 2) } } + let a = fib(3); + let a = a + fib(4); + assert!(a == 5) + "); + + debug!("modules are cached"); + run_program(" + mod b { pub fn foo() -> uint { 3 } } + assert!(b::foo() == 3) + "); + + debug!("multiple function definitions are allowed"); + run_program(" + fn f() {} + fn f() {} + f() + "); + + debug!("multiple item definitions are allowed"); + run_program(" + fn f() {} + mod f {} + struct f; + enum f {} + fn f() {} + f() + "); + } + + #[test] + // FIXME: #7220 rusti on 32bit mac doesn't work. + #[cfg(not(target_word_size="32", + target_os="macos"))] + fn exit_quits() { + let mut r = repl(); + assert!(r.running); + let result = run_line(&mut r, io::stdin(), io::stdout(), + ~":exit", false); + assert!(result.is_none()); + assert!(!r.running); + } +} diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs index 54a404d971e..abb0cf271ec 100644 --- a/src/librusti/rusti.rs +++ b/src/librusti/rusti.rs @@ -55,7 +55,7 @@ extern mod extra; extern mod rustc; extern mod syntax; -use std::{libc, io, os, task, vec}; +use std::{libc, io, os, task}; use std::cell::Cell; use extra::rl; @@ -402,7 +402,8 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer, if line.trim() == ":}" { end_multiline = true; } else { - multiline_cmd += line + "\n"; + multiline_cmd.push_str(line); + multiline_cmd.push_char('\n'); } } } @@ -430,7 +431,7 @@ pub fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str, if !cmd.is_empty() { let args = if len > 1 { - vec::slice(split, 1, len).to_owned() + split.slice(1, len).to_owned() } else { ~[] }; match run_cmd(repl, in, out, cmd, args, use_rl) { diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index 9b727e9d3e0..ebdea2537ac 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -12,7 +12,7 @@ use target::*; use package_id::PkgId; use core::path::Path; use core::option::*; -use core::{os, run, str, vec}; +use core::{os, run, str}; use context::*; use crate::Crate; use messages::*; @@ -146,8 +146,7 @@ impl PkgSrc { fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) { assert!(p.components.len() > prefix); let mut sub = Path(""); - for vec::slice(p.components, prefix, - p.components.len()).iter().advance |c| { + for p.components.slice(prefix, p.components.len()).iter().advance |c| { sub = sub.push(*c); } debug!("found crate %s", sub.to_str()); diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 6d146145f36..f0a3f24c307 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -22,11 +22,39 @@ use core::iterator::IteratorUtil; use messages::*; use package_id::*; +fn push_if_exists(vec: &mut ~[Path], p: &Path) { + let maybe_dir = p.push(".rust"); + if os::path_exists(&maybe_dir) { + vec.push(maybe_dir); + } +} + +#[cfg(windows)] +static path_entry_separator: &'static str = ";"; +#[cfg(not(windows))] +static path_entry_separator: &'static str = ":"; + /// Returns the value of RUST_PATH, as a list -/// of Paths. In general this should be read from the -/// environment; for now, it's hard-wired to just be "." +/// of Paths. Includes default entries for, if they exist: +/// $HOME/.rust +/// DIR/.rust for any DIR that's the current working directory +/// or an ancestor of it pub fn rust_path() -> ~[Path] { - ~[Path(".")] + let mut env_rust_path: ~[Path] = match os::getenv("RUST_PATH") { + Some(env_path) => { + let env_path_components: ~[&str] = + env_path.split_str_iter(path_entry_separator).collect(); + env_path_components.map(|&s| Path(s)) + } + None => ~[] + }; + let cwd = os::getcwd(); + // now add in default entries + env_rust_path.push(copy cwd); + do cwd.each_parent() |p| { push_if_exists(&mut env_rust_path, p) }; + let h = os::homedir(); + for h.iter().advance |h| { push_if_exists(&mut env_rust_path, h); } + env_rust_path } pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index d70428e7338..550a3411b5d 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -185,7 +185,21 @@ impl<'self> PkgScript<'self> { } -impl Ctx { +pub trait CtxMethods { + fn run(&self, cmd: &str, args: ~[~str]); + fn do_cmd(&self, _cmd: &str, _pkgname: &str); + fn build(&self, workspace: &Path, pkgid: &PkgId); + fn clean(&self, workspace: &Path, id: &PkgId); + fn info(&self); + fn install(&self, workspace: &Path, id: &PkgId); + fn install_no_build(&self, workspace: &Path, id: &PkgId); + fn prefer(&self, _id: &str, _vers: Option<~str>); + fn test(&self); + fn uninstall(&self, _id: &str, _vers: Option<~str>); + fn unprefer(&self, _id: &str, _vers: Option<~str>); +} + +impl CtxMethods for Ctx { fn run(&self, cmd: &str, args: ~[~str]) { match cmd { diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index afeb6407533..44a8e696bde 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -12,7 +12,7 @@ use context::Ctx; use core::hashmap::HashMap; -use core::{io, libc, os, result, run, str}; +use core::{io, libc, os, result, run, str, vec}; use core::prelude::*; use extra::tempfile::mkdtemp; use core::run::ProcessOutput; @@ -25,7 +25,7 @@ use path_util::{target_executable_in_workspace, target_library_in_workspace, make_dir_rwx, u_rwx, library_in_workspace, built_bench_in_workspace, built_test_in_workspace, built_library_in_workspace, built_executable_in_workspace, - installed_library_in_workspace}; + installed_library_in_workspace, rust_path}; use target::*; /// Returns the last-modified date as an Option @@ -144,10 +144,10 @@ fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput { err_fd: None }); let output = prog.finish_with_output(); - io::println(fmt!("Output from command %s with args %? was %s {%s}[%?]", + debug!("Output from command %s with args %? was %s {%s}[%?]", cmd, args, str::from_bytes(output.output), str::from_bytes(output.error), - output.status)); + output.status); /* By the way, rustpkg *won't* return a nonzero exit code if it fails -- see #4547 @@ -248,7 +248,7 @@ fn command_line_test_output(args: &[~str]) -> ~[~str] { let p_output = command_line_test(args, &os::getcwd()); let test_output = str::from_bytes(p_output.output); for test_output.split_iter('\n').advance |s| { - result += [s.to_owned()]; + result.push(s.to_owned()); } result } @@ -562,13 +562,58 @@ fn package_script_with_default_build() { } #[test] -#[ignore (reason = "RUST_PATH not yet implemented -- #5682")] +#[ignore (reason = "Un-ignore when #7071 is fixed")] fn rust_path_test() { - let dir = mk_workspace(&Path("/home/more_rust"), - &normalize(RemotePath(Path("foo"))), - &NoVersion); - // command_line_test("RUST_PATH=/home/rust:/home/more_rust rustpkg install foo"); - command_line_test([~"install", ~"foo"], &dir); + let dir_for_path = mkdtemp(&os::tmpdir(), "more_rust").expect("rust_path_test failed"); + let dir = mk_workspace(&dir_for_path, &normalize(RemotePath(Path("foo"))), &NoVersion); + debug!("dir = %s", dir.to_str()); + writeFile(&Path("/Users/tjc/more_rust/src/foo-0.1/main.rs"), + "fn main() { let _x = (); }"); + + let cwd = os::getcwd(); + debug!("cwd = %s", cwd.to_str()); + let mut prog = run::Process::new("rustpkg", + [~"install", ~"foo"], + run::ProcessOptions { env: Some(&[(~"RUST_PATH", + dir_for_path.to_str())]), + dir: Some(&cwd), + in_fd: None, + out_fd: None, + err_fd: None + }); + prog.finish_with_output(); + assert_executable_exists(&dir_for_path, "foo"); +} + +#[test] +fn rust_path_contents() { + let dir = mkdtemp(&os::tmpdir(), "rust_path").expect("rust_path_contents failed"); + let abc = &dir.push("A").push("B").push("C"); + assert!(os::mkdir_recursive(&abc.push(".rust"), u_rwx)); + assert!(os::mkdir_recursive(&abc.pop().push(".rust"), u_rwx)); + assert!(os::mkdir_recursive(&abc.pop().pop().push(".rust"), u_rwx)); + assert!(do os::change_dir_locked(&dir.push("A").push("B").push("C")) { + let p = rust_path(); + let cwd = os::getcwd().push(".rust"); + let parent = cwd.pop().pop().push(".rust"); + let grandparent = cwd.pop().pop().pop().push(".rust"); + assert!(vec::contains(p, &cwd)); + assert!(vec::contains(p, &parent)); + assert!(vec::contains(p, &grandparent)); + for p.iter().advance() |a_path| { + assert!(!a_path.components.is_empty()); + } + }); +} + +#[test] +fn rust_path_parse() { + os::setenv("RUST_PATH", "/a/b/c:/d/e/f:/g/h/i"); + let paths = rust_path(); + assert!(vec::contains(paths, &Path("/g/h/i"))); + assert!(vec::contains(paths, &Path("/d/e/f"))); + assert!(vec::contains(paths, &Path("/a/b/c"))); + os::unsetenv("RUST_PATH"); } #[test] diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 38e6a4824af..cb9bbf80ea8 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -187,7 +187,7 @@ pub fn compile_input(ctxt: &Ctx, Lib => lib_crate, Test | Bench | Main => bin_crate }; - let matches = getopts(~[~"-Z", ~"time-passes"] + let matches = getopts(debug_flags() + match what { Lib => ~[~"--lib"], // --test compiles both #[test] and #[bench] fns @@ -415,3 +415,7 @@ mod test { } } + +// tjc: cheesy +fn debug_flags() -> ~[~str] { ~[] } +// static debug_flags: ~[~str] = ~[~"-Z", ~"time-passes"]; \ No newline at end of file diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs index e1d2b246dd3..53ea11f2b05 100644 --- a/src/libstd/cell.rs +++ b/src/libstd/cell.rs @@ -22,7 +22,8 @@ A dynamic, mutable location. Similar to a mutable option type, but friendlier. */ -#[mutable] +#[mutable] // XXX remove after snap +#[no_freeze] #[deriving(Clone, DeepClone, Eq)] #[allow(missing_doc)] pub struct Cell<T> { diff --git a/src/libstd/char.rs b/src/libstd/char.rs index 797fd9e8c02..8f0870af513 100644 --- a/src/libstd/char.rs +++ b/src/libstd/char.rs @@ -10,6 +10,7 @@ //! Utilities for manipulating the char type +use container::Container; use option::{None, Option, Some}; use str; use str::{StrSlice, OwnedStr}; diff --git a/src/libstd/clone.rs b/src/libstd/clone.rs index 046693632c6..947aa5708c2 100644 --- a/src/libstd/clone.rs +++ b/src/libstd/clone.rs @@ -22,7 +22,7 @@ by convention implementing the `Clone` trait and calling the */ -use core::kinds::Const; +use core::kinds::Freeze; /// A common trait for cloning an object. pub trait Clone { @@ -112,17 +112,17 @@ impl<T: DeepClone> DeepClone for ~T { fn deep_clone(&self) -> ~T { ~(**self).deep_clone() } } -// FIXME: #6525: should also be implemented for `T: Owned + DeepClone` -impl<T: Const + DeepClone> DeepClone for @T { - /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing +// FIXME: #6525: should also be implemented for `T: Send + DeepClone` +impl<T: Freeze + DeepClone> DeepClone for @T { + /// Return a deep copy of the managed box. The `Freeze` trait is required to prevent performing /// a deep clone of a potentially cyclical type. #[inline] fn deep_clone(&self) -> @T { @(**self).deep_clone() } } -// FIXME: #6525: should also be implemented for `T: Owned + DeepClone` -impl<T: Const + DeepClone> DeepClone for @mut T { - /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing +// FIXME: #6525: should also be implemented for `T: Send + DeepClone` +impl<T: Freeze + DeepClone> DeepClone for @mut T { + /// Return a deep copy of the managed box. The `Freeze` trait is required to prevent performing /// a deep clone of a potentially cyclical type. #[inline] fn deep_clone(&self) -> @mut T { @mut (**self).deep_clone() } diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index 7918abe4ae6..8316a33ecf1 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -17,7 +17,7 @@ Message passing use cast::{transmute, transmute_mut}; use container::Container; use either::{Either, Left, Right}; -use kinds::Owned; +use kinds::Send; use option::{Option, Some, None}; use uint; use vec::OwnedVector; @@ -77,7 +77,7 @@ pub struct Port<T> { These allow sending or receiving an unlimited number of messages. */ -pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) { +pub fn stream<T:Send>() -> (Port<T>, Chan<T>) { let (port, chan) = match rt::context() { rt::OldTaskContext => match pipesy::stream() { (p, c) => (Left(p), Left(c)) @@ -91,7 +91,7 @@ pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) { return (port, chan); } -impl<T: Owned> GenericChan<T> for Chan<T> { +impl<T: Send> GenericChan<T> for Chan<T> { fn send(&self, x: T) { match self.inner { Left(ref chan) => chan.send(x), @@ -100,7 +100,7 @@ impl<T: Owned> GenericChan<T> for Chan<T> { } } -impl<T: Owned> GenericSmartChan<T> for Chan<T> { +impl<T: Send> GenericSmartChan<T> for Chan<T> { fn try_send(&self, x: T) -> bool { match self.inner { Left(ref chan) => chan.try_send(x), @@ -109,7 +109,7 @@ impl<T: Owned> GenericSmartChan<T> for Chan<T> { } } -impl<T: Owned> GenericPort<T> for Port<T> { +impl<T: Send> GenericPort<T> for Port<T> { fn recv(&self) -> T { match self.inner { Left(ref port) => port.recv(), @@ -125,7 +125,7 @@ impl<T: Owned> GenericPort<T> for Port<T> { } } -impl<T: Owned> Peekable<T> for Port<T> { +impl<T: Send> Peekable<T> for Port<T> { fn peek(&self) -> bool { match self.inner { Left(ref port) => port.peek(), @@ -134,7 +134,7 @@ impl<T: Owned> Peekable<T> for Port<T> { } } -impl<T: Owned> Selectable for Port<T> { +impl<T: Send> Selectable for Port<T> { fn header(&mut self) -> *mut PacketHeader { match self.inner { Left(ref mut port) => port.header(), @@ -149,7 +149,7 @@ pub struct PortSet<T> { ports: ~[pipesy::Port<T>], } -impl<T: Owned> PortSet<T> { +impl<T: Send> PortSet<T> { pub fn new() -> PortSet<T> { PortSet { ports: ~[] @@ -175,7 +175,7 @@ impl<T: Owned> PortSet<T> { } } -impl<T:Owned> GenericPort<T> for PortSet<T> { +impl<T:Send> GenericPort<T> for PortSet<T> { fn try_recv(&self) -> Option<T> { unsafe { let self_ports = transmute_mut(&self.ports); @@ -204,7 +204,7 @@ impl<T:Owned> GenericPort<T> for PortSet<T> { } } -impl<T: Owned> Peekable<T> for PortSet<T> { +impl<T: Send> Peekable<T> for PortSet<T> { fn peek(&self) -> bool { // It'd be nice to use self.port.each, but that version isn't // pure. @@ -223,7 +223,7 @@ pub struct SharedChan<T> { ch: Exclusive<pipesy::Chan<T>> } -impl<T: Owned> SharedChan<T> { +impl<T: Send> SharedChan<T> { /// Converts a `chan` into a `shared_chan`. pub fn new(c: Chan<T>) -> SharedChan<T> { let Chan { inner } = c; @@ -235,7 +235,7 @@ impl<T: Owned> SharedChan<T> { } } -impl<T: Owned> GenericChan<T> for SharedChan<T> { +impl<T: Send> GenericChan<T> for SharedChan<T> { fn send(&self, x: T) { unsafe { let mut xx = Some(x); @@ -247,7 +247,7 @@ impl<T: Owned> GenericChan<T> for SharedChan<T> { } } -impl<T: Owned> GenericSmartChan<T> for SharedChan<T> { +impl<T: Send> GenericSmartChan<T> for SharedChan<T> { fn try_send(&self, x: T) -> bool { unsafe { let mut xx = Some(x); @@ -259,7 +259,7 @@ impl<T: Owned> GenericSmartChan<T> for SharedChan<T> { } } -impl<T: Owned> ::clone::Clone for SharedChan<T> { +impl<T: Send> ::clone::Clone for SharedChan<T> { fn clone(&self) -> SharedChan<T> { SharedChan { ch: self.ch.clone() } } @@ -273,7 +273,7 @@ pub struct ChanOne<T> { inner: Either<pipesy::ChanOne<T>, rtcomm::ChanOne<T>> } -pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { +pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) { let (port, chan) = match rt::context() { rt::OldTaskContext => match pipesy::oneshot() { (p, c) => (Left(p), Left(c)), @@ -287,7 +287,7 @@ pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { return (port, chan); } -impl<T: Owned> PortOne<T> { +impl<T: Send> PortOne<T> { pub fn recv(self) -> T { let PortOne { inner } = self; match inner { @@ -305,7 +305,7 @@ impl<T: Owned> PortOne<T> { } } -impl<T: Owned> ChanOne<T> { +impl<T: Send> ChanOne<T> { pub fn send(self, data: T) { let ChanOne { inner } = self; match inner { @@ -323,7 +323,7 @@ impl<T: Owned> ChanOne<T> { } } -pub fn recv_one<T: Owned>(port: PortOne<T>) -> T { +pub fn recv_one<T: Send>(port: PortOne<T>) -> T { let PortOne { inner } = port; match inner { Left(p) => pipesy::recv_one(p), @@ -331,7 +331,7 @@ pub fn recv_one<T: Owned>(port: PortOne<T>) -> T { } } -pub fn try_recv_one<T: Owned>(port: PortOne<T>) -> Option<T> { +pub fn try_recv_one<T: Send>(port: PortOne<T>) -> Option<T> { let PortOne { inner } = port; match inner { Left(p) => pipesy::try_recv_one(p), @@ -339,7 +339,7 @@ pub fn try_recv_one<T: Owned>(port: PortOne<T>) -> Option<T> { } } -pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) { +pub fn send_one<T: Send>(chan: ChanOne<T>, data: T) { let ChanOne { inner } = chan; match inner { Left(c) => pipesy::send_one(c, data), @@ -347,7 +347,7 @@ pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) { } } -pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T) -> bool { +pub fn try_send_one<T: Send>(chan: ChanOne<T>, data: T) -> bool { let ChanOne { inner } = chan; match inner { Left(c) => pipesy::try_send_one(c, data), @@ -357,7 +357,7 @@ pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T) -> bool { mod pipesy { - use kinds::Owned; + use kinds::Send; use option::{Option, Some, None}; use pipes::{recv, try_recv, peek, PacketHeader}; use super::{GenericChan, GenericSmartChan, GenericPort, Peekable, Selectable}; @@ -365,17 +365,17 @@ mod pipesy { use util::replace; /*proto! oneshot ( - Oneshot:send<T:Owned> { + Oneshot:send<T:Send> { send(T) -> ! } )*/ #[allow(non_camel_case_types)] pub mod oneshot { - priv use core::kinds::Owned; + priv use core::kinds::Send; use ptr::to_mut_unsafe_ptr; - pub fn init<T: Owned>() -> (server::Oneshot<T>, client::Oneshot<T>) { + pub fn init<T: Send>() -> (server::Oneshot<T>, client::Oneshot<T>) { pub use core::pipes::HasBuffer; let buffer = ~::core::pipes::Buffer { @@ -399,10 +399,10 @@ mod pipesy { #[allow(non_camel_case_types)] pub mod client { - priv use core::kinds::Owned; + priv use core::kinds::Send; #[allow(non_camel_case_types)] - pub fn try_send<T: Owned>(pipe: Oneshot<T>, x_0: T) -> + pub fn try_send<T: Send>(pipe: Oneshot<T>, x_0: T) -> ::core::option::Option<()> { { use super::send; @@ -414,7 +414,7 @@ mod pipesy { } #[allow(non_camel_case_types)] - pub fn send<T: Owned>(pipe: Oneshot<T>, x_0: T) { + pub fn send<T: Send>(pipe: Oneshot<T>, x_0: T) { { use super::send; let message = send(x_0); @@ -464,12 +464,12 @@ mod pipesy { } /// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair. - pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { + pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) { let (port, chan) = oneshot::init(); (PortOne::new(port), ChanOne::new(chan)) } - impl<T: Owned> PortOne<T> { + impl<T: Send> PortOne<T> { pub fn recv(self) -> T { recv_one(self) } pub fn try_recv(self) -> Option<T> { try_recv_one(self) } pub fn unwrap(self) -> oneshot::server::Oneshot<T> { @@ -479,7 +479,7 @@ mod pipesy { } } - impl<T: Owned> ChanOne<T> { + impl<T: Send> ChanOne<T> { pub fn send(self, data: T) { send_one(self, data) } pub fn try_send(self, data: T) -> bool { try_send_one(self, data) } pub fn unwrap(self) -> oneshot::client::Oneshot<T> { @@ -493,7 +493,7 @@ mod pipesy { * Receive a message from a oneshot pipe, failing if the connection was * closed. */ - pub fn recv_one<T: Owned>(port: PortOne<T>) -> T { + pub fn recv_one<T: Send>(port: PortOne<T>) -> T { match port { PortOne { contents: port } => { let oneshot::send(message) = recv(port); @@ -503,7 +503,7 @@ mod pipesy { } /// Receive a message from a oneshot pipe unless the connection was closed. - pub fn try_recv_one<T: Owned> (port: PortOne<T>) -> Option<T> { + pub fn try_recv_one<T: Send> (port: PortOne<T>) -> Option<T> { match port { PortOne { contents: port } => { let message = try_recv(port); @@ -519,7 +519,7 @@ mod pipesy { } /// Send a message on a oneshot pipe, failing if the connection was closed. - pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) { + pub fn send_one<T: Send>(chan: ChanOne<T>, data: T) { match chan { ChanOne { contents: chan } => oneshot::client::send(chan, data), } @@ -529,7 +529,7 @@ mod pipesy { * Send a message on a oneshot pipe, or return false if the connection was * closed. */ - pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T) -> bool { + pub fn try_send_one<T: Send>(chan: ChanOne<T>, data: T) -> bool { match chan { ChanOne { contents: chan } => { oneshot::client::try_send(chan, data).is_some() @@ -540,16 +540,16 @@ mod pipesy { // Streams - Make pipes a little easier in general. /*proto! streamp ( - Open:send<T: Owned> { + Open:send<T: Send> { data(T) -> Open<T> } )*/ #[allow(non_camel_case_types)] pub mod streamp { - priv use core::kinds::Owned; + priv use core::kinds::Send; - pub fn init<T: Owned>() -> (server::Open<T>, client::Open<T>) { + pub fn init<T: Send>() -> (server::Open<T>, client::Open<T>) { pub use core::pipes::HasBuffer; ::core::pipes::entangle() } @@ -559,10 +559,10 @@ mod pipesy { #[allow(non_camel_case_types)] pub mod client { - priv use core::kinds::Owned; + priv use core::kinds::Send; #[allow(non_camel_case_types)] - pub fn try_data<T: Owned>(pipe: Open<T>, x_0: T) -> + pub fn try_data<T: Send>(pipe: Open<T>, x_0: T) -> ::core::option::Option<Open<T>> { { use super::data; @@ -575,7 +575,7 @@ mod pipesy { } #[allow(non_camel_case_types)] - pub fn data<T: Owned>(pipe: Open<T>, x_0: T) -> Open<T> { + pub fn data<T: Send>(pipe: Open<T>, x_0: T) -> Open<T> { { use super::data; let (s, c) = ::core::pipes::entangle(); @@ -613,7 +613,7 @@ mod pipesy { These allow sending or receiving an unlimited number of messages. */ - pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) { + pub fn stream<T:Send>() -> (Port<T>, Chan<T>) { let (s, c) = streamp::init(); (Port { @@ -623,7 +623,7 @@ mod pipesy { }) } - impl<T: Owned> GenericChan<T> for Chan<T> { + impl<T: Send> GenericChan<T> for Chan<T> { #[inline] fn send(&self, x: T) { unsafe { @@ -634,7 +634,7 @@ mod pipesy { } } - impl<T: Owned> GenericSmartChan<T> for Chan<T> { + impl<T: Send> GenericSmartChan<T> for Chan<T> { #[inline] fn try_send(&self, x: T) -> bool { unsafe { @@ -651,7 +651,7 @@ mod pipesy { } } - impl<T: Owned> GenericPort<T> for Port<T> { + impl<T: Send> GenericPort<T> for Port<T> { #[inline] fn recv(&self) -> T { unsafe { @@ -679,7 +679,7 @@ mod pipesy { } } - impl<T: Owned> Peekable<T> for Port<T> { + impl<T: Send> Peekable<T> for Port<T> { #[inline] fn peek(&self) -> bool { unsafe { @@ -695,7 +695,7 @@ mod pipesy { } } - impl<T: Owned> Selectable for Port<T> { + impl<T: Send> Selectable for Port<T> { fn header(&mut self) -> *mut PacketHeader { match self.endp { Some(ref mut endp) => endp.header(), @@ -723,15 +723,15 @@ pub fn select2i<A:Selectable, B:Selectable>(a: &mut A, b: &mut B) } /// Receive a message from one of two endpoints. -pub trait Select2<T: Owned, U: Owned> { +pub trait Select2<T: Send, U: Send> { /// Receive a message or return `None` if a connection closes. fn try_select(&mut self) -> Either<Option<T>, Option<U>>; /// Receive a message or fail if a connection closes. fn select(&mut self) -> Either<T, U>; } -impl<T:Owned, - U:Owned, +impl<T:Send, + U:Send, Left:Selectable + GenericPort<T>, Right:Selectable + GenericPort<U>> Select2<T, U> diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs index 8e88bfb4632..6c3fcd41ed3 100644 --- a/src/libstd/hash.rs +++ b/src/libstd/hash.rs @@ -24,6 +24,7 @@ use container::Container; use iterator::IteratorUtil; use rt::io::Writer; +use str::OwnedStr; use to_bytes::IterBytes; use uint; use vec::ImmutableVector; @@ -369,7 +370,7 @@ impl Streaming for SipState { let r = self.result_bytes(); let mut s = ~""; for r.iter().advance |b| { - s += uint::to_str_radix(*b as uint, 16u); + s.push_str(uint::to_str_radix(*b as uint, 16u)); } s } @@ -471,7 +472,7 @@ mod tests { fn to_hex_str(r: &[u8, ..8]) -> ~str { let mut s = ~""; for r.iter().advance |b| { - s += uint::to_str_radix(*b as uint, 16u); + s.push_str(uint::to_str_radix(*b as uint, 16u)); } s } @@ -492,7 +493,7 @@ mod tests { assert!(f == i && f == v); - buf += [t as u8]; + buf.push(t as u8); stream_inc.input([t as u8]); t += 1; diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index bfa0f2fa124..7f9fb6ad938 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -671,7 +671,7 @@ impl<T:Hash + Eq> Set<T> for HashSet<T> { fn symmetric_difference(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool { - self.difference(other, f) && other.difference(self, f) + self.difference(other, |t| f(t)) && other.difference(self, |t| f(t)) } /// Visit the values representing the intersection @@ -681,7 +681,8 @@ impl<T:Hash + Eq> Set<T> for HashSet<T> { /// Visit the values representing the union fn union(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool { - self.iter().advance(f) && other.iter().advance(|v| self.contains(v) || f(v)) + self.iter().advance(|t| f(t)) && + other.iter().advance(|v| self.contains(v) || f(v)) } } diff --git a/src/libstd/io.rs b/src/libstd/io.rs index a78be9c8b2b..59ac58a514f 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -65,7 +65,7 @@ use str::StrSlice; use to_str::ToStr; use uint; use vec; -use vec::{ImmutableVector, OwnedVector, OwnedCopyableVector, CopyableVector}; +use vec::{MutableVector, ImmutableVector, OwnedVector, OwnedCopyableVector, CopyableVector}; #[allow(non_camel_case_types)] // not sure what to do about this pub type fd_t = c_int; @@ -698,7 +698,7 @@ impl<T:Reader> ReaderUtil for T { // over-read by reading 1-byte per char needed nbread = if ncreq > nbreq { ncreq } else { nbreq }; if nbread > 0 { - bytes = vec::slice(bytes, offset, bytes.len()).to_owned(); + bytes = bytes.slice(offset, bytes.len()).to_owned(); } } chars @@ -771,7 +771,9 @@ impl<T:Reader> ReaderUtil for T { fn read_le_uint_n(&self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut (val, pos, i) = (0u64, 0, nbytes); + let mut val = 0u64; + let mut pos = 0; + let mut i = nbytes; while i > 0 { val += (self.read_u8() as u64) << pos; pos += 8; @@ -787,7 +789,8 @@ impl<T:Reader> ReaderUtil for T { fn read_be_uint_n(&self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut (val, i) = (0u64, nbytes); + let mut val = 0u64; + let mut i = nbytes; while i > 0 { i -= 1; val += (self.read_u8() as u64) << i * 8; @@ -1053,7 +1056,7 @@ impl Reader for BytesReader { fn read(&self, bytes: &mut [u8], len: uint) -> uint { let count = uint::min(len, self.bytes.len() - *self.pos); - let view = vec::slice(self.bytes, *self.pos, self.bytes.len()); + let view = self.bytes.slice(*self.pos, self.bytes.len()); vec::bytes::copy_memory(bytes, view, count); *self.pos += count; @@ -1658,12 +1661,12 @@ impl Writer for BytesWriter { let bytes = &mut *self.bytes; let count = uint::max(bytes.len(), *self.pos + v_len); - vec::reserve(bytes, count); + bytes.reserve(count); unsafe { vec::raw::set_len(bytes, count); - let view = vec::mut_slice(*bytes, *self.pos, count); + let view = bytes.mut_slice(*self.pos, count); vec::bytes::copy_memory(view, v, v_len); } @@ -1909,8 +1912,7 @@ mod tests { if len <= ivals.len() { assert_eq!(res.len(), len); } - assert!(vec::slice(ivals, 0u, res.len()) == - vec::map(res, |x| *x as int)); + assert!(ivals.slice(0u, res.len()) == vec::map(res, |x| *x as int)); } } let mut i = 0; diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 9e434272198..976ca8bae7a 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -964,7 +964,7 @@ impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for return Some(x) } } - match self.iter.next().map_consume(self.f) { + match self.iter.next().map_consume(|x| (self.f)(x)) { None => return None, next => self.subiter = next, } @@ -983,7 +983,7 @@ impl<'self, A, St> UnfoldrIterator<'self, A, St> { /// Creates a new iterator with the specified closure as the "iterator /// function" and an initial state to eventually pass to the iterator #[inline] - pub fn new<'a>(f: &'a fn(&mut St) -> Option<A>, initial_state: St) + pub fn new<'a>(initial_state: St, f: &'a fn(&mut St) -> Option<A>) -> UnfoldrIterator<'a, A, St> { UnfoldrIterator { f: f, @@ -1030,7 +1030,6 @@ mod tests { use super::*; use prelude::*; - use iter; use uint; #[test] @@ -1175,7 +1174,7 @@ mod tests { } } - let mut it = UnfoldrIterator::new(count, 0); + let mut it = UnfoldrIterator::new(0, count); let mut i = 0; for it.advance |counted| { assert_eq!(counted, i); diff --git a/src/libstd/kinds.rs b/src/libstd/kinds.rs index 05c963a32cc..f350e106168 100644 --- a/src/libstd/kinds.rs +++ b/src/libstd/kinds.rs @@ -24,11 +24,10 @@ The 4 kinds are scalar types and managed pointers, and exludes owned pointers. It also excludes types that implement `Drop`. -* Owned - owned types and types containing owned types. These types +* Send - owned types and types containing owned types. These types may be transferred across task boundaries. -* Const - types that are deeply immutable. Const types are used for - freezable data structures. +* Freeze - types that are deeply immutable. `Copy` types include both implicitly copyable types that the compiler will copy automatically and non-implicitly copyable types that require @@ -44,14 +43,28 @@ pub trait Copy { // Empty. } +#[cfg(stage0)] #[lang="owned"] -pub trait Owned { - // Empty. +pub trait Send { + // empty. +} + +#[cfg(not(stage0))] +#[lang="send"] +pub trait Send { + // empty. } +#[cfg(stage0)] #[lang="const"] -pub trait Const { - // Empty. +pub trait Freeze { + // empty. +} + +#[cfg(not(stage0))] +#[lang="freeze"] +pub trait Freeze { + // empty. } #[lang="sized"] diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 3c2ae93b656..41b78afded1 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -349,7 +349,6 @@ pub mod types { use libc::types::os::arch::c95::{c_uchar, c_uint, c_ulong, time_t}; use libc::types::os::arch::c99::{c_longlong, c_ulonglong}; use libc::types::os::arch::posix88::{uid_t, gid_t, ino_t}; - use libc::types::os::arch::posix88::{uid_t}; pub type nlink_t = u16; pub type blksize_t = u32; diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index 82c01c998cf..c5f2c8ae584 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -46,7 +46,7 @@ use task::local_data_priv::{local_get, local_pop, local_modify, local_set, Handl * * These two cases aside, the interface is safe. */ -pub type LocalDataKey<'self,T> = &'self fn(v: @T); +pub type LocalDataKey<'self,T> = &'self fn:Copy(v: @T); /** * Remove a task-local data value from the table, returning the @@ -92,14 +92,12 @@ fn test_tls_multitask() { fn my_key(_x: @~str) { } local_data_set(my_key, @~"parent data"); do task::spawn { - unsafe { - // TLS shouldn't carry over. - assert!(local_data_get(my_key).is_none()); - local_data_set(my_key, @~"child data"); - assert!(*(local_data_get(my_key).get()) == + // TLS shouldn't carry over. + assert!(local_data_get(my_key).is_none()); + local_data_set(my_key, @~"child data"); + assert!(*(local_data_get(my_key).get()) == ~"child data"); - // should be cleaned up for us - } + // should be cleaned up for us } // Must work multiple times assert!(*(local_data_get(my_key).get()) == ~"parent data"); @@ -206,12 +204,11 @@ fn test_tls_cleanup_on_failure() { local_data_set(str_key, @~"parent data"); local_data_set(box_key, @@()); do task::spawn { - unsafe { // spawn_linked - local_data_set(str_key, @~"string data"); - local_data_set(box_key, @@()); - local_data_set(int_key, @42); - fail!(); - } + // spawn_linked + local_data_set(str_key, @~"string data"); + local_data_set(box_key, @@()); + local_data_set(int_key, @42); + fail!(); } // Not quite nondeterministic. local_data_set(int_key, @31337); diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 74ec46ccfcd..845152f8552 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -400,7 +400,8 @@ impl Integer for $T { #[inline] fn gcd(&self, other: &$T) -> $T { // Use Euclid's algorithm - let mut (m, n) = (*self, *other); + let mut m = *self; + let mut n = *other; while m != 0 { let temp = m; m = n % temp; diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index 30a18a0587b..b856c3c65ea 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -412,7 +412,7 @@ pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(radix: uint, pow if my_pow % 2u == 1u { total = total * multiplier; } - my_pow = my_pow / 2u; + my_pow = my_pow / 2u; multiplier = multiplier * multiplier; } total diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 52f620f97ce..0dabe7fafa8 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -237,7 +237,8 @@ impl Integer for $T { #[inline] fn gcd(&self, other: &$T) -> $T { // Use Euclid's algorithm - let mut (m, n) = (*self, *other); + let mut m = *self; + let mut n = *other; while m != 0 { let temp = m; m = n % temp; diff --git a/src/libstd/option.rs b/src/libstd/option.rs index f3ea81f1ae5..12ae2abd4a1 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -447,7 +447,7 @@ fn test_option_dance() { } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_option_too_much_dance() { - let mut y = Some(util::NonCopyable::new()); + let mut y = Some(util::NonCopyable); let _y2 = y.swap_unwrap(); let _y3 = y.swap_unwrap(); } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 0f6517f5799..1fbcda12dce 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -29,6 +29,7 @@ #[allow(missing_doc)]; use cast; +use container::Container; use io; use iterator::IteratorUtil; use libc; @@ -134,7 +135,7 @@ pub mod win32 { } } if k != 0 && done { - let sub = vec::slice(buf, 0u, k as uint); + let sub = buf.slice(0, k as uint); res = option::Some(str::from_utf16(sub)); } } @@ -145,7 +146,7 @@ pub mod win32 { pub fn as_utf16_p<T>(s: &str, f: &fn(*u16) -> T) -> T { let mut t = s.to_utf16(); // Null terminate before passing on. - t += [0u16]; + t.push(0u16); vec::as_imm_buf(t, |buf, _len| f(buf)) } } @@ -594,7 +595,7 @@ pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool { let r = list_dir(p); r.iter().advance(|q| { let path = &p.push(*q); - f(path) && (!path_is_dir(path) || walk_dir(path, f)) + f(path) && (!path_is_dir(path) || walk_dir(path, |p| f(p))) }) } @@ -1140,7 +1141,7 @@ pub fn set_exit_status(code: int) { unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] { let mut args = ~[]; for uint::range(0, argc as uint) |i| { - vec::push(&mut args, str::raw::from_c_str(*argv.offset(i))); + args.push(str::raw::from_c_str(*argv.offset(i))); } args } @@ -1186,8 +1187,7 @@ pub fn real_args() -> ~[~str] { while *ptr.offset(len) != 0 { len += 1; } // Push it onto the list. - vec::push(&mut args, - vec::raw::buf_as_slice(ptr, len, + args.push(vec::raw::buf_as_slice(ptr, len, str::from_utf16)); } } @@ -1501,7 +1501,10 @@ mod tests { fn test_getenv_big() { let mut s = ~""; let mut i = 0; - while i < 100 { s += "aaaaaaaaaa"; i += 1; } + while i < 100 { + s = s + "aaaaaaaaaa"; + i += 1; + } let n = make_rand_name(); setenv(n, s); debug!(copy s); diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 700bfff3f5d..a5e82c31d79 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -21,8 +21,8 @@ use cmp::Eq; use iterator::IteratorUtil; use libc; use option::{None, Option, Some}; +use str::{OwnedStr, Str, StrSlice, StrVector}; use str; -use str::{Str, StrSlice, StrVector}; use to_str::ToStr; use ascii::{AsciiCast, AsciiStr}; use vec::{OwnedVector, ImmutableVector}; @@ -335,8 +335,8 @@ mod stat { } } - -impl Path { +#[cfg(target_os = "win32")] +impl WindowsPath { pub fn stat(&self) -> Option<libc::stat> { unsafe { do str::as_c_str(self.to_str()) |buf| { @@ -349,12 +349,35 @@ impl Path { } } - #[cfg(unix)] - pub fn lstat(&self) -> Option<libc::stat> { + pub fn exists(&self) -> bool { + match self.stat() { + None => false, + Some(_) => true, + } + } + + pub fn get_size(&self) -> Option<i64> { + match self.stat() { + None => None, + Some(ref st) => Some(st.st_size as i64), + } + } + + pub fn get_mode(&self) -> Option<uint> { + match self.stat() { + None => None, + Some(ref st) => Some(st.st_mode as uint), + } + } +} + +#[cfg(not(target_os = "win32"))] +impl PosixPath { + pub fn stat(&self) -> Option<libc::stat> { unsafe { - do str::as_c_str(self.to_str()) |buf| { + do str::as_c_str(self.to_str()) |buf| { let mut st = stat::arch::default_stat(); - match libc::lstat(buf, &mut st) { + match libc::stat(buf, &mut st) { 0 => Some(st), _ => None, } @@ -382,12 +405,21 @@ impl Path { Some(ref st) => Some(st.st_mode as uint), } } + + /// Execute a function on p as well as all of its ancestors + pub fn each_parent(&self, f: &fn(&Path)) { + if !self.components.is_empty() { + f(self); + self.pop().each_parent(f); + } + } + } #[cfg(target_os = "freebsd")] #[cfg(target_os = "linux")] #[cfg(target_os = "macos")] -impl Path { +impl PosixPath { pub fn get_atime(&self) -> Option<(i64, int)> { match self.stat() { None => None, @@ -419,9 +451,24 @@ impl Path { } } +#[cfg(unix)] +impl PosixPath { + pub fn lstat(&self) -> Option<libc::stat> { + unsafe { + do str::as_c_str(self.to_str()) |buf| { + let mut st = stat::arch::default_stat(); + match libc::lstat(buf, &mut st) { + 0 => Some(st), + _ => None, + } + } + } + } +} + #[cfg(target_os = "freebsd")] #[cfg(target_os = "macos")] -impl Path { +impl PosixPath { pub fn get_birthtime(&self) -> Option<(i64, int)> { match self.stat() { None => None, @@ -434,7 +481,7 @@ impl Path { } #[cfg(target_os = "win32")] -impl Path { +impl WindowsPath { pub fn get_atime(&self) -> Option<(i64, int)> { match self.stat() { None => None, @@ -461,13 +508,21 @@ impl Path { } } } + + /// Execute a function on p as well as all of its ancestors + pub fn each_parent(&self, f: &fn(&Path)) { + if !self.components.is_empty() { + f(self); + self.pop().each_parent(f); + } + } } impl ToStr for PosixPath { fn to_str(&self) -> ~str { let mut s = ~""; if self.is_absolute { - s += "/"; + s.push_str("/"); } s + self.components.connect("/") } @@ -646,15 +701,21 @@ impl ToStr for WindowsPath { fn to_str(&self) -> ~str { let mut s = ~""; match self.host { - Some(ref h) => { s += "\\\\"; s += *h; } + Some(ref h) => { + s.push_str("\\\\"); + s.push_str(*h); + } None => { } } match self.device { - Some(ref d) => { s += *d; s += ":"; } + Some(ref d) => { + s.push_str(*d); + s.push_str(":"); + } None => { } } if self.is_absolute { - s += "\\"; + s.push_str("\\"); } s + self.components.connect("\\") } diff --git a/src/libstd/pipes.rs b/src/libstd/pipes.rs index 661dc2a659f..49713a3a23b 100644 --- a/src/libstd/pipes.rs +++ b/src/libstd/pipes.rs @@ -88,7 +88,7 @@ use container::Container; use cast::{forget, transmute, transmute_copy, transmute_mut}; use either::{Either, Left, Right}; use iterator::IteratorUtil; -use kinds::Owned; +use kinds::Send; use libc; use ops::Drop; use option::{None, Option, Some}; @@ -177,7 +177,7 @@ impl PacketHeader { transmute_copy(&self.buffer) } - pub fn set_buffer<T:Owned>(&mut self, b: ~Buffer<T>) { + pub fn set_buffer<T:Send>(&mut self, b: ~Buffer<T>) { unsafe { self.buffer = transmute_copy(&b); } @@ -193,13 +193,13 @@ pub trait HasBuffer { fn set_buffer(&mut self, b: *libc::c_void); } -impl<T:Owned> HasBuffer for Packet<T> { +impl<T:Send> HasBuffer for Packet<T> { fn set_buffer(&mut self, b: *libc::c_void) { self.header.buffer = b; } } -pub fn mk_packet<T:Owned>() -> Packet<T> { +pub fn mk_packet<T:Send>() -> Packet<T> { Packet { header: PacketHeader(), payload: None, @@ -230,7 +230,7 @@ pub fn packet<T>() -> *mut Packet<T> { p } -pub fn entangle_buffer<T:Owned,Tstart:Owned>( +pub fn entangle_buffer<T:Send,Tstart:Send>( mut buffer: ~Buffer<T>, init: &fn(*libc::c_void, x: &mut T) -> *mut Packet<Tstart>) -> (RecvPacketBuffered<Tstart, T>, SendPacketBuffered<Tstart, T>) { @@ -396,7 +396,7 @@ pub fn send<T,Tbuffer>(mut p: SendPacketBuffered<T,Tbuffer>, Fails if the sender closes the connection. */ -pub fn recv<T:Owned,Tbuffer:Owned>( +pub fn recv<T:Send,Tbuffer:Send>( p: RecvPacketBuffered<T, Tbuffer>) -> T { try_recv(p).expect("connection closed") } @@ -407,7 +407,7 @@ Returns `None` if the sender has closed the connection without sending a message, or `Some(T)` if a message was received. */ -pub fn try_recv<T:Owned,Tbuffer:Owned>(mut p: RecvPacketBuffered<T, Tbuffer>) +pub fn try_recv<T:Send,Tbuffer:Send>(mut p: RecvPacketBuffered<T, Tbuffer>) -> Option<T> { let p_ = p.unwrap(); let p = unsafe { &mut *p_ }; @@ -427,7 +427,7 @@ pub fn try_recv<T:Owned,Tbuffer:Owned>(mut p: RecvPacketBuffered<T, Tbuffer>) } } -fn try_recv_<T:Owned>(p: &mut Packet<T>) -> Option<T> { +fn try_recv_<T:Send>(p: &mut Packet<T>) -> Option<T> { // optimistic path match p.header.state { Full => { @@ -511,7 +511,7 @@ fn try_recv_<T:Owned>(p: &mut Packet<T>) -> Option<T> { } /// Returns true if messages are available. -pub fn peek<T:Owned,Tb:Owned>(p: &mut RecvPacketBuffered<T, Tb>) -> bool { +pub fn peek<T:Send,Tb:Send>(p: &mut RecvPacketBuffered<T, Tb>) -> bool { unsafe { match (*p.header()).state { Empty | Terminated => false, @@ -521,7 +521,7 @@ pub fn peek<T:Owned,Tb:Owned>(p: &mut RecvPacketBuffered<T, Tb>) -> bool { } } -fn sender_terminate<T:Owned>(p: *mut Packet<T>) { +fn sender_terminate<T:Send>(p: *mut Packet<T>) { let p = unsafe { &mut *p }; @@ -553,7 +553,7 @@ fn sender_terminate<T:Owned>(p: *mut Packet<T>) { } } -fn receiver_terminate<T:Owned>(p: *mut Packet<T>) { +fn receiver_terminate<T:Send>(p: *mut Packet<T>) { let p = unsafe { &mut *p }; @@ -671,7 +671,7 @@ pub struct SendPacketBuffered<T, Tbuffer> { } #[unsafe_destructor] -impl<T:Owned,Tbuffer:Owned> Drop for SendPacketBuffered<T,Tbuffer> { +impl<T:Send,Tbuffer:Send> Drop for SendPacketBuffered<T,Tbuffer> { fn drop(&self) { unsafe { let this: &mut SendPacketBuffered<T,Tbuffer> = transmute(self); @@ -729,7 +729,7 @@ pub struct RecvPacketBuffered<T, Tbuffer> { } #[unsafe_destructor] -impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> { +impl<T:Send,Tbuffer:Send> Drop for RecvPacketBuffered<T,Tbuffer> { fn drop(&self) { unsafe { let this: &mut RecvPacketBuffered<T,Tbuffer> = transmute(self); @@ -741,7 +741,7 @@ impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> { } } -impl<T:Owned,Tbuffer:Owned> RecvPacketBuffered<T, Tbuffer> { +impl<T:Send,Tbuffer:Send> RecvPacketBuffered<T, Tbuffer> { pub fn unwrap(&mut self) -> *mut Packet<T> { replace(&mut self.p, None).unwrap() } @@ -751,7 +751,7 @@ impl<T:Owned,Tbuffer:Owned> RecvPacketBuffered<T, Tbuffer> { } } -impl<T:Owned,Tbuffer:Owned> Selectable for RecvPacketBuffered<T, Tbuffer> { +impl<T:Send,Tbuffer:Send> Selectable for RecvPacketBuffered<T, Tbuffer> { fn header(&mut self) -> *mut PacketHeader { match self.p { Some(packet) => unsafe { @@ -807,7 +807,7 @@ Sometimes messages will be available on both endpoints at once. In this case, `select2` may return either `left` or `right`. */ -pub fn select2<A:Owned,Ab:Owned,B:Owned,Bb:Owned>( +pub fn select2<A:Send,Ab:Send,B:Send,Bb:Send>( mut a: RecvPacketBuffered<A, Ab>, mut b: RecvPacketBuffered<B, Bb>) -> Either<(Option<A>, RecvPacketBuffered<B, Bb>), @@ -847,7 +847,7 @@ pub fn select2i<A:Selectable,B:Selectable>(a: &mut A, b: &mut B) /// Waits on a set of endpoints. Returns a message, its index, and a /// list of the remaining endpoints. -pub fn select<T:Owned,Tb:Owned>(mut endpoints: ~[RecvPacketBuffered<T, Tb>]) +pub fn select<T:Send,Tb:Send>(mut endpoints: ~[RecvPacketBuffered<T, Tb>]) -> (uint, Option<T>, ~[RecvPacketBuffered<T, Tb>]) { diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 6d7cb2a28a8..13d19b276f5 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -29,7 +29,8 @@ Rust's prelude has three main parts: // Reexported core operators pub use either::{Either, Left, Right}; -pub use kinds::{Const, Copy, Owned, Sized}; +pub use kinds::{Copy, Sized}; +pub use kinds::{Freeze, Send}; pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Drop}; diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index ea4a9059e72..5baff8aee68 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -42,6 +42,7 @@ fn main () { use cast; use cmp; +use container::Container; use int; use iterator::IteratorUtil; use local_data; @@ -720,7 +721,8 @@ impl IsaacRng { fn isaac(&mut self) { self.c += 1; // abbreviations - let mut (a, b) = (self.a, self.b + self.c); + let mut a = self.a; + let mut b = self.b + self.c; static midpoint: uint = RAND_SIZE as uint / 2; diff --git a/src/libstd/rand/distributions.rs b/src/libstd/rand/distributions.rs index 6f4f1a34977..e8dad2fc5e8 100644 --- a/src/libstd/rand/distributions.rs +++ b/src/libstd/rand/distributions.rs @@ -89,7 +89,8 @@ impl Rand for StandardNormal { // do-while, so the condition should be true on the first // run, they get overwritten anyway (0 < 1, so these are // good). - let mut (x, y) = (1.0, 0.0); + let mut x = 1.0; + let mut y = 0.0; // XXX infinities? while -2.0*y < x * x { diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index 75b1d8f3810..72907f40a07 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -19,7 +19,7 @@ use option::*; use cast; use util; use ops::Drop; -use kinds::Owned; +use kinds::Send; use rt::sched::{Scheduler, Coroutine}; use rt::local::Local; use unstable::intrinsics::{atomic_xchg, atomic_load}; @@ -68,7 +68,7 @@ pub struct PortOneHack<T> { suppress_finalize: bool } -pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { +pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) { let packet: ~Packet<T> = ~Packet { state: STATE_BOTH, payload: None @@ -307,20 +307,20 @@ pub struct Port<T> { next: Cell<PortOne<StreamPayload<T>>> } -pub fn stream<T: Owned>() -> (Port<T>, Chan<T>) { +pub fn stream<T: Send>() -> (Port<T>, Chan<T>) { let (pone, cone) = oneshot(); let port = Port { next: Cell::new(pone) }; let chan = Chan { next: Cell::new(cone) }; return (port, chan); } -impl<T: Owned> GenericChan<T> for Chan<T> { +impl<T: Send> GenericChan<T> for Chan<T> { fn send(&self, val: T) { self.try_send(val); } } -impl<T: Owned> GenericSmartChan<T> for Chan<T> { +impl<T: Send> GenericSmartChan<T> for Chan<T> { fn try_send(&self, val: T) -> bool { let (next_pone, next_cone) = oneshot(); let cone = self.next.take(); diff --git a/src/libstd/rt/io/extensions.rs b/src/libstd/rt/io/extensions.rs index 55861f127bb..c6654e9dabe 100644 --- a/src/libstd/rt/io/extensions.rs +++ b/src/libstd/rt/io/extensions.rs @@ -292,13 +292,13 @@ impl<T: Reader> ReaderUtil for T { let start_len = buf.len(); let mut total_read = 0; - vec::reserve_at_least(buf, start_len + len); + buf.reserve_at_least(start_len + len); vec::raw::set_len(buf, start_len + len); do (|| { while total_read < len { let len = buf.len(); - let slice = vec::mut_slice(*buf, start_len + total_read, len); + let slice = buf.mut_slice(start_len + total_read, len); match self.read(slice) { Some(nread) => { total_read += nread; @@ -343,7 +343,9 @@ impl<T: Reader> ReaderByteConversions for T { fn read_le_uint_n(&mut self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut (val, pos, i) = (0u64, 0, nbytes); + let mut val = 0u64; + let mut pos = 0; + let mut i = nbytes; while i > 0 { val += (self.read_u8() as u64) << pos; pos += 8; @@ -359,7 +361,8 @@ impl<T: Reader> ReaderByteConversions for T { fn read_be_uint_n(&mut self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut (val, i) = (0u64, nbytes); + let mut val = 0u64; + let mut i = nbytes; while i > 0 { i -= 1; val += (self.read_u8() as u64) << i * 8; diff --git a/src/libstd/rt/io/mem.rs b/src/libstd/rt/io/mem.rs index bd9cff76e57..c93945a6a9a 100644 --- a/src/libstd/rt/io/mem.rs +++ b/src/libstd/rt/io/mem.rs @@ -86,7 +86,7 @@ impl Reader for MemReader { let write_len = min(buf.len(), self.buf.len() - self.pos); { let input = self.buf.slice(self.pos, self.pos + write_len); - let output = vec::mut_slice(buf, 0, write_len); + let output = buf.mut_slice(0, write_len); assert_eq!(input.len(), output.len()); vec::bytes::copy_memory(output, input, write_len); } diff --git a/src/libstd/rt/message_queue.rs b/src/libstd/rt/message_queue.rs index 5b60543344d..d561e81d032 100644 --- a/src/libstd/rt/message_queue.rs +++ b/src/libstd/rt/message_queue.rs @@ -9,7 +9,7 @@ // except according to those terms. use container::Container; -use kinds::Owned; +use kinds::Send; use vec::OwnedVector; use cell::Cell; use option::*; @@ -21,7 +21,7 @@ pub struct MessageQueue<T> { priv queue: ~Exclusive<~[T]> } -impl<T: Owned> MessageQueue<T> { +impl<T: Send> MessageQueue<T> { pub fn new() -> MessageQueue<T> { MessageQueue { queue: ~exclusive(~[]) diff --git a/src/libstd/rt/uv/timer.rs b/src/libstd/rt/uv/timer.rs index cd6fc5c0a25..14465eb7dfd 100644 --- a/src/libstd/rt/uv/timer.rs +++ b/src/libstd/rt/uv/timer.rs @@ -160,14 +160,14 @@ mod test { let mut timer2 = TimerWatcher::new(&mut loop_); do timer2.start(10, 0) |timer2, _| { - unsafe { *count_ptr += 1; } + *count_ptr += 1; timer2.close(||()); // Restart the original timer let mut timer = timer; do timer.start(1, 0) |timer, _| { - unsafe { *count_ptr += 1; } + *count_ptr += 1; timer.close(||()); } } diff --git a/src/libstd/rt/work_queue.rs b/src/libstd/rt/work_queue.rs index cfffc55a58c..00d27744268 100644 --- a/src/libstd/rt/work_queue.rs +++ b/src/libstd/rt/work_queue.rs @@ -13,7 +13,7 @@ use option::*; use vec::OwnedVector; use unstable::sync::{Exclusive, exclusive}; use cell::Cell; -use kinds::Owned; +use kinds::Send; use clone::Clone; pub struct WorkQueue<T> { @@ -21,7 +21,7 @@ pub struct WorkQueue<T> { priv queue: ~Exclusive<~[T]> } -impl<T: Owned> WorkQueue<T> { +impl<T: Send> WorkQueue<T> { pub fn new() -> WorkQueue<T> { WorkQueue { queue: ~exclusive(~[]) diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 801a4af281e..e47800d70c6 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -357,7 +357,8 @@ impl<'self> Iterator<(uint, uint)> for StrMatchesIndexIterator<'self> { fn next(&mut self) -> Option<(uint, uint)> { // See Issue #1932 for why this is a naive search let (h_len, n_len) = (self.haystack.len(), self.needle.len()); - let mut (match_start, match_i) = (0, 0); + let mut match_start = 0; + let mut match_i = 0; while self.position < h_len { if self.haystack[self.position] == self.needle[match_i] { @@ -462,7 +463,7 @@ pub fn each_split_within<'a>(ss: &'a str, cont }; - ss.iter().enumerate().advance(machine); + ss.iter().enumerate().advance(|x| machine(x)); // Let the automaton 'run out' by supplying trailing whitespace let mut fake_i = ss.len(); @@ -473,6 +474,31 @@ pub fn each_split_within<'a>(ss: &'a str, return cont; } +/** + * Replace all occurrences of one string with another + * + * # Arguments + * + * * s - The string containing substrings to replace + * * from - The string to replace + * * to - The replacement string + * + * # Return value + * + * The original string with all occurances of `from` replaced with `to` + */ +pub fn replace(s: &str, from: &str, to: &str) -> ~str { + let mut result = ~""; + let mut last_end = 0; + for s.matches_index_iter(from).advance |(start, end)| { + result.push_str(unsafe{raw::slice_bytes(s, last_end, start)}); + result.push_str(to); + last_end = end; + } + result.push_str(unsafe{raw::slice_bytes(s, last_end, s.len())}); + result +} + /* Section: Comparing strings */ @@ -631,6 +657,48 @@ pub fn with_capacity(capacity: uint) -> ~str { buf } +/** + * As char_len but for a slice of a string + * + * # Arguments + * + * * s - A valid string + * * start - The position inside `s` where to start counting in bytes + * * end - The position where to stop counting + * + * # Return value + * + * The number of Unicode characters in `s` between the given indices. + */ +pub fn count_chars(s: &str, start: uint, end: uint) -> uint { + assert!(s.is_char_boundary(start)); + assert!(s.is_char_boundary(end)); + let mut i = start; + let mut len = 0u; + while i < end { + let next = s.char_range_at(i).next; + len += 1u; + i = next; + } + return len; +} + +/// Counts the number of bytes taken by the first `n` chars in `s` +/// starting from `start`. +pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint { + assert!(s.is_char_boundary(start)); + let mut end = start; + let mut cnt = n; + let l = s.len(); + while cnt > 0u { + assert!(end < l); + let next = s.char_range_at(end).next; + cnt -= 1u; + end = next; + } + end - start +} + /// Given a first byte, determine how many bytes are in this UTF-8 character pub fn utf8_char_width(b: u8) -> uint { let byte: uint = b as uint; @@ -693,7 +761,7 @@ impl<'self> StrUtil for &'self str { // NB: len includes the trailing null. assert!(len > 0); if unsafe { *(ptr::offset(buf,len-1)) != 0 } { - to_owned(self).as_c_str(f) + to_owned(self).as_c_str(|s| f(s)) } else { f(buf as *libc::c_char) } @@ -737,7 +805,8 @@ pub mod raw { /// Create a Rust string from a null-terminated *u8 buffer pub unsafe fn from_buf(buf: *u8) -> ~str { - let mut (curr, i) = (buf, 0u); + let mut curr = buf; + let mut i = 0u; while *curr != 0u8 { i += 1u; curr = ptr::offset(buf, i); @@ -790,7 +859,8 @@ pub mod raw { /// invalidated later. pub unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str { let s = s as *u8; - let mut (curr, len) = (s, 0u); + let mut curr = s; + let mut len = 0u; while *curr != 0u8 { len += 1u; curr = ptr::offset(s, len); @@ -1070,6 +1140,17 @@ impl<'self> Str for @str { } } +impl<'self> Container for &'self str { + #[inline] + fn len(&self) -> uint { + do as_buf(*self) |_p, n| { n - 1u } + } + #[inline] + fn is_empty(&self) -> bool { + self.len() == 0 + } +} + #[allow(missing_doc)] pub trait StrSlice<'self> { fn contains<'a>(&self, needle: &'a str) -> bool; @@ -1088,10 +1169,8 @@ pub trait StrSlice<'self> { fn any_line_iter(&self) -> AnyLineIterator<'self>; fn word_iter(&self) -> WordIterator<'self>; fn ends_with(&self, needle: &str) -> bool; - fn is_empty(&self) -> bool; fn is_whitespace(&self) -> bool; fn is_alphanumeric(&self) -> bool; - fn len(&self) -> uint; fn char_len(&self) -> uint; fn slice(&self, begin: uint, end: uint) -> &'self str; @@ -1292,9 +1371,6 @@ impl<'self> StrSlice<'self> for &'self str { self.split_iter(char::is_whitespace).filter(|s| !s.is_empty()) } - /// Returns true if the string has length 0 - #[inline] - fn is_empty(&self) -> bool { self.len() == 0 } /** * Returns true if the string contains only whitespace * @@ -1309,11 +1385,6 @@ impl<'self> StrSlice<'self> for &'self str { */ #[inline] fn is_alphanumeric(&self) -> bool { self.iter().all(char::is_alphanumeric) } - /// Returns the size in bytes not counting the null terminator - #[inline] - fn len(&self) -> uint { - do as_buf(*self) |_p, n| { n - 1u } - } /// Returns the number of characters that a string holds #[inline] fn char_len(&self) -> uint { self.iter().len_() } @@ -1357,7 +1428,8 @@ impl<'self> StrSlice<'self> for &'self str { fn slice_chars(&self, begin: uint, end: uint) -> &'self str { assert!(begin <= end); // not sure how to use the iterators for this nicely. - let mut (position, count) = (0, 0); + let mut position = 0; + let mut count = 0; let l = self.len(); while count < begin && position < l { position = self.char_range_at(position).next; @@ -1505,7 +1577,8 @@ impl<'self> StrSlice<'self> for &'self str { * The original string with all occurances of `from` replaced with `to` */ pub fn replace(&self, from: &str, to: &str) -> ~str { - let mut (result, last_end) = (~"", 0); + let mut result = ~""; + let mut last_end = 0; for self.matches_index_iter(from).advance |(start, end)| { result.push_str(unsafe{raw::slice_bytes(*self, last_end, start)}); result.push_str(to); @@ -2081,7 +2154,7 @@ impl OwnedStr for ~str { pub fn reserve(&mut self, n: uint) { unsafe { let v: *mut ~[u8] = cast::transmute(self); - vec::reserve(&mut *v, n + 1); + (*v).reserve(n + 1); } } @@ -2115,8 +2188,8 @@ impl OwnedStr for ~str { * reallocating */ fn capacity(&self) -> uint { - let buf: &const ~[u8] = unsafe { cast::transmute(self) }; - let vcap = vec::capacity(buf); + let buf: &~[u8] = unsafe { cast::transmute(self) }; + let vcap = buf.capacity(); assert!(vcap > 0u); vcap - 1u } @@ -2249,7 +2322,7 @@ mod tests { assert!("" <= ""); assert!("" <= "foo"); assert!("foo" <= "foo"); - assert!("foo" != ~"bar"); + assert!("foo" != "bar"); } #[test] @@ -3156,6 +3229,7 @@ mod tests { #[test] fn test_add() { + #[allow(unnecessary_allocation)]; macro_rules! t ( ($s1:expr, $s2:expr, $e:expr) => { assert_eq!($s1 + $s2, $e); diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index 223afbce091..a8e8cfd163a 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -353,7 +353,7 @@ impl TaskBuilder { } /// Runs a task, while transfering ownership of one argument to the child. - pub fn spawn_with<A:Owned>(&mut self, arg: A, f: ~fn(v: A)) { + pub fn spawn_with<A:Send>(&mut self, arg: A, f: ~fn(v: A)) { let arg = Cell::new(arg); do self.spawn { f(arg.take()); @@ -373,7 +373,7 @@ impl TaskBuilder { * # Failure * Fails if a future_result was already set for this task. */ - pub fn try<T:Owned>(&mut self, f: ~fn() -> T) -> Result<T,()> { + pub fn try<T:Send>(&mut self, f: ~fn() -> T) -> Result<T,()> { let (po, ch) = stream::<T>(); let mut result = None; @@ -445,7 +445,7 @@ pub fn spawn_supervised(f: ~fn()) { task.spawn(f) } -pub fn spawn_with<A:Owned>(arg: A, f: ~fn(v: A)) { +pub fn spawn_with<A:Send>(arg: A, f: ~fn(v: A)) { /*! * Runs a task, while transfering ownership of one argument to the * child. @@ -478,7 +478,7 @@ pub fn spawn_sched(mode: SchedMode, f: ~fn()) { task.spawn(f) } -pub fn try<T:Owned>(f: ~fn() -> T) -> Result<T,()> { +pub fn try<T:Send>(f: ~fn() -> T) -> Result<T,()> { /*! * Execute a function in another task and return either the return value * of the function or result::err. @@ -934,17 +934,15 @@ fn test_spawn_sched_blocking() { let lock = testrt::rust_dbg_lock_create(); do spawn_sched(SingleThreaded) { - unsafe { - testrt::rust_dbg_lock_lock(lock); + testrt::rust_dbg_lock_lock(lock); - start_ch.send(()); + start_ch.send(()); - // Block the scheduler thread - testrt::rust_dbg_lock_wait(lock); - testrt::rust_dbg_lock_unlock(lock); + // Block the scheduler thread + testrt::rust_dbg_lock_wait(lock); + testrt::rust_dbg_lock_unlock(lock); - fin_ch.send(()); - } + fin_ch.send(()); }; // Wait until the other task has its lock diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 95fc53c1b55..c932a9660c2 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -230,11 +230,15 @@ fn each_ancestor(list: &mut AncestorList, // 'do_continue' - Did the forward_blk succeed at this point? (i.e., // should we recurse? or should our callers unwind?) + let forward_blk = Cell::new(forward_blk); + // The map defaults to None, because if ancestors is None, we're at // the end of the list, which doesn't make sense to coalesce. return do (**ancestors).map_default((None,false)) |ancestor_arc| { // NB: Takes a lock! (this ancestor node) do access_ancestors(ancestor_arc) |nobe| { + // Argh, but we couldn't give it to coalesce() otherwise. + let forward_blk = forward_blk.take(); // Check monotonicity assert!(last_generation > nobe.generation); /*##########################################################* @@ -636,7 +640,8 @@ fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { let child_data = Cell::new((notify_chan, child_arc, ancestors)); let result: ~fn() = || { // Agh. Get move-mode items into the closure. FIXME (#2829) - let mut (notify_chan, child_arc, ancestors) = child_data.take(); + let (notify_chan, child_arc, ancestors) = child_data.take(); + let mut ancestors = ancestors; // Child task runs this code. // Even if the below code fails to kick the child off, we must diff --git a/src/libstd/to_bytes.rs b/src/libstd/to_bytes.rs index 6f0c615d007..d6e92dd679e 100644 --- a/src/libstd/to_bytes.rs +++ b/src/libstd/to_bytes.rs @@ -232,7 +232,8 @@ impl<A:IterBytes,B:IterBytes> IterBytes for (A,B) { #[inline] fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { match *self { - (ref a, ref b) => { a.iter_bytes(lsb0, f) && b.iter_bytes(lsb0, f) } + (ref a, ref b) => { a.iter_bytes(lsb0, |b| f(b)) && + b.iter_bytes(lsb0, |b| f(b)) } } } } @@ -242,7 +243,9 @@ impl<A:IterBytes,B:IterBytes,C:IterBytes> IterBytes for (A,B,C) { fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { match *self { (ref a, ref b, ref c) => { - a.iter_bytes(lsb0, f) && b.iter_bytes(lsb0, f) && c.iter_bytes(lsb0, f) + a.iter_bytes(lsb0, |b| f(b)) && + b.iter_bytes(lsb0, |b| f(b)) && + c.iter_bytes(lsb0, |b| f(b)) } } } @@ -296,7 +299,7 @@ impl<A:IterBytes> IterBytes for Option<A> { #[inline] fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { match *self { - Some(ref a) => 0u8.iter_bytes(lsb0, f) && a.iter_bytes(lsb0, f), + Some(ref a) => 0u8.iter_bytes(lsb0, |b| f(b)) && a.iter_bytes(lsb0, |b| f(b)), None => 1u8.iter_bytes(lsb0, f) } } diff --git a/src/libstd/to_str.rs b/src/libstd/to_str.rs index ea0e212b14f..77701acd33e 100644 --- a/src/libstd/to_str.rs +++ b/src/libstd/to_str.rs @@ -53,7 +53,8 @@ impl<A:ToStr> ToStr for (A,) { impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> { #[inline] fn to_str(&self) -> ~str { - let mut (acc, first) = (~"{", true); + let mut acc = ~"{"; + let mut first = true; for self.iter().advance |(key, value)| { if first { first = false; @@ -73,7 +74,8 @@ impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> { impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> { #[inline] fn to_str(&self) -> ~str { - let mut (acc, first) = (~"{", true); + let mut acc = ~"{"; + let mut first = true; for self.iter().advance |element| { if first { first = false; @@ -121,7 +123,8 @@ impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) { impl<'self,A:ToStr> ToStr for &'self [A] { #[inline] fn to_str(&self) -> ~str { - let mut (acc, first) = (~"[", true); + let mut acc = ~"["; + let mut first = true; for self.iter().advance |elt| { if first { first = false; @@ -139,7 +142,8 @@ impl<'self,A:ToStr> ToStr for &'self [A] { impl<A:ToStr> ToStr for ~[A] { #[inline] fn to_str(&self) -> ~str { - let mut (acc, first) = (~"[", true); + let mut acc = ~"["; + let mut first = true; for self.iter().advance |elt| { if first { first = false; @@ -157,7 +161,8 @@ impl<A:ToStr> ToStr for ~[A] { impl<A:ToStr> ToStr for @[A] { #[inline] fn to_str(&self) -> ~str { - let mut (acc, first) = (~"[", true); + let mut acc = ~"["; + let mut first = true; for self.iter().advance |elt| { if first { first = false; diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index 8f70c75439a..b9b03ea5661 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -251,7 +251,7 @@ impl<T> TrieNode<T> { fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range(0, self.children.len()) |idx| { match self.children[idx] { - Internal(ref x) => if !x.each(f) { return false }, + Internal(ref x) => if !x.each(|i,t| f(i,t)) { return false }, External(k, ref v) => if !f(&k, v) { return false }, Nothing => () } @@ -262,7 +262,7 @@ impl<T> TrieNode<T> { fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range_rev(self.children.len(), 0) |idx| { match self.children[idx - 1] { - Internal(ref x) => if !x.each_reverse(f) { return false }, + Internal(ref x) => if !x.each_reverse(|i,t| f(i,t)) { return false }, External(k, ref v) => if !f(&k, v) { return false }, Nothing => () } @@ -273,7 +273,7 @@ impl<T> TrieNode<T> { fn mutate_values<'a>(&'a mut self, f: &fn(&uint, &mut T) -> bool) -> bool { for self.children.mut_iter().advance |child| { match *child { - Internal(ref mut x) => if !x.mutate_values(f) { + Internal(ref mut x) => if !x.mutate_values(|i,t| f(i,t)) { return false }, External(k, ref mut v) => if !f(&k, v) { return false }, diff --git a/src/libstd/unstable/atomics.rs b/src/libstd/unstable/atomics.rs index 45eced9846c..1e5ac305df3 100644 --- a/src/libstd/unstable/atomics.rs +++ b/src/libstd/unstable/atomics.rs @@ -62,7 +62,7 @@ pub struct AtomicPtr<T> { /** * An owned atomic pointer. Ensures that only a single reference to the data is held at any time. */ -#[no_drop_flag] +#[unsafe_no_drop_flag] pub struct AtomicOption<T> { priv p: *mut c_void } diff --git a/src/libstd/unstable/extfmt.rs b/src/libstd/unstable/extfmt.rs index 87bd25bdad3..624062a7ec4 100644 --- a/src/libstd/unstable/extfmt.rs +++ b/src/libstd/unstable/extfmt.rs @@ -94,6 +94,7 @@ use iterator::IteratorUtil; #[doc(hidden)] pub mod ct { use char; + use container::Container; use prelude::*; use str; diff --git a/src/libstd/unstable/global.rs b/src/libstd/unstable/global.rs index 4fde8f704b9..285a8114cc2 100644 --- a/src/libstd/unstable/global.rs +++ b/src/libstd/unstable/global.rs @@ -27,7 +27,7 @@ avoid hitting the mutex. use cast::{transmute}; use clone::Clone; -use kinds::Owned; +use kinds::Send; use libc::{c_void}; use option::{Option, Some, None}; use ops::Drop; @@ -43,7 +43,7 @@ use sys::Closure; pub type GlobalDataKey<'self,T> = &'self fn(v: T); -pub unsafe fn global_data_clone_create<T:Owned + Clone>( +pub unsafe fn global_data_clone_create<T:Send + Clone>( key: GlobalDataKey<T>, create: &fn() -> ~T) -> T { /*! * Clone a global value or, if it has not been created, @@ -59,7 +59,7 @@ pub unsafe fn global_data_clone_create<T:Owned + Clone>( global_data_clone_create_(key_ptr(key), create) } -unsafe fn global_data_clone_create_<T:Owned + Clone>( +unsafe fn global_data_clone_create_<T:Send + Clone>( key: uint, create: &fn() -> ~T) -> T { let mut clone_value: Option<T> = None; @@ -79,13 +79,13 @@ unsafe fn global_data_clone_create_<T:Owned + Clone>( return clone_value.unwrap(); } -unsafe fn global_data_modify<T:Owned>( +unsafe fn global_data_modify<T:Send>( key: GlobalDataKey<T>, op: &fn(Option<~T>) -> Option<~T>) { global_data_modify_(key_ptr(key), op) } -unsafe fn global_data_modify_<T:Owned>( +unsafe fn global_data_modify_<T:Send>( key: uint, op: &fn(Option<~T>) -> Option<~T>) { let mut old_dtor = None; @@ -124,7 +124,7 @@ unsafe fn global_data_modify_<T:Owned>( } } -pub unsafe fn global_data_clone<T:Owned + Clone>( +pub unsafe fn global_data_clone<T:Send + Clone>( key: GlobalDataKey<T>) -> Option<T> { let mut maybe_clone: Option<T> = None; do global_data_modify(key) |current| { @@ -220,7 +220,7 @@ fn get_global_state() -> Exclusive<GlobalState> { } } -fn key_ptr<T:Owned>(key: GlobalDataKey<T>) -> uint { +fn key_ptr<T:Send>(key: GlobalDataKey<T>) -> uint { unsafe { let closure: Closure = transmute(key); return transmute(closure.code); diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index 0f9298595ee..06c3ecb8147 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -17,7 +17,7 @@ use unstable::finally::Finally; use unstable::intrinsics; use ops::Drop; use clone::Clone; -use kinds::Owned; +use kinds::Send; /// An atomically reference counted pointer. /// @@ -31,7 +31,7 @@ struct AtomicRcBoxData<T> { data: Option<T>, } -impl<T: Owned> UnsafeAtomicRcBox<T> { +impl<T: Send> UnsafeAtomicRcBox<T> { pub fn new(data: T) -> UnsafeAtomicRcBox<T> { unsafe { let data = ~AtomicRcBoxData { count: 1, data: Some(data) }; @@ -61,7 +61,7 @@ impl<T: Owned> UnsafeAtomicRcBox<T> { } } -impl<T: Owned> Clone for UnsafeAtomicRcBox<T> { +impl<T: Send> Clone for UnsafeAtomicRcBox<T> { fn clone(&self) -> UnsafeAtomicRcBox<T> { unsafe { let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data); @@ -144,7 +144,7 @@ pub struct Exclusive<T> { x: UnsafeAtomicRcBox<ExData<T>> } -pub fn exclusive<T:Owned>(user_data: T) -> Exclusive<T> { +pub fn exclusive<T:Send>(user_data: T) -> Exclusive<T> { let data = ExData { lock: LittleLock(), failed: false, @@ -155,14 +155,14 @@ pub fn exclusive<T:Owned>(user_data: T) -> Exclusive<T> { } } -impl<T:Owned> Clone for Exclusive<T> { +impl<T:Send> Clone for Exclusive<T> { // Duplicate an exclusive ARC, as std::arc::clone. fn clone(&self) -> Exclusive<T> { Exclusive { x: self.x.clone() } } } -impl<T:Owned> Exclusive<T> { +impl<T:Send> Exclusive<T> { // Exactly like std::arc::mutex_arc,access(), but with the little_lock // instead of a proper mutex. Same reason for being unsafe. // diff --git a/src/libstd/util.rs b/src/libstd/util.rs index 6eddae17ce6..fd29d7dc14b 100644 --- a/src/libstd/util.rs +++ b/src/libstd/util.rs @@ -75,18 +75,14 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T { } /// A non-copyable dummy type. +#[deriving(Eq, TotalEq, Ord, TotalOrd)] +#[unsafe_no_drop_flag] pub struct NonCopyable; -impl NonCopyable { - /// Creates a dummy non-copyable structure and returns it for use. - pub fn new() -> NonCopyable { NonCopyable } -} - impl Drop for NonCopyable { fn drop(&self) { } } - /// A type with no inhabitants pub enum Void { } @@ -130,39 +126,73 @@ pub fn unreachable() -> ! { #[cfg(test)] mod tests { + use super::*; use option::{None, Some}; - use util::{Void, NonCopyable, id, replace, swap}; use either::{Either, Left, Right}; + use sys::size_of; + use kinds::Drop; #[test] - pub fn identity_crisis() { + fn identity_crisis() { // Writing a test for the identity function. How did it come to this? let x = ~[(5, false)]; //FIXME #3387 assert!(x.eq(id(copy x))); let y = copy x; assert!(x.eq(&id(y))); } + #[test] - pub fn test_swap() { + fn test_swap() { let mut x = 31337; let mut y = 42; swap(&mut x, &mut y); assert_eq!(x, 42); assert_eq!(y, 31337); } + #[test] - pub fn test_replace() { - let mut x = Some(NonCopyable::new()); + fn test_replace() { + let mut x = Some(NonCopyable); let y = replace(&mut x, None); assert!(x.is_none()); assert!(y.is_some()); } + #[test] - pub fn test_uninhabited() { + fn test_uninhabited() { let could_only_be_coin : Either <Void, ()> = Right (()); match could_only_be_coin { Right (coin) => coin, Left (is_void) => is_void.uninhabited () } } + + #[test] + fn test_noncopyable() { + assert_eq!(size_of::<NonCopyable>(), 0); + + // verify that `#[unsafe_no_drop_flag]` works as intended on a zero-size struct + + // NOTE: uncomment after snapshot, will not parse yet + //static mut did_run: bool = false; + + struct Foo { five: int } + + impl Drop for Foo { + fn drop(&self) { + assert_eq!(self.five, 5); + // NOTE: uncomment after snapshot, will not parse yet + //unsafe { + //did_run = true; + //} + } + } + + { + let _a = (NonCopyable, Foo { five: 5 }, NonCopyable); + } + + // NOTE: uncomment after snapshot, will not parse yet + //unsafe { assert_eq!(did_run, true); } + } } diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 56e6bacf93e..4e7943f7cfd 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -69,63 +69,6 @@ pub fn same_length<T, U>(xs: &const [T], ys: &const [U]) -> bool { } /** - * Reserves capacity for exactly `n` elements in the given vector. - * - * If the capacity for `v` is already equal to or greater than the requested - * capacity, then no action is taken. - * - * # Arguments - * - * * v - A vector - * * n - The number of elements to reserve space for - */ -#[inline] -pub fn reserve<T>(v: &mut ~[T], n: uint) { - // Only make the (slow) call into the runtime if we have to - use managed; - if capacity(v) < n { - unsafe { - let ptr: **raw::VecRepr = cast::transmute(v); - let td = get_tydesc::<T>(); - if ((**ptr).box_header.ref_count == - managed::raw::RC_MANAGED_UNIQUE) { - rustrt::vec_reserve_shared_actual(td, ptr, n as libc::size_t); - } else { - rustrt::vec_reserve_shared(td, ptr, n as libc::size_t); - } - } - } -} - -/** - * Reserves capacity for at least `n` elements in the given vector. - * - * This function will over-allocate in order to amortize the allocation costs - * in scenarios where the caller may need to repeatedly reserve additional - * space. - * - * If the capacity for `v` is already equal to or greater than the requested - * capacity, then no action is taken. - * - * # Arguments - * - * * v - A vector - * * n - The number of elements to reserve space for - */ -pub fn reserve_at_least<T>(v: &mut ~[T], n: uint) { - reserve(v, uint::next_power_of_two(n)); -} - -/// Returns the number of elements the vector can hold without reallocating -#[inline] -pub fn capacity<T>(v: &const ~[T]) -> uint { - unsafe { - let repr: **raw::VecRepr = transmute(v); - (**repr).unboxed.alloc / sys::nonzero_size_of::<T>() - } -} - -/** * Creates and initializes an owned vector. * * Creates an owned vector of size `n_elts` and initializes the elements @@ -179,7 +122,7 @@ pub fn to_owned<T:Copy>(t: &[T]) -> ~[T] { /// Creates a new vector with a capacity of `capacity` pub fn with_capacity<T>(capacity: uint) -> ~[T] { let mut vec = ~[]; - reserve(&mut vec, capacity); + vec.reserve(capacity); vec } @@ -238,85 +181,6 @@ pub fn build_sized_opt<A>(size: Option<uint>, // Accessors -/// Returns the first element of a vector -pub fn head<'r,T>(v: &'r [T]) -> &'r T { - if v.len() == 0 { fail!("head: empty vector") } - &v[0] -} - -/// Returns `Some(x)` where `x` is the first element of the slice `v`, -/// or `None` if the vector is empty. -pub fn head_opt<'r,T>(v: &'r [T]) -> Option<&'r T> { - if v.len() == 0 { None } else { Some(&v[0]) } -} - -/// Returns a vector containing all but the first element of a slice -pub fn tail<'r,T>(v: &'r [T]) -> &'r [T] { slice(v, 1, v.len()) } - -/// Returns a vector containing all but the first `n` elements of a slice -pub fn tailn<'r,T>(v: &'r [T], n: uint) -> &'r [T] { slice(v, n, v.len()) } - -/// Returns a vector containing all but the last element of a slice -pub fn init<'r,T>(v: &'r [T]) -> &'r [T] { slice(v, 0, v.len() - 1) } - -/// Returns a vector containing all but the last `n' elements of a slice -pub fn initn<'r,T>(v: &'r [T], n: uint) -> &'r [T] { - slice(v, 0, v.len() - n) -} - -/// Returns the last element of the slice `v`, failing if the slice is empty. -pub fn last<'r,T>(v: &'r [T]) -> &'r T { - if v.len() == 0 { fail!("last: empty vector") } - &v[v.len() - 1] -} - -/// Returns `Some(x)` where `x` is the last element of the slice `v`, or -/// `None` if the vector is empty. -pub fn last_opt<'r,T>(v: &'r [T]) -> Option<&'r T> { - if v.len() == 0 { None } else { Some(&v[v.len() - 1]) } -} - -/// Return a slice that points into another slice. -#[inline] -pub fn slice<'r,T>(v: &'r [T], start: uint, end: uint) -> &'r [T] { - assert!(start <= end); - assert!(end <= v.len()); - do as_imm_buf(v) |p, _len| { - unsafe { - transmute((ptr::offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) - } - } -} - -/// Return a slice that points into another slice. -#[inline] -pub fn mut_slice<'r,T>(v: &'r mut [T], start: uint, end: uint) - -> &'r mut [T] { - assert!(start <= end); - assert!(end <= v.len()); - do as_mut_buf(v) |p, _len| { - unsafe { - transmute((ptr::mut_offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) - } - } -} - -/// Return a slice that points into another slice. -#[inline] -pub fn const_slice<'r,T>(v: &'r const [T], start: uint, end: uint) - -> &'r const [T] { - assert!(start <= end); - assert!(end <= v.len()); - do as_const_buf(v) |p, _len| { - unsafe { - transmute((ptr::const_offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) - } - } -} - /// Copies /// Split the vector `v` by applying each element against the predicate `f`. @@ -327,15 +191,15 @@ pub fn split<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[~[T]] { let mut start = 0u; let mut result = ~[]; while start < ln { - match position_between(v, start, ln, f) { + match position_between(v, start, ln, |t| f(t)) { None => break, Some(i) => { - result.push(slice(v, start, i).to_owned()); + result.push(v.slice(start, i).to_owned()); start = i + 1u; } } } - result.push(slice(v, start, ln).to_owned()); + result.push(v.slice(start, ln).to_owned()); result } @@ -351,17 +215,17 @@ pub fn splitn<T:Copy>(v: &[T], n: uint, f: &fn(t: &T) -> bool) -> ~[~[T]] { let mut count = n; let mut result = ~[]; while start < ln && count > 0u { - match position_between(v, start, ln, f) { + match position_between(v, start, ln, |t| f(t)) { None => break, Some(i) => { - result.push(slice(v, start, i).to_owned()); + result.push(v.slice(start, i).to_owned()); // Make sure to skip the separator. start = i + 1u; count -= 1u; } } } - result.push(slice(v, start, ln).to_owned()); + result.push(v.slice(start, ln).to_owned()); result } @@ -376,15 +240,15 @@ pub fn rsplit<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[~[T]] { let mut end = ln; let mut result = ~[]; while end > 0 { - match rposition_between(v, 0, end, f) { + match rposition_between(v, 0, end, |t| f(t)) { None => break, Some(i) => { - result.push(slice(v, i + 1, end).to_owned()); + result.push(v.slice(i + 1, end).to_owned()); end = i; } } } - result.push(slice(v, 0u, end).to_owned()); + result.push(v.slice(0u, end).to_owned()); reverse(result); result } @@ -401,151 +265,21 @@ pub fn rsplitn<T:Copy>(v: &[T], n: uint, f: &fn(t: &T) -> bool) -> ~[~[T]] { let mut count = n; let mut result = ~[]; while end > 0u && count > 0u { - match rposition_between(v, 0u, end, f) { + match rposition_between(v, 0u, end, |t| f(t)) { None => break, Some(i) => { - result.push(slice(v, i + 1u, end).to_owned()); + result.push(v.slice(i + 1u, end).to_owned()); // Make sure to skip the separator. end = i; count -= 1u; } } } - result.push(slice(v, 0u, end).to_owned()); + result.push(v.slice(0u, end).to_owned()); reverse(result); result } -/** - * Partitions a vector into two new vectors: those that satisfies the - * predicate, and those that do not. - */ -pub fn partition<T>(v: ~[T], f: &fn(&T) -> bool) -> (~[T], ~[T]) { - let mut lefts = ~[]; - let mut rights = ~[]; - - // FIXME (#4355 maybe): using v.consume here crashes - // do v.consume |_, elt| { - do consume(v) |_, elt| { - if f(&elt) { - lefts.push(elt); - } else { - rights.push(elt); - } - } - - (lefts, rights) -} - -/** - * Partitions a vector into two new vectors: those that satisfies the - * predicate, and those that do not. - */ -pub fn partitioned<T:Copy>(v: &[T], f: &fn(&T) -> bool) -> (~[T], ~[T]) { - let mut lefts = ~[]; - let mut rights = ~[]; - - for v.iter().advance |elt| { - if f(elt) { - lefts.push(copy *elt); - } else { - rights.push(copy *elt); - } - } - - (lefts, rights) -} - -// Mutators - -/// Removes the first element from a vector and return it -pub fn shift<T>(v: &mut ~[T]) -> T { - unsafe { - assert!(!v.is_empty()); - - if v.len() == 1 { return v.pop() } - - if v.len() == 2 { - let last = v.pop(); - let first = v.pop(); - v.push(last); - return first; - } - - let ln = v.len(); - let next_ln = v.len() - 1; - - // Save the last element. We're going to overwrite its position - let work_elt = v.pop(); - // We still should have room to work where what last element was - assert!(capacity(v) >= ln); - // Pretend like we have the original length so we can use - // the vector copy_memory to overwrite the hole we just made - raw::set_len(&mut *v, ln); - - // Memcopy the head element (the one we want) to the location we just - // popped. For the moment it unsafely exists at both the head and last - // positions - { - let first_slice = slice(*v, 0, 1); - let last_slice = slice(*v, next_ln, ln); - raw::copy_memory(transmute(last_slice), first_slice, 1); - } - - // Memcopy everything to the left one element - { - let init_slice = slice(*v, 0, next_ln); - let tail_slice = slice(*v, 1, ln); - raw::copy_memory(transmute(init_slice), - tail_slice, - next_ln); - } - - // Set the new length. Now the vector is back to normal - raw::set_len(&mut *v, next_ln); - - // Swap out the element we want from the end - let vp = raw::to_mut_ptr(*v); - let vp = ptr::mut_offset(vp, next_ln - 1); - - ptr::replace_ptr(vp, work_elt) - } -} - -/// Prepend an element to the vector -pub fn unshift<T>(v: &mut ~[T], x: T) { - let vv = util::replace(v, ~[x]); - v.push_all_move(vv); -} - -/// Insert an element at position i within v, shifting all -/// elements after position i one position to the right. -pub fn insert<T>(v: &mut ~[T], i: uint, x: T) { - let len = v.len(); - assert!(i <= len); - - v.push(x); - let mut j = len; - while j > i { - swap(*v, j, j - 1); - j -= 1; - } -} - -/// Remove and return the element at position i within v, shifting -/// all elements after position i one position to the left. -pub fn remove<T>(v: &mut ~[T], i: uint) -> T { - let len = v.len(); - assert!(i < len); - - let mut j = i; - while j < len - 1 { - swap(*v, j, j + 1); - j += 1; - } - v.pop() -} - /// Consumes all elements, in a vector, moving them out into the / closure /// provided. The vector is traversed from the start to the end. /// @@ -607,131 +341,6 @@ pub fn consume_reverse<T>(mut v: ~[T], f: &fn(uint, v: T)) { } } -/// Remove the last element from a vector and return it -pub fn pop<T>(v: &mut ~[T]) -> T { - let ln = v.len(); - if ln == 0 { - fail!("sorry, cannot vec::pop an empty vector") - } - let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]); - unsafe { - let val = ptr::replace_ptr(valptr, intrinsics::init()); - raw::set_len(v, ln - 1u); - val - } -} - -/** - * Remove an element from anywhere in the vector and return it, replacing it - * with the last element. This does not preserve ordering, but is O(1). - * - * Fails if index >= length. - */ -pub fn swap_remove<T>(v: &mut ~[T], index: uint) -> T { - let ln = v.len(); - if index >= ln { - fail!("vec::swap_remove - index %u >= length %u", index, ln); - } - if index < ln - 1 { - swap(*v, index, ln - 1); - } - v.pop() -} - -/// Append an element to a vector -#[inline] -pub fn push<T>(v: &mut ~[T], initval: T) { - unsafe { - let repr: **raw::VecRepr = transmute(&mut *v); - let fill = (**repr).unboxed.fill; - if (**repr).unboxed.alloc > fill { - push_fast(v, initval); - } - else { - push_slow(v, initval); - } - } -} - -// This doesn't bother to make sure we have space. -#[inline] // really pretty please -unsafe fn push_fast<T>(v: &mut ~[T], initval: T) { - let repr: **mut raw::VecRepr = transmute(v); - let fill = (**repr).unboxed.fill; - (**repr).unboxed.fill += sys::nonzero_size_of::<T>(); - let p = to_unsafe_ptr(&((**repr).unboxed.data)); - let p = ptr::offset(p, fill) as *mut T; - intrinsics::move_val_init(&mut(*p), initval); -} - -#[inline(never)] -fn push_slow<T>(v: &mut ~[T], initval: T) { - let new_len = v.len() + 1; - reserve_at_least(&mut *v, new_len); - unsafe { push_fast(v, initval) } -} - -/// Iterates over the slice `rhs`, copies each element, and then appends it to -/// the vector provided `v`. The `rhs` vector is traversed in-order. -/// -/// # Example -/// -/// ~~~ {.rust} -/// let mut a = ~[1]; -/// vec::push_all(&mut a, [2, 3, 4]); -/// assert!(a == ~[1, 2, 3, 4]); -/// ~~~ -#[inline] -pub fn push_all<T:Copy>(v: &mut ~[T], rhs: &const [T]) { - let new_len = v.len() + rhs.len(); - reserve(&mut *v, new_len); - - for uint::range(0u, rhs.len()) |i| { - push(&mut *v, unsafe { raw::get(rhs, i) }) - } -} - -/// Takes ownership of the vector `rhs`, moving all elements into the specified -/// vector `v`. This does not copy any elements, and it is illegal to use the -/// `rhs` vector after calling this method (because it is moved here). -/// -/// # Example -/// -/// ~~~ {.rust} -/// let mut a = ~[~1]; -/// vec::push_all_move(&mut a, ~[~2, ~3, ~4]); -/// assert!(a == ~[~1, ~2, ~3, ~4]); -/// ~~~ -#[inline] -pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) { - let new_len = v.len() + rhs.len(); - reserve(&mut *v, new_len); - unsafe { - do as_mut_buf(rhs) |p, len| { - for uint::range(0, len) |i| { - let x = ptr::replace_ptr(ptr::mut_offset(p, i), - intrinsics::uninit()); - push(&mut *v, x); - } - } - raw::set_len(&mut rhs, 0); - } -} - -/// Shorten a vector, dropping excess elements. -pub fn truncate<T>(v: &mut ~[T], newlen: uint) { - do as_mut_buf(*v) |p, oldlen| { - assert!(newlen <= oldlen); - unsafe { - // This loop is optimized out for non-drop types. - for uint::range(newlen, oldlen) |i| { - ptr::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit()); - } - } - } - unsafe { raw::set_len(&mut *v, newlen); } -} - /** * Remove consecutive repeated elements from a vector; if the vector is * sorted, this removes all duplicates. @@ -739,7 +348,8 @@ pub fn truncate<T>(v: &mut ~[T], newlen: uint) { pub fn dedup<T:Eq>(v: &mut ~[T]) { unsafe { if v.len() < 1 { return; } - let mut (last_written, next_to_read) = (0, 1); + let mut last_written = 0; + let mut next_to_read = 1; do as_const_buf(*v) |p, ln| { // We have a mutable reference to v, so we can make arbitrary // changes. (cf. push and pop) @@ -800,7 +410,7 @@ pub fn append_one<T>(lhs: ~[T], x: T) -> ~[T] { */ pub fn grow<T:Copy>(v: &mut ~[T], n: uint, initval: &T) { let new_len = v.len() + n; - reserve_at_least(&mut *v, new_len); + v.reserve_at_least(new_len); let mut i: uint = 0u; while i < n { @@ -824,7 +434,7 @@ pub fn grow<T:Copy>(v: &mut ~[T], n: uint, initval: &T) { */ pub fn grow_fn<T>(v: &mut ~[T], n: uint, op: &fn(uint) -> T) { let new_len = v.len() + n; - reserve_at_least(&mut *v, new_len); + v.reserve_at_least(new_len); let mut i: uint = 0u; while i < n { v.push(op(i)); @@ -981,26 +591,6 @@ pub fn filtered<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[T] { result } -/** - * Like `filter()`, but in place. Preserves order of `v`. Linear time. - */ -pub fn retain<T>(v: &mut ~[T], f: &fn(t: &T) -> bool) { - let len = v.len(); - let mut deleted: uint = 0; - - for uint::range(0, len) |i| { - if !f(&v[i]) { - deleted += 1; - } else if deleted > 0 { - swap(*v, i - deleted, i); - } - } - - if deleted > 0 { - v.truncate(len - deleted); - } -} - /// Flattens a vector of vectors of T into a single vector of T. pub fn concat<T:Copy>(v: &[~[T]]) -> ~[T] { v.concat_vec() } @@ -1209,7 +799,8 @@ pub fn bsearch_elem<T:TotalOrd>(v: &[T], x: &T) -> Option<uint> { * Convert a vector of pairs into a pair of vectors, by reference. As unzip(). */ pub fn unzip_slice<T:Copy,U:Copy>(v: &[(T, U)]) -> (~[T], ~[U]) { - let mut (ts, us) = (~[], ~[]); + let mut ts = ~[]; + let mut us = ~[]; for v.iter().advance |p| { let (t, u) = copy *p; ts.push(t); @@ -1227,7 +818,8 @@ pub fn unzip_slice<T:Copy,U:Copy>(v: &[(T, U)]) -> (~[T], ~[U]) { * of the i-th tuple of the input vector. */ pub fn unzip<T,U>(v: ~[(T, U)]) -> (~[T], ~[U]) { - let mut (ts, us) = (~[], ~[]); + let mut ts = ~[]; + let mut us = ~[]; do consume(v) |_i, p| { let (t, u) = p; ts.push(t); @@ -1652,13 +1244,11 @@ impl<'self,T:Copy> CopyableVector<T> for &'self [T] { /// Returns a copy of `v`. #[inline] fn to_owned(&self) -> ~[T] { - let mut result = ~[]; - reserve(&mut result, self.len()); + let mut result = with_capacity(self.len()); for self.iter().advance |e| { result.push(copy *e); } result - } } @@ -1689,7 +1279,14 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { /// Return a slice that points into another slice. #[inline] fn slice(&self, start: uint, end: uint) -> &'self [T] { - slice(*self, start, end) + assert!(start <= end); + assert!(end <= self.len()); + do as_imm_buf(*self) |p, _len| { + unsafe { + transmute((ptr::offset(p, start), + (end - start) * sys::nonzero_size_of::<T>())) + } + } } #[inline] @@ -1712,35 +1309,49 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { /// Returns the first element of a vector, failing if the vector is empty. #[inline] - fn head(&self) -> &'self T { head(*self) } + fn head(&self) -> &'self T { + if self.len() == 0 { fail!("head: empty vector") } + &self[0] + } - /// Returns the first element of a vector + /// Returns the first element of a vector, or `None` if it is empty #[inline] - fn head_opt(&self) -> Option<&'self T> { head_opt(*self) } + fn head_opt(&self) -> Option<&'self T> { + if self.len() == 0 { None } else { Some(&self[0]) } + } /// Returns all but the first element of a vector #[inline] - fn tail(&self) -> &'self [T] { tail(*self) } + fn tail(&self) -> &'self [T] { self.slice(1, self.len()) } /// Returns all but the first `n' elements of a vector #[inline] - fn tailn(&self, n: uint) -> &'self [T] { tailn(*self, n) } + fn tailn(&self, n: uint) -> &'self [T] { self.slice(n, self.len()) } - /// Returns all but the last elemnt of a vector + /// Returns all but the last element of a vector #[inline] - fn init(&self) -> &'self [T] { init(*self) } + fn init(&self) -> &'self [T] { + self.slice(0, self.len() - 1) + } /// Returns all but the last `n' elemnts of a vector #[inline] - fn initn(&self, n: uint) -> &'self [T] { initn(*self, n) } + fn initn(&self, n: uint) -> &'self [T] { + self.slice(0, self.len() - n) + } - /// Returns the last element of a `v`, failing if the vector is empty. + /// Returns the last element of a vector, failing if the vector is empty. #[inline] - fn last(&self) -> &'self T { last(*self) } + fn last(&self) -> &'self T { + if self.len() == 0 { fail!("last: empty vector") } + &self[self.len() - 1] + } - /// Returns the last element of a `v`, failing if the vector is empty. + /// Returns the last element of a vector, or `None` if it is empty. #[inline] - fn last_opt(&self) -> Option<&'self T> { last_opt(*self) } + fn last_opt(&self) -> Option<&'self T> { + if self.len() == 0 { None } else { Some(&self[self.len() - 1]) } + } /** * Find the last index matching some predicate @@ -1865,7 +1476,18 @@ impl<'self,T:Copy> ImmutableCopyableVector<T> for &'self [T] { */ #[inline] fn partitioned(&self, f: &fn(&T) -> bool) -> (~[T], ~[T]) { - partitioned(*self, f) + let mut lefts = ~[]; + let mut rights = ~[]; + + for self.iter().advance |elt| { + if f(elt) { + lefts.push(copy *elt); + } else { + rights.push(copy *elt); + } + } + + (lefts, rights) } /// Returns the element at the given index, without doing bounds checking. @@ -1877,7 +1499,13 @@ impl<'self,T:Copy> ImmutableCopyableVector<T> for &'self [T] { #[allow(missing_doc)] pub trait OwnedVector<T> { + fn reserve(&mut self, n: uint); + fn reserve_at_least(&mut self, n: uint); + fn capacity(&self) -> uint; + fn push(&mut self, t: T); + unsafe fn push_fast(&mut self, t: T); + fn push_all_move(&mut self, rhs: ~[T]); fn pop(&mut self) -> T; fn shift(&mut self) -> T; @@ -1895,54 +1523,276 @@ pub trait OwnedVector<T> { } impl<T> OwnedVector<T> for ~[T] { + /** + * Reserves capacity for exactly `n` elements in the given vector. + * + * If the capacity for `self` is already equal to or greater than the requested + * capacity, then no action is taken. + * + * # Arguments + * + * * n - The number of elements to reserve space for + */ #[inline] - fn push(&mut self, t: T) { - push(self, t); + fn reserve(&mut self, n: uint) { + // Only make the (slow) call into the runtime if we have to + use managed; + if self.capacity() < n { + unsafe { + let ptr: **raw::VecRepr = cast::transmute(self); + let td = get_tydesc::<T>(); + if ((**ptr).box_header.ref_count == + managed::raw::RC_MANAGED_UNIQUE) { + rustrt::vec_reserve_shared_actual(td, ptr, n as libc::size_t); + } else { + rustrt::vec_reserve_shared(td, ptr, n as libc::size_t); + } + } + } } + /** + * Reserves capacity for at least `n` elements in the given vector. + * + * This function will over-allocate in order to amortize the allocation costs + * in scenarios where the caller may need to repeatedly reserve additional + * space. + * + * If the capacity for `self` is already equal to or greater than the requested + * capacity, then no action is taken. + * + * # Arguments + * + * * n - The number of elements to reserve space for + */ + fn reserve_at_least(&mut self, n: uint) { + self.reserve(uint::next_power_of_two(n)); + } + + /// Returns the number of elements the vector can hold without reallocating. #[inline] - fn push_all_move(&mut self, rhs: ~[T]) { - push_all_move(self, rhs); + fn capacity(&self) -> uint { + unsafe { + let repr: **raw::VecRepr = transmute(self); + (**repr).unboxed.alloc / sys::nonzero_size_of::<T>() + } } + /// Append an element to a vector #[inline] + fn push(&mut self, t: T) { + unsafe { + let repr: **raw::VecRepr = transmute(&mut *self); + let fill = (**repr).unboxed.fill; + if (**repr).unboxed.alloc <= fill { + // need more space + reserve_no_inline(self); + } + + self.push_fast(t); + } + + // this peculiar function is because reserve_at_least is very + // large (because of reserve), and will be inlined, which + // makes push too large. + #[inline(never)] + fn reserve_no_inline<T>(v: &mut ~[T]) { + let new_len = v.len() + 1; + v.reserve_at_least(new_len); + } + } + + // This doesn't bother to make sure we have space. + #[inline] // really pretty please + unsafe fn push_fast(&mut self, t: T) { + let repr: **mut raw::VecRepr = transmute(self); + let fill = (**repr).unboxed.fill; + (**repr).unboxed.fill += sys::nonzero_size_of::<T>(); + let p = to_unsafe_ptr(&((**repr).unboxed.data)); + let p = ptr::offset(p, fill) as *mut T; + intrinsics::move_val_init(&mut(*p), t); + } + + /// Takes ownership of the vector `rhs`, moving all elements into + /// the current vector. This does not copy any elements, and it is + /// illegal to use the `rhs` vector after calling this method + /// (because it is moved here). + /// + /// # Example + /// + /// ~~~ {.rust} + /// let mut a = ~[~1]; + /// a.push_all_move(~[~2, ~3, ~4]); + /// assert!(a == ~[~1, ~2, ~3, ~4]); + /// ~~~ + #[inline] + fn push_all_move(&mut self, mut rhs: ~[T]) { + let new_len = self.len() + rhs.len(); + self.reserve(new_len); + unsafe { + do as_mut_buf(rhs) |p, len| { + for uint::range(0, len) |i| { + let x = ptr::replace_ptr(ptr::mut_offset(p, i), + intrinsics::uninit()); + self.push(x); + } + } + raw::set_len(&mut rhs, 0); + } + } + + /// Remove the last element from a vector and return it fn pop(&mut self) -> T { - pop(self) + let ln = self.len(); + if ln == 0 { + fail!("sorry, cannot pop an empty vector") + } + let valptr = ptr::to_mut_unsafe_ptr(&mut self[ln - 1u]); + unsafe { + let val = ptr::replace_ptr(valptr, intrinsics::init()); + raw::set_len(self, ln - 1u); + val + } } - #[inline] + /// Removes the first element from a vector and return it fn shift(&mut self) -> T { - shift(self) + unsafe { + assert!(!self.is_empty()); + + if self.len() == 1 { return self.pop() } + + if self.len() == 2 { + let last = self.pop(); + let first = self.pop(); + self.push(last); + return first; + } + + let ln = self.len(); + let next_ln = self.len() - 1; + + // Save the last element. We're going to overwrite its position + let work_elt = self.pop(); + // We still should have room to work where what last element was + assert!(self.capacity() >= ln); + // Pretend like we have the original length so we can use + // the vector copy_memory to overwrite the hole we just made + raw::set_len(self, ln); + + // Memcopy the head element (the one we want) to the location we just + // popped. For the moment it unsafely exists at both the head and last + // positions + { + let first_slice = self.slice(0, 1); + let last_slice = self.slice(next_ln, ln); + raw::copy_memory(transmute(last_slice), first_slice, 1); + } + + // Memcopy everything to the left one element + { + let init_slice = self.slice(0, next_ln); + let tail_slice = self.slice(1, ln); + raw::copy_memory(transmute(init_slice), + tail_slice, + next_ln); + } + + // Set the new length. Now the vector is back to normal + raw::set_len(self, next_ln); + + // Swap out the element we want from the end + let vp = raw::to_mut_ptr(*self); + let vp = ptr::mut_offset(vp, next_ln - 1); + + ptr::replace_ptr(vp, work_elt) + } } - #[inline] + /// Prepend an element to the vector fn unshift(&mut self, x: T) { - unshift(self, x) + let v = util::replace(self, ~[x]); + self.push_all_move(v); } - #[inline] + /// Insert an element at position i within v, shifting all + /// elements after position i one position to the right. fn insert(&mut self, i: uint, x:T) { - insert(self, i, x) + let len = self.len(); + assert!(i <= len); + + self.push(x); + let mut j = len; + while j > i { + swap(*self, j, j - 1); + j -= 1; + } } - #[inline] + /// Remove and return the element at position i within v, shifting + /// all elements after position i one position to the left. fn remove(&mut self, i: uint) -> T { - remove(self, i) + let len = self.len(); + assert!(i < len); + + let mut j = i; + while j < len - 1 { + swap(*self, j, j + 1); + j += 1; + } + self.pop() } - #[inline] + /** + * Remove an element from anywhere in the vector and return it, replacing it + * with the last element. This does not preserve ordering, but is O(1). + * + * Fails if index >= length. + */ fn swap_remove(&mut self, index: uint) -> T { - swap_remove(self, index) + let ln = self.len(); + if index >= ln { + fail!("vec::swap_remove - index %u >= length %u", index, ln); + } + if index < ln - 1 { + swap(*self, index, ln - 1); + } + self.pop() } - #[inline] + /// Shorten a vector, dropping excess elements. fn truncate(&mut self, newlen: uint) { - truncate(self, newlen); + do as_mut_buf(*self) |p, oldlen| { + assert!(newlen <= oldlen); + unsafe { + // This loop is optimized out for non-drop types. + for uint::range(newlen, oldlen) |i| { + ptr::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit()); + } + } + } + unsafe { raw::set_len(self, newlen); } } - #[inline] + + /** + * Like `filter()`, but in place. Preserves order of `v`. Linear time. + */ fn retain(&mut self, f: &fn(t: &T) -> bool) { - retain(self, f); + let len = self.len(); + let mut deleted: uint = 0; + + for uint::range(0, len) |i| { + if !f(&self[i]) { + deleted += 1; + } else if deleted > 0 { + swap(*self, i - deleted, i); + } + } + + if deleted > 0 { + self.truncate(len - deleted); + } } #[inline] @@ -1966,7 +1816,18 @@ impl<T> OwnedVector<T> for ~[T] { */ #[inline] fn partition(self, f: &fn(&T) -> bool) -> (~[T], ~[T]) { - partition(self, f) + let mut lefts = ~[]; + let mut rights = ~[]; + + do self.consume |_, elt| { + if f(&elt) { + lefts.push(elt); + } else { + rights.push(elt); + } + } + + (lefts, rights) } #[inline] @@ -1988,9 +1849,24 @@ pub trait OwnedCopyableVector<T:Copy> { } impl<T:Copy> OwnedCopyableVector<T> for ~[T] { + /// Iterates over the slice `rhs`, copies each element, and then appends it to + /// the vector provided `v`. The `rhs` vector is traversed in-order. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let mut a = ~[1]; + /// a.push_all([2, 3, 4]); + /// assert!(a == ~[1, 2, 3, 4]); + /// ~~~ #[inline] fn push_all(&mut self, rhs: &const [T]) { - push_all(self, rhs); + let new_len = self.len() + rhs.len(); + self.reserve(new_len); + + for uint::range(0u, rhs.len()) |i| { + self.push(unsafe { raw::get(rhs, i) }) + } } #[inline] @@ -2042,9 +1918,17 @@ pub trait MutableVector<'self, T> { } impl<'self,T> MutableVector<'self, T> for &'self mut [T] { + /// Return a slice that points into another slice. #[inline] fn mut_slice(self, start: uint, end: uint) -> &'self mut [T] { - mut_slice(self, start, end) + assert!(start <= end); + assert!(end <= self.len()); + do as_mut_buf(self) |p, _len| { + unsafe { + transmute((ptr::mut_offset(p, start), + (end - start) * sys::nonzero_size_of::<T>())) + } + } } #[inline] @@ -2462,6 +2346,7 @@ impl<T> FromIter<T> for ~[T]{ } } +#[cfg(stage0)] impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] { pub fn from_iterator(iterator: &mut T) -> ~[A] { let mut xs = ~[]; @@ -2472,7 +2357,8 @@ impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] { } } -/* FIXME: #7341 - ICE + +#[cfg(not(stage0))] impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] { pub fn from_iterator(iterator: &mut T) -> ~[A] { let (lower, _) = iterator.size_hint(); @@ -2483,7 +2369,7 @@ impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] { xs } } -*/ + #[cfg(test)] mod tests { @@ -2713,7 +2599,7 @@ mod tests { fn test_slice() { // Test fixed length vector. let vec_fixed = [1, 2, 3, 4]; - let v_a = slice(vec_fixed, 1u, vec_fixed.len()).to_owned(); + let v_a = vec_fixed.slice(1u, vec_fixed.len()).to_owned(); assert_eq!(v_a.len(), 3u); assert_eq!(v_a[0], 2); assert_eq!(v_a[1], 3); @@ -2721,14 +2607,14 @@ mod tests { // Test on stack. let vec_stack = &[1, 2, 3]; - let v_b = slice(vec_stack, 1u, 3u).to_owned(); + let v_b = vec_stack.slice(1u, 3u).to_owned(); assert_eq!(v_b.len(), 2u); assert_eq!(v_b[0], 2); assert_eq!(v_b[1], 3); // Test on managed heap. let vec_managed = @[1, 2, 3, 4, 5]; - let v_c = slice(vec_managed, 0u, 3u).to_owned(); + let v_c = vec_managed.slice(0u, 3u).to_owned(); assert_eq!(v_c.len(), 3u); assert_eq!(v_c[0], 1); assert_eq!(v_c[1], 2); @@ -2736,7 +2622,7 @@ mod tests { // Test on exchange heap. let vec_unique = ~[1, 2, 3, 4, 5, 6]; - let v_d = slice(vec_unique, 1u, 6u).to_owned(); + let v_d = vec_unique.slice(1u, 6u).to_owned(); assert_eq!(v_d.len(), 5u); assert_eq!(v_d[0], 2); assert_eq!(v_d[1], 3); @@ -3329,11 +3215,10 @@ mod tests { #[test] fn test_partition() { - // FIXME (#4355 maybe): using v.partition here crashes - assert_eq!(partition(~[], |x: &int| *x < 3), (~[], ~[])); - assert_eq!(partition(~[1, 2, 3], |x: &int| *x < 4), (~[1, 2, 3], ~[])); - assert_eq!(partition(~[1, 2, 3], |x: &int| *x < 2), (~[1], ~[2, 3])); - assert_eq!(partition(~[1, 2, 3], |x: &int| *x < 0), (~[], ~[1, 2, 3])); + assert_eq!((~[]).partition(|x: &int| *x < 3), (~[], ~[])); + assert_eq!((~[1, 2, 3]).partition(|x: &int| *x < 4), (~[1, 2, 3], ~[])); + assert_eq!((~[1, 2, 3]).partition(|x: &int| *x < 2), (~[1], ~[2, 3])); + assert_eq!((~[1, 2, 3]).partition(|x: &int| *x < 0), (~[], ~[1, 2, 3])); } #[test] @@ -3453,11 +3338,11 @@ mod tests { #[test] fn test_capacity() { let mut v = ~[0u64]; - reserve(&mut v, 10u); - assert_eq!(capacity(&v), 10u); + v.reserve(10u); + assert_eq!(v.capacity(), 10u); let mut v = ~[0u32]; - reserve(&mut v, 10u); - assert_eq!(capacity(&v), 10u); + v.reserve(10u); + assert_eq!(v.capacity(), 10u); } #[test] @@ -3981,11 +3866,11 @@ mod tests { fn test_vec_zero() { use num::Zero; macro_rules! t ( - ($ty:ty) => { + ($ty:ty) => {{ let v: $ty = Zero::zero(); assert!(v.is_empty()); assert!(v.is_zero()); - } + }} ); t!(&[int]); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index feb03896558..bc432c4c7b0 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -17,17 +17,14 @@ use parse::token::{interner_get, str_to_ident}; use std::hashmap::HashMap; use std::option::Option; -use std::to_bytes::IterBytes; -use std::to_bytes; use std::to_str::ToStr; use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; - // an identifier contains a Name (index into the interner // table) and a SyntaxContext to track renaming and // macro expansion per Flatt et al., "Macros // That Work Together" -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct ident { name: Name, ctxt: SyntaxContext } /// Construct an identifier with the given name and an empty context: @@ -57,7 +54,7 @@ pub struct SCTable { pub static empty_ctxt : uint = 0; pub static illegal_ctxt : uint = 1; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum SyntaxContext_ { EmptyCtxt, Mark (Mrk,SyntaxContext), @@ -86,42 +83,28 @@ impl<S:Encoder> Encodable<S> for ident { } } +#[deriving(IterBytes)] impl<D:Decoder> Decodable<D> for ident { fn decode(d: &mut D) -> ident { str_to_ident(d.read_str()) } } -impl to_bytes::IterBytes for ident { - #[inline] - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.name.iter_bytes(lsb0, f) - } -} - // Functions may or may not have names. pub type fn_ident = Option<ident>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct Lifetime { id: node_id, span: span, ident: ident } -impl to_bytes::IterBytes for Lifetime { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.id.iter_bytes(lsb0, f) && - self.span.iter_bytes(lsb0, f) && - self.ident.iter_bytes(lsb0, f) - } -} - // a "Path" is essentially Rust's notion of a name; // for instance: core::cmp::Eq . It's represented // as a sequence of identifiers, along with a bunch // of supporting information. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct Path { span: span, global: bool, @@ -134,7 +117,7 @@ pub type crate_num = int; pub type node_id = int; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct def_id { crate: crate_num, node: node_id, @@ -143,24 +126,24 @@ pub struct def_id { pub static local_crate: crate_num = 0; pub static crate_node_id: node_id = 0; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] // The AST represents all type param bounds as types. // typeck::collect::compute_bounds matches these against // the "special" built-in traits (see middle::lang_items) and -// detects Copy, Send, Owned, and Const. +// detects Copy, Send, Send, and Freeze. pub enum TyParamBound { TraitTyParamBound(@trait_ref), RegionTyParamBound } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct TyParam { ident: ident, id: node_id, bounds: @OptVec<TyParamBound> } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct Generics { lifetimes: OptVec<Lifetime>, ty_params: OptVec<TyParam> @@ -178,7 +161,7 @@ impl Generics { } } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum def { def_fn(def_id, purity), def_static_method(/* method */ def_id, @@ -205,7 +188,8 @@ pub enum def { def_struct(def_id), def_typaram_binder(node_id), /* struct, impl or trait with ty params */ def_region(node_id), - def_label(node_id) + def_label(node_id), + def_method(def_id /* method */, Option<def_id> /* trait */), } @@ -215,7 +199,7 @@ pub type crate_cfg = ~[@meta_item]; pub type crate = spanned<crate_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct crate_ { module: _mod, attrs: ~[attribute], @@ -224,7 +208,7 @@ pub struct crate_ { pub type meta_item = spanned<meta_item_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum meta_item_ { meta_word(@str), meta_list(@str, ~[@meta_item]), @@ -233,7 +217,7 @@ pub enum meta_item_ { pub type blk = spanned<blk_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct blk_ { view_items: ~[@view_item], stmts: ~[@stmt], @@ -242,40 +226,26 @@ pub struct blk_ { rules: blk_check_mode, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct pat { id: node_id, node: pat_, span: span, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct field_pat { ident: ident, pat: @pat, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum binding_mode { bind_by_ref(mutability), bind_infer } -impl to_bytes::IterBytes for binding_mode { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - bind_by_ref(ref m) => { - 0u8.iter_bytes(lsb0, f) && m.iter_bytes(lsb0, f) - } - - bind_infer => { - 1u8.iter_bytes(lsb0, f) - } - } - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum pat_ { pat_wild, // A pat_ident may either be a new bound variable, @@ -300,28 +270,16 @@ pub enum pat_ { pat_vec(~[@pat], Option<@pat>, ~[@pat]) } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum mutability { m_mutbl, m_imm, m_const, } -impl to_bytes::IterBytes for mutability { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum Sigil { BorrowedSigil, OwnedSigil, ManagedSigil } -impl to_bytes::IterBytes for Sigil { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as uint).iter_bytes(lsb0, f) - } -} - impl ToStr for Sigil { fn to_str(&self) -> ~str { match *self { @@ -332,7 +290,7 @@ impl ToStr for Sigil { } } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum vstore { // FIXME (#3469): Change uint to @expr (actually only constant exprs) vstore_fixed(Option<uint>), // [1,2,3,4] @@ -341,7 +299,7 @@ pub enum vstore { vstore_slice(Option<@Lifetime>) // &'foo? [1,2,3,4] } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum expr_vstore { expr_vstore_uniq, // ~[1,2,3,4] expr_vstore_box, // @[1,2,3,4] @@ -350,7 +308,7 @@ pub enum expr_vstore { expr_vstore_mut_slice, // &mut [1,2,3,4] } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum binop { add, subtract, @@ -372,7 +330,7 @@ pub enum binop { gt, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum unop { box(mutability), uniq(mutability), @@ -383,7 +341,7 @@ pub enum unop { pub type stmt = spanned<stmt_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum stmt_ { // could be an item or a local (let) binding: stmt_decl(@decl, node_id), @@ -400,7 +358,7 @@ pub enum stmt_ { // FIXME (pending discussion of #1697, #2178...): local should really be // a refinement on pat. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct local_ { is_mutbl: bool, ty: @Ty, @@ -413,7 +371,7 @@ pub type local = spanned<local_>; pub type decl = spanned<decl_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum decl_ { // a local (let) binding: decl_local(@local), @@ -421,14 +379,14 @@ pub enum decl_ { decl_item(@item), } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct arm { pats: ~[@pat], guard: Option<@expr>, body: blk, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct field_ { ident: ident, expr: @expr, @@ -436,10 +394,10 @@ pub struct field_ { pub type field = spanned<field_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum blk_check_mode { default_blk, unsafe_blk, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct expr { id: node_id, node: expr_, @@ -459,14 +417,14 @@ impl expr { } } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum CallSugar { NoSugar, DoSugar, ForSugar } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum expr_ { expr_vstore(@expr, expr_vstore), expr_vec(~[@expr], mutability), @@ -537,7 +495,7 @@ pub enum expr_ { // else knows what to do with them, so you'll probably get a syntax // error. // -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] #[doc="For macro invocations; parsing is delegated to the macro"] pub enum token_tree { // a single token @@ -610,7 +568,7 @@ pub enum token_tree { // pub type matcher = spanned<matcher_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum matcher_ { // match one token match_tok(::parse::token::Token), @@ -623,14 +581,14 @@ pub enum matcher_ { pub type mac = spanned<mac_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum mac_ { mac_invoc_tt(@Path,~[token_tree]), // new macro-invocation } pub type lit = spanned<lit_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum lit_ { lit_str(@str), lit_int(i64, int_ty), @@ -644,13 +602,13 @@ pub enum lit_ { // NB: If you change this, you'll probably want to change the corresponding // type structure in middle/ty.rs as well. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct mt { ty: @Ty, mutbl: mutability, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct ty_field_ { ident: ident, mt: mt, @@ -658,7 +616,7 @@ pub struct ty_field_ { pub type ty_field = spanned<ty_field_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct ty_method { ident: ident, attrs: ~[attribute], @@ -670,7 +628,7 @@ pub struct ty_method { span: span, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] // A trait method is either required (meaning it doesn't have an // implementation, just a signature) or provided (meaning it has a default // implementation). @@ -679,7 +637,7 @@ pub enum trait_method { provided(@method), } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, } impl ToStr for int_ty { @@ -688,13 +646,7 @@ impl ToStr for int_ty { } } -impl to_bytes::IterBytes for int_ty { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum uint_ty { ty_u, ty_u8, ty_u16, ty_u32, ty_u64, } impl ToStr for uint_ty { @@ -703,13 +655,7 @@ impl ToStr for uint_ty { } } -impl to_bytes::IterBytes for uint_ty { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum float_ty { ty_f, ty_f32, ty_f64, } impl ToStr for float_ty { @@ -718,14 +664,8 @@ impl ToStr for float_ty { } } -impl to_bytes::IterBytes for float_ty { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - // NB Eq method appears below. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct Ty { id: node_id, node: ty_, @@ -733,7 +673,7 @@ pub struct Ty { } // Not represented directly in the AST, referred to by name through a ty_path. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum prim_ty { ty_int(int_ty), ty_uint(uint_ty), @@ -742,12 +682,13 @@ pub enum prim_ty { ty_bool, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum Onceness { Once, Many } +#[deriving(IterBytes)] impl ToStr for Onceness { fn to_str(&self) -> ~str { match *self { @@ -757,13 +698,7 @@ impl ToStr for Onceness { } } -impl to_bytes::IterBytes for Onceness { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as uint).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct TyClosure { sigil: Sigil, region: Option<@Lifetime>, @@ -778,7 +713,7 @@ pub struct TyClosure { bounds: Option<OptVec<TyParamBound>>, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct TyBareFn { purity: purity, abis: AbiSet, @@ -786,7 +721,7 @@ pub struct TyBareFn { decl: fn_decl } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum ty_ { ty_nil, ty_bot, /* bottom type */ @@ -807,19 +742,13 @@ pub enum ty_ { ty_infer, } -impl to_bytes::IterBytes for Ty { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.span.lo.iter_bytes(lsb0, f) && self.span.hi.iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum asm_dialect { asm_att, asm_intel } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct inline_asm { asm: @str, clobbers: @str, @@ -830,7 +759,7 @@ pub struct inline_asm { dialect: asm_dialect } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct arg { is_mutbl: bool, ty: @Ty, @@ -838,20 +767,21 @@ pub struct arg { id: node_id, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct fn_decl { inputs: ~[arg], output: @Ty, cf: ret_style, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum purity { unsafe_fn, // declared with "unsafe fn" impure_fn, // declared with "fn" extern_fn, // declared with "extern fn" } +#[deriving(IterBytes)] impl ToStr for purity { fn to_str(&self) -> ~str { match *self { @@ -862,26 +792,14 @@ impl ToStr for purity { } } -impl to_bytes::IterBytes for purity { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum ret_style { noreturn, // functions with return type _|_ that always // raise an error or exit (i.e. never return to the caller) return_val, // everything else } -impl to_bytes::IterBytes for ret_style { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum explicit_self_ { sty_static, // no self sty_value, // `self` @@ -890,27 +808,9 @@ pub enum explicit_self_ { sty_uniq(mutability) // `~self` } -impl to_bytes::IterBytes for explicit_self_ { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - sty_static => 0u8.iter_bytes(lsb0, f), - sty_value => 1u8.iter_bytes(lsb0, f), - sty_region(ref lft, ref mutbl) => { - 2u8.iter_bytes(lsb0, f) && lft.iter_bytes(lsb0, f) && mutbl.iter_bytes(lsb0, f) - } - sty_box(ref mutbl) => { - 3u8.iter_bytes(lsb0, f) && mutbl.iter_bytes(lsb0, f) - } - sty_uniq(ref mutbl) => { - 4u8.iter_bytes(lsb0, f) && mutbl.iter_bytes(lsb0, f) - } - } - } -} - pub type explicit_self = spanned<explicit_self_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct method { ident: ident, attrs: ~[attribute], @@ -925,17 +825,17 @@ pub struct method { vis: visibility, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct _mod { view_items: ~[@view_item], items: ~[@item], } // Foreign mods can be named or anonymous -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum foreign_mod_sort { named, anonymous } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct foreign_mod { sort: foreign_mod_sort, abis: AbiSet, @@ -943,24 +843,24 @@ pub struct foreign_mod { items: ~[@foreign_item], } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct variant_arg { ty: @Ty, id: node_id, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum variant_kind { tuple_variant_kind(~[variant_arg]), struct_variant_kind(@struct_def), } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct enum_def { variants: ~[variant], } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct variant_ { name: ident, attrs: ~[attribute], @@ -972,7 +872,7 @@ pub struct variant_ { pub type variant = spanned<variant_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct path_list_ident_ { name: ident, id: node_id, @@ -982,7 +882,7 @@ pub type path_list_ident = spanned<path_list_ident_>; pub type view_path = spanned<view_path_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum view_path_ { // quux = foo::bar::baz @@ -999,7 +899,7 @@ pub enum view_path_ { view_path_list(@Path, ~[path_list_ident], node_id) } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct view_item { node: view_item_, attrs: ~[attribute], @@ -1007,7 +907,7 @@ pub struct view_item { span: span, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum view_item_ { view_item_extern_mod(ident, ~[@meta_item], node_id), view_item_use(~[@view_path]), @@ -1019,11 +919,11 @@ pub type attribute = spanned<attribute_>; // Distinguishes between attributes that decorate items and attributes that // are contained as statements within items. These two cases need to be // distinguished for pretty-printing. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum attr_style { attr_outer, attr_inner, } // doc-comments are promoted to attributes that have is_sugared_doc = true -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct attribute_ { style: attr_style, value: @meta_item, @@ -1037,17 +937,17 @@ pub struct attribute_ { If this impl is an item_impl, the impl_id is redundant (it could be the same as the impl's node id). */ -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct trait_ref { path: @Path, ref_id: node_id, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum visibility { public, private, inherited } impl visibility { - fn inherit_from(&self, parent_visibility: visibility) -> visibility { + pub fn inherit_from(&self, parent_visibility: visibility) -> visibility { match self { &inherited => parent_visibility, &public | &private => *self @@ -1055,7 +955,7 @@ impl visibility { } } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct struct_field_ { kind: struct_field_kind, id: node_id, @@ -1065,13 +965,13 @@ pub struct struct_field_ { pub type struct_field = spanned<struct_field_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum struct_field_kind { named_field(ident, visibility), unnamed_field // element of a tuple-like struct } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct struct_def { fields: ~[@struct_field], /* fields, not including ctor */ /* ID of the constructor. This is only used for tuple- or enum-like @@ -1083,7 +983,7 @@ pub struct struct_def { FIXME (#3300): Should allow items to be anonymous. Right now we just use dummy names for anon items. */ -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct item { ident: ident, attrs: ~[attribute], @@ -1093,7 +993,7 @@ pub struct item { span: span, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum item_ { item_static(@Ty, mutability, @expr), item_fn(fn_decl, purity, AbiSet, Generics, blk), @@ -1111,7 +1011,7 @@ pub enum item_ { item_mac(mac), } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct foreign_item { ident: ident, attrs: ~[attribute], @@ -1121,7 +1021,7 @@ pub struct foreign_item { vis: visibility, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum foreign_item_ { foreign_item_fn(fn_decl, purity, Generics), foreign_item_static(@Ty, /* is_mutbl */ bool), @@ -1130,7 +1030,7 @@ pub enum foreign_item_ { // The data we save and restore about an inlined item or method. This is not // part of the AST that we parse from a file, but it becomes part of the tree // that we trans. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum inlined_item { ii_item(@item), ii_method(def_id /* impl id */, @method), diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 9ba7cb3c818..9439f45be21 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -19,7 +19,6 @@ use visit; use std::hashmap::HashMap; use std::int; use std::option; -use std::to_bytes; use std::cast; use std::local_data; @@ -59,7 +58,7 @@ pub fn def_id_of_def(d: def) -> def_id { def_fn(id, _) | def_static_method(id, _, _) | def_mod(id) | def_foreign_mod(id) | def_static(id, _) | def_variant(_, id) | def_ty(id) | def_ty_param(id, _) | - def_use(id) | def_struct(id) | def_trait(id) => { + def_use(id) | def_struct(id) | def_trait(id) | def_method(id, _) => { id } def_arg(id, _) | def_local(id, _) | def_self(id, _) | def_self_ty(id) @@ -194,14 +193,6 @@ pub fn is_call_expr(e: @expr) -> bool { match e.node { expr_call(*) => true, _ => false } } -// This makes def_id hashable -impl to_bytes::IterBytes for def_id { - #[inline] - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.crate.iter_bytes(lsb0, f) && self.node.iter_bytes(lsb0, f) - } -} - pub fn block_from_expr(e: @expr) -> blk { let blk_ = default_block(~[], option::Some::<@expr>(e), e.id); return spanned {node: blk_, span: e.span}; @@ -544,18 +535,18 @@ pub fn walk_pat(pat: @pat, it: &fn(@pat) -> bool) -> bool { match pat.node { pat_ident(_, _, Some(p)) => walk_pat(p, it), pat_struct(_, ref fields, _) => { - fields.iter().advance(|f| walk_pat(f.pat, it)) + fields.iter().advance(|f| walk_pat(f.pat, |p| it(p))) } pat_enum(_, Some(ref s)) | pat_tup(ref s) => { - s.iter().advance(|&p| walk_pat(p, it)) + s.iter().advance(|&p| walk_pat(p, |p| it(p))) } pat_box(s) | pat_uniq(s) | pat_region(s) => { walk_pat(s, it) } pat_vec(ref before, ref slice, ref after) => { - before.iter().advance(|&p| walk_pat(p, it)) && - slice.iter().advance(|&p| walk_pat(p, it)) && - after.iter().advance(|&p| walk_pat(p, it)) + before.iter().advance(|&p| walk_pat(p, |p| it(p))) && + slice.iter().advance(|&p| walk_pat(p, |p| it(p))) && + after.iter().advance(|&p| walk_pat(p, |p| it(p))) } pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, _, _) | pat_enum(_, _) => { @@ -619,6 +610,15 @@ pub enum Privacy { Public } +/// Returns true if the given pattern consists solely of an identifier +/// and false otherwise. +pub fn pat_is_ident(pat: @ast::pat) -> bool { + match pat.node { + ast::pat_ident(*) => true, + _ => false, + } +} + // HYGIENE FUNCTIONS /// Construct an identifier with the given name and an empty context: @@ -695,7 +695,7 @@ pub fn new_sctable_internal() -> SCTable { pub fn get_sctable() -> @mut SCTable { unsafe { let sctable_key = (cast::transmute::<(uint, uint), - &fn(v: @@mut SCTable)>( + &fn:Copy(v: @@mut SCTable)>( (-4 as uint, 0u))); match local_data::local_data_get(sctable_key) { None => { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 5efc96e16b5..bcf617c56ae 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -22,7 +22,6 @@ source code snippets, etc. */ use std::cmp; -use std::to_bytes; use std::uint; use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -32,12 +31,12 @@ pub trait Pos { } /// A byte offset -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct BytePos(uint); /// A character offset. Because of multibyte utf8 characters, a byte offset /// is not equivalent to a character offset. The CodeMap will convert BytePos /// values to CharPos values as necessary. -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct CharPos(uint); // XXX: Lots of boilerplate in these impls, but so far my attempts to fix @@ -67,12 +66,6 @@ impl Sub<BytePos, BytePos> for BytePos { } } -impl to_bytes::IterBytes for BytePos { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (**self).iter_bytes(lsb0, f) - } -} - impl Pos for CharPos { fn from_uint(n: uint) -> CharPos { CharPos(n) } fn to_uint(&self) -> uint { **self } @@ -85,12 +78,6 @@ impl cmp::Ord for CharPos { fn gt(&self, other: &CharPos) -> bool { **self > **other } } -impl to_bytes::IterBytes for CharPos { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (**self).iter_bytes(lsb0, f) - } -} - impl Add<CharPos,CharPos> for CharPos { fn add(&self, rhs: &CharPos) -> CharPos { CharPos(**self + **rhs) @@ -109,13 +96,14 @@ are *absolute* positions from the beginning of the codemap, not positions relative to FileMaps. Methods on the CodeMap can be used to relate spans back to the original source. */ +#[deriving(IterBytes)] pub struct span { lo: BytePos, hi: BytePos, expn_info: Option<@ExpnInfo> } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct spanned<T> { node: T, span: span } impl cmp::Eq for span { @@ -138,14 +126,6 @@ impl<D:Decoder> Decodable<D> for span { } } -impl to_bytes::IterBytes for span { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.lo.iter_bytes(lsb0, f) && - self.hi.iter_bytes(lsb0, f) && - self.expn_info.iter_bytes(lsb0, f) - } -} - pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> spanned<T> { respan(mk_sp(lo, hi), t) } @@ -191,40 +171,21 @@ pub struct LocWithOpt { // used to be structural records. Better names, anyone? pub struct FileMapAndLine {fm: @FileMap, line: uint} pub struct FileMapAndBytePos {fm: @FileMap, pos: BytePos} +#[deriving(IterBytes)] pub struct NameAndSpan {name: @str, span: Option<span>} -impl to_bytes::IterBytes for NameAndSpan { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.name.iter_bytes(lsb0, f) && self.span.iter_bytes(lsb0, f) - } -} - +#[deriving(IterBytes)] pub struct CallInfo { call_site: span, callee: NameAndSpan } -impl to_bytes::IterBytes for CallInfo { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.call_site.iter_bytes(lsb0, f) && self.callee.iter_bytes(lsb0, f) - } -} - /// Extra information for tracking macro expansion of spans +#[deriving(IterBytes)] pub enum ExpnInfo { ExpandedFrom(CallInfo) } -impl to_bytes::IterBytes for ExpnInfo { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - ExpandedFrom(ref call_info) => { - 0u8.iter_bytes(lsb0, f) && call_info.iter_bytes(lsb0, f) - } - } - } -} - pub type FileName = @str; pub struct FileLines diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 89867922b25..ab7d3fda501 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -13,7 +13,6 @@ use codemap; use std::io; use std::uint; -use std::vec; use extra::term; pub type Emitter = @fn(cmsp: Option<(@codemap::CodeMap, span)>, @@ -250,7 +249,7 @@ fn highlight_lines(cm: @codemap::CodeMap, let mut elided = false; let mut display_lines = /* FIXME (#2543) */ copy lines.lines; if display_lines.len() > max_lines { - display_lines = vec::slice(display_lines, 0u, max_lines).to_owned(); + display_lines = display_lines.slice(0u, max_lines).to_owned(); elided = true; } // Print the offending lines @@ -264,8 +263,11 @@ fn highlight_lines(cm: @codemap::CodeMap, let s = fmt!("%s:%u ", fm.name, last_line + 1u); let mut indent = s.len(); let mut out = ~""; - while indent > 0u { out += " "; indent -= 1u; } - out += "...\n"; + while indent > 0u { + out.push_char(' '); + indent -= 1u; + } + out.push_str("...\n"); io::stderr().write_str(out); } @@ -286,23 +288,29 @@ fn highlight_lines(cm: @codemap::CodeMap, // part of the 'filename:line ' part of the previous line. let skip = fm.name.len() + digits + 3u; for skip.times() { - s += " "; + s.push_char(' '); } let orig = fm.get_line(lines.lines[0] as int); for uint::range(0u,left-skip) |pos| { let curChar = (orig[pos] as char); - s += match curChar { // Whenever a tab occurs on the previous - '\t' => "\t", // line, we insert one on the error-point- - _ => " " // -squiggly-line as well (instead of a - }; // space). This way the squiggly-line will - } // usually appear in the correct position. + // Whenever a tab occurs on the previous line, we insert one on + // the error-point-squiggly-line as well (instead of a space). + // That way the squiggly line will usually appear in the correct + // position. + match curChar { + '\t' => s.push_char('\t'), + _ => s.push_char(' '), + }; + } io::stderr().write_str(s); let mut s = ~"^"; let hi = cm.lookup_char_pos(sp.hi); if hi.col != lo.col { // the ^ already takes up one space let num_squigglies = hi.col.to_uint()-lo.col.to_uint()-1u; - for num_squigglies.times() { s += "~"; } + for num_squigglies.times() { + s.push_char('~') + } } print_maybe_colored(s + "\n", diagnosticcolor(lvl)); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 282a28ff9e0..78fdb99753d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -509,7 +509,7 @@ impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{ } }, ConsMapChain (~ref mut map, rest) => { - if satisfies_pred(map,&n,pred) { + if satisfies_pred(map,&n,|v|pred(v)) { map.insert(key,ext); } else { rest.insert_into_frame(key,ext,n,pred) diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 80ab54b7e2c..7df8874076e 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -26,8 +26,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) } } else { match *e { - ast::tt_tok(_, token::IDENT(ident,_)) => - res_str += cx.str_of(ident), + ast::tt_tok(_, token::IDENT(ident,_)) => res_str.push_str(cx.str_of(ident)), _ => cx.span_fatal(sp, "concat_idents! requires ident args.") } } diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs index 8403234f892..15fb6ee9ff7 100644 --- a/src/libsyntax/ext/deriving/iter_bytes.rs +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -43,15 +43,21 @@ pub fn expand_deriving_iter_bytes(cx: @ExtCtxt, } fn iter_bytes_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { - let lsb0_f = match substr.nonself_args { - [l, f] => ~[l, f], + let (lsb0, f)= match substr.nonself_args { + [l, f] => (l, f), _ => cx.span_bug(span, "Incorrect number of arguments in `deriving(IterBytes)`") }; + // Build the "explicitly borrowed" stack closure, "|_buf| f(_buf)". + let blk_arg = cx.ident_of("_buf"); + let borrowed_f = + cx.lambda_expr_1(span, cx.expr_call(span, f, ~[cx.expr_ident(span, blk_arg)]), + blk_arg); + let iter_bytes_ident = substr.method_ident; let call_iterbytes = |thing_expr| { cx.expr_method_call(span, thing_expr, iter_bytes_ident, - copy lsb0_f) + ~[lsb0, borrowed_f]) }; let mut exprs = ~[]; let fields; diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index dfbc028ddf6..19aa29a62a9 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -99,7 +99,7 @@ fn rand_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { (ident, ref summary) => { cx.arm(span, ~[ pat ], - rand_thing(cx, span, ident, summary, rand_call)) + rand_thing(cx, span, ident, summary, || rand_call())) } } }; diff --git a/src/libsyntax/ext/deriving/to_str.rs b/src/libsyntax/ext/deriving/to_str.rs index d1d4d173a3f..c9d63d2c416 100644 --- a/src/libsyntax/ext/deriving/to_str.rs +++ b/src/libsyntax/ext/deriving/to_str.rs @@ -30,7 +30,7 @@ pub fn expand_deriving_to_str(cx: @ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: ~[], - ret_ty: Ptr(~Literal(Path::new_local("str")), Owned), + ret_ty: Ptr(~Literal(Path::new_local("str")), Send), const_nonmatching: false, combine_substructure: to_str_substructure } diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index 2f21eba11d7..a2f9aa58d99 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -22,7 +22,7 @@ use opt_vec; /// The types of pointers pub enum PtrTy<'self> { - Owned, // ~ + Send, // ~ Managed(ast::mutability), // @[mut] Borrowed(Option<&'self str>, ast::mutability), // &['lifetime] [mut] } @@ -128,7 +128,7 @@ impl<'self> Ty<'self> { Ptr(ref ty, ref ptr) => { let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); match *ptr { - Owned => { + Send => { cx.ty_uniq(span, raw_ty) } Managed(mutbl) => { @@ -248,7 +248,7 @@ pub fn get_explicit_self(cx: @ExtCtxt, span: span, self_ptr: &Option<PtrTy>) let self_ty = respan( span, match *ptr { - Owned => ast::sty_uniq(ast::m_imm), + Send => ast::sty_uniq(ast::m_imm), Managed(mutbl) => ast::sty_box(mutbl), Borrowed(ref lt, mutbl) => { let lt = lt.map(|s| @cx.lifetime(span, diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index 2c5ec0909d9..3044cd50b34 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -65,8 +65,8 @@ impl gen_send for message { args_ast); let mut body = ~"{\n"; - body += fmt!("use super::%s;\n", name); - body += "let mut pipe = pipe;\n"; + body.push_str(fmt!("use super::%s;\n", name)); + body.push_str("let mut pipe = pipe;\n"); if this.proto.is_bounded() { let (sp, rp) = match (this.dir, next.dir) { @@ -76,13 +76,15 @@ impl gen_send for message { (recv, recv) => (~"c", ~"s") }; - body += "let mut b = pipe.reuse_buffer();\n"; - body += fmt!("let %s = ::std::pipes::SendPacketBuffered(\ - &mut (b.buffer.data.%s));\n", - sp, next.name); - body += fmt!("let %s = ::std::pipes::RecvPacketBuffered(\ - &mut (b.buffer.data.%s));\n", - rp, next.name); + body.push_str("let mut b = pipe.reuse_buffer();\n"); + body.push_str(fmt!("let %s = ::std::pipes::SendPacketBuffered(\ + &mut (b.buffer.data.%s));\n", + sp, + next.name)); + body.push_str(fmt!("let %s = ::std::pipes::RecvPacketBuffered(\ + &mut (b.buffer.data.%s));\n", + rp, + next.name)); } else { let pat = match (this.dir, next.dir) { @@ -92,23 +94,22 @@ impl gen_send for message { (recv, recv) => "(s, c)" }; - body += fmt!("let %s = ::std::pipes::entangle();\n", pat); + body.push_str(fmt!("let %s = ::std::pipes::entangle();\n", pat)); } - body += fmt!("let message = %s(%s);\n", - name, - vec::append_one( - arg_names.map(|x| cx.str_of(*x)), - @"s").connect(", ")); + body.push_str(fmt!("let message = %s(%s);\n", + name, + vec::append_one(arg_names.map(|x| cx.str_of(*x)), @"s") + .connect(", "))); if !try { - body += fmt!("::std::pipes::send(pipe, message);\n"); + body.push_str(fmt!("::std::pipes::send(pipe, message);\n")); // return the new channel - body += "c }"; + body.push_str("c }"); } else { - body += fmt!("if ::std::pipes::send(pipe, message) {\n \ + body.push_str(fmt!("if ::std::pipes::send(pipe, message) {\n \ ::std::pipes::rt::make_some(c) \ - } else { ::std::pipes::rt::make_none() } }"); + } else { ::std::pipes::rt::make_none() } }")); } let body = cx.parse_expr(body.to_managed()); @@ -155,19 +156,19 @@ impl gen_send for message { }; let mut body = ~"{ "; - body += fmt!("use super::%s;\n", name); - body += fmt!("let message = %s%s;\n", name, message_args); + body.push_str(fmt!("use super::%s;\n", name)); + body.push_str(fmt!("let message = %s%s;\n", name, message_args)); if !try { - body += fmt!("::std::pipes::send(pipe, message);\n"); - body += " }"; + body.push_str(fmt!("::std::pipes::send(pipe, message);\n")); + body.push_str(" }"); } else { - body += fmt!("if ::std::pipes::send(pipe, message) \ + body.push_str(fmt!("if ::std::pipes::send(pipe, message) \ { \ ::std::pipes::rt::make_some(()) \ } else { \ ::std::pipes::rt::make_none() \ - } }"); + } }")); } let body = cx.parse_expr(body.to_managed()); @@ -433,10 +434,10 @@ impl gen_init for protocol { let mut server_states = ~[]; for (copy self.states).iter().advance |s| { - items += s.to_type_decls(cx); + items.push_all_move(s.to_type_decls(cx)); - client_states += s.to_endpoint_decls(cx, send); - server_states += s.to_endpoint_decls(cx, recv); + client_states.push_all_move(s.to_endpoint_decls(cx, send)); + server_states.push_all_move(s.to_endpoint_decls(cx, recv)); } if self.is_bounded() { diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index fe050fc99f1..bf8c5ae462b 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -18,7 +18,7 @@ use std::vec::VecIterator; -#[deriving(Encodable, Decodable)] +#[deriving(Encodable, Decodable,IterBytes)] pub enum OptVec<T> { Empty, Vec(~[T]) diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index ddcad5c3e8f..d33b72ae3c9 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -42,7 +42,7 @@ impl parser_attr for Parser { if self.look_ahead(1u) != token::LBRACKET { break; } - attrs += [self.parse_attribute(ast::attr_outer)]; + attrs.push(self.parse_attribute(ast::attr_outer)); } token::DOC_COMMENT(s) => { let attr = ::attr::mk_sugared_doc_attr( @@ -53,7 +53,7 @@ impl parser_attr for Parser { if attr.node.style != ast::attr_outer { self.fatal("expected outer comment"); } - attrs += [attr]; + attrs.push(attr); self.bump(); } _ => break @@ -77,9 +77,7 @@ impl parser_attr for Parser { self.expect(&token::RBRACKET); let hi = self.span.hi; return spanned(lo, hi, ast::attribute_ { style: style, - value: meta_item, - is_sugared_doc: false }); - } + value: meta_item, is_sugared_doc: false }); } // Parse attributes that appear after the opening of an item, each // terminated by a semicolon. In addition to a vector of inner attributes, @@ -105,7 +103,7 @@ impl parser_attr for Parser { let attr = self.parse_attribute(ast::attr_inner); if *self.token == token::SEMI { self.bump(); - inner_attrs += [attr]; + inner_attrs.push(attr); } else { // It's not really an inner attribute let outer_attr = @@ -113,7 +111,7 @@ impl parser_attr for Parser { ast::attribute_ { style: ast::attr_outer, value: attr.node.value, is_sugared_doc: false }); - next_outer_attrs += [outer_attr]; + next_outer_attrs.push(outer_attr); break; } } @@ -125,9 +123,9 @@ impl parser_attr for Parser { ); self.bump(); if attr.node.style == ast::attr_inner { - inner_attrs += [attr]; + inner_attrs.push(attr); } else { - next_outer_attrs += [attr]; + next_outer_attrs.push(attr); break; } } diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs index 2baf08b68f1..01af33b13b8 100644 --- a/src/libsyntax/parse/comments.rs +++ b/src/libsyntax/parse/comments.rs @@ -254,7 +254,7 @@ fn read_block_comment(rdr: @mut StringReader, bump(rdr); } if !is_eof(rdr) { - curr_line += "*/"; + curr_line.push_str("*/"); bump(rdr); bump(rdr); } @@ -278,13 +278,13 @@ fn read_block_comment(rdr: @mut StringReader, if rdr.curr == '/' && nextch(rdr) == '*' { bump(rdr); bump(rdr); - curr_line += "*"; + curr_line.push_char('*'); level += 1; } else { if rdr.curr == '*' && nextch(rdr) == '/' { bump(rdr); bump(rdr); - curr_line += "/"; + curr_line.push_char('/'); level -= 1; } else { bump(rdr); } } diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index cde4c754d56..04f62f35749 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -51,251 +51,3 @@ pub fn token_to_str(token: &token::Token) -> ~str { token::to_str(get_ident_interner(), token) } -impl Parser { - // convert a token to a string using self's reader - pub fn token_to_str(&self, token: &token::Token) -> ~str { - token::to_str(get_ident_interner(), token) - } - - // convert the current token to a string using self's reader - pub fn this_token_to_str(&self) -> ~str { - self.token_to_str(self.token) - } - - pub fn unexpected_last(&self, t: &token::Token) -> ! { - self.span_fatal( - *self.last_span, - fmt!( - "unexpected token: `%s`", - self.token_to_str(t) - ) - ); - } - - pub fn unexpected(&self) -> ! { - self.fatal( - fmt!( - "unexpected token: `%s`", - self.this_token_to_str() - ) - ); - } - - // expect and consume the token t. Signal an error if - // the next token is not t. - pub fn expect(&self, t: &token::Token) { - if *self.token == *t { - self.bump(); - } else { - self.fatal( - fmt!( - "expected `%s` but found `%s`", - self.token_to_str(t), - self.this_token_to_str() - ) - ) - } - } - - pub fn parse_ident(&self) -> ast::ident { - self.check_strict_keywords(); - self.check_reserved_keywords(); - match *self.token { - token::IDENT(i, _) => { - self.bump(); - i - } - token::INTERPOLATED(token::nt_ident(*)) => { - self.bug("ident interpolation not converted to real token"); - } - _ => { - self.fatal( - fmt!( - "expected ident, found `%s`", - self.this_token_to_str() - ) - ); - } - } - } - - pub fn parse_path_list_ident(&self) -> ast::path_list_ident { - let lo = self.span.lo; - let ident = self.parse_ident(); - let hi = self.last_span.hi; - spanned(lo, hi, ast::path_list_ident_ { name: ident, - id: self.get_id() }) - } - - // consume token 'tok' if it exists. Returns true if the given - // token was present, false otherwise. - pub fn eat(&self, tok: &token::Token) -> bool { - return if *self.token == *tok { self.bump(); true } else { false }; - } - - pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { - token::is_keyword(kw, self.token) - } - - // if the next token is the given keyword, eat it and return - // true. Otherwise, return false. - pub fn eat_keyword(&self, kw: keywords::Keyword) -> bool { - let is_kw = match *self.token { - token::IDENT(sid, false) => kw.to_ident().name == sid.name, - _ => false - }; - if is_kw { self.bump() } - is_kw - } - - // if the given word is not a keyword, signal an error. - // if the next token is not the given word, signal an error. - // otherwise, eat it. - pub fn expect_keyword(&self, kw: keywords::Keyword) { - if !self.eat_keyword(kw) { - self.fatal( - fmt!( - "expected `%s`, found `%s`", - self.id_to_str(kw.to_ident()), - self.this_token_to_str() - ) - ); - } - } - - // signal an error if the given string is a strict keyword - pub fn check_strict_keywords(&self) { - if token::is_strict_keyword(self.token) { - self.span_err(*self.last_span, - fmt!("found `%s` in ident position", self.this_token_to_str())); - } - } - - // signal an error if the current token is a reserved keyword - pub fn check_reserved_keywords(&self) { - if token::is_reserved_keyword(self.token) { - self.fatal(fmt!("`%s` is a reserved keyword", self.this_token_to_str())); - } - } - - // expect and consume a GT. if a >> is seen, replace it - // with a single > and continue. If a GT is not seen, - // signal an error. - pub fn expect_gt(&self) { - if *self.token == token::GT { - self.bump(); - } else if *self.token == token::BINOP(token::SHR) { - self.replace_token( - token::GT, - self.span.lo + BytePos(1u), - self.span.hi - ); - } else { - let mut s: ~str = ~"expected `"; - s += self.token_to_str(&token::GT); - s += "`, found `"; - s += self.this_token_to_str(); - s += "`"; - self.fatal(s); - } - } - - // parse a sequence bracketed by '<' and '>', stopping - // before the '>'. - pub fn parse_seq_to_before_gt<T: Copy>(&self, - sep: Option<token::Token>, - f: &fn(&Parser) -> T) - -> OptVec<T> { - let mut first = true; - let mut v = opt_vec::Empty; - while *self.token != token::GT - && *self.token != token::BINOP(token::SHR) { - match sep { - Some(ref t) => { - if first { first = false; } - else { self.expect(t); } - } - _ => () - } - v.push(f(self)); - } - return v; - } - - pub fn parse_seq_to_gt<T: Copy>(&self, - sep: Option<token::Token>, - f: &fn(&Parser) -> T) - -> OptVec<T> { - let v = self.parse_seq_to_before_gt(sep, f); - self.expect_gt(); - return v; - } - - // parse a sequence, including the closing delimiter. The function - // f must consume tokens until reaching the next separator or - // closing bracket. - pub fn parse_seq_to_end<T: Copy>(&self, - ket: &token::Token, - sep: SeqSep, - f: &fn(&Parser) -> T) - -> ~[T] { - let val = self.parse_seq_to_before_end(ket, sep, f); - self.bump(); - val - } - - // parse a sequence, not including the closing delimiter. The function - // f must consume tokens until reaching the next separator or - // closing bracket. - pub fn parse_seq_to_before_end<T: Copy>(&self, - ket: &token::Token, - sep: SeqSep, - f: &fn(&Parser) -> T) - -> ~[T] { - let mut first: bool = true; - let mut v: ~[T] = ~[]; - while *self.token != *ket { - match sep.sep { - Some(ref t) => { - if first { first = false; } - else { self.expect(t); } - } - _ => () - } - if sep.trailing_sep_allowed && *self.token == *ket { break; } - v.push(f(self)); - } - return v; - } - - // parse a sequence, including the closing delimiter. The function - // f must consume tokens until reaching the next separator or - // closing bracket. - pub fn parse_unspanned_seq<T: Copy>(&self, - bra: &token::Token, - ket: &token::Token, - sep: SeqSep, - f: &fn(&Parser) -> T) - -> ~[T] { - self.expect(bra); - let result = self.parse_seq_to_before_end(ket, sep, f); - self.bump(); - result - } - - // NB: Do not use this function unless you actually plan to place the - // spanned list in the AST. - pub fn parse_seq<T: Copy>(&self, - bra: &token::Token, - ket: &token::Token, - sep: SeqSep, - f: &fn(&Parser) -> T) - -> spanned<~[T]> { - let lo = self.span.lo; - self.expect(bra); - let result = self.parse_seq_to_before_end(ket, sep, f); - let hi = self.span.hi; - self.bump(); - spanned(lo, hi, result) - } -} diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 2092f0fa5fa..4a872832952 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -180,7 +180,7 @@ pub fn bump(rdr: &mut StringReader) { let byte_offset_diff = next.next - current_byte_offset; rdr.pos = rdr.pos + BytePos(byte_offset_diff); rdr.curr = next.ch; - rdr.col += CharPos(1u); + rdr.col = rdr.col + CharPos(1u); if last_char == '\n' { rdr.filemap.next_line(rdr.last_pos); rdr.col = CharPos(0u); @@ -448,8 +448,8 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token { is_float = true; bump(rdr); let dec_part = scan_digits(rdr, 10u); - num_str += "."; - num_str += dec_part; + num_str.push_char('.'); + num_str.push_str(dec_part); } if is_float { match base { @@ -461,7 +461,7 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token { match scan_exponent(rdr) { Some(ref s) => { is_float = true; - num_str += (*s); + num_str.push_str(*s); } None => () } diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 32508f3b477..fff4c125af6 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -62,6 +62,8 @@ pub enum ObsoleteSyntax { ObsoleteFixedLengthVectorType, ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl, + ObsoleteMutWithMultipleBindings, + ObsoletePatternCopyKeyword, } impl to_bytes::IterBytes for ObsoleteSyntax { @@ -71,7 +73,26 @@ impl to_bytes::IterBytes for ObsoleteSyntax { } } -impl Parser { +pub trait ParserObsoleteMethods { + /// Reports an obsolete syntax non-fatal error. + fn obsolete(&self, sp: span, kind: ObsoleteSyntax); + // Reports an obsolete syntax non-fatal error, and returns + // a placeholder expression + fn obsolete_expr(&self, sp: span, kind: ObsoleteSyntax) -> @expr; + fn report(&self, + sp: span, + kind: ObsoleteSyntax, + kind_str: &str, + desc: &str); + fn token_is_obsolete_ident(&self, ident: &str, token: &Token) -> bool; + fn is_obsolete_ident(&self, ident: &str) -> bool; + fn eat_obsolete_ident(&self, ident: &str) -> bool; + fn try_parse_obsolete_struct_ctor(&self) -> bool; + fn try_parse_obsolete_with(&self) -> bool; + fn try_parse_obsolete_priv_section(&self, attrs: &[attribute]) -> bool; +} + +impl ParserObsoleteMethods for Parser { /// Reports an obsolete syntax non-fatal error. pub fn obsolete(&self, sp: span, kind: ObsoleteSyntax) { let (kind_str, desc) = match kind { @@ -223,6 +244,15 @@ impl Parser { "instead of e.g. `let a = 1, b = 2`, write \ `let (a, b) = (1, 2)`." ), + ObsoleteMutWithMultipleBindings => ( + "`mut` with multiple bindings", + "use multiple local declarations instead of e.g. `let mut \ + (x, y) = ...`." + ), + ObsoletePatternCopyKeyword => ( + "`copy` in patterns", + "`copy` in patterns no longer has any effect" + ), }; self.report(sp, kind, kind_str, desc); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d67771fc435..f1b5c4d16be 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -64,7 +64,7 @@ use codemap::{span, BytePos, spanned, mk_sp}; use codemap; use parse::attr::parser_attr; use parse::classify; -use parse::common::{seq_sep_none}; +use parse::common::{SeqSep, seq_sep_none}; use parse::common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed}; use parse::lexer::reader; use parse::lexer::TokenAndSpan; @@ -83,8 +83,12 @@ use parse::obsolete::{ObsoleteLifetimeNotation, ObsoleteConstManagedPointer}; use parse::obsolete::{ObsoletePurity, ObsoleteStaticMethod}; use parse::obsolete::{ObsoleteConstItem, ObsoleteFixedLengthVectorType}; use parse::obsolete::{ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl}; -use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident, is_ident_or_path}; -use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents, token_to_binop}; +use parse::obsolete::{ObsoleteMutWithMultipleBindings}; +use parse::obsolete::{ObsoletePatternCopyKeyword, ParserObsoleteMethods}; +use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident}; +use parse::token::{is_ident_or_path}; +use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents}; +use parse::token::{token_to_binop}; use parse::token; use parse::{new_sub_parser_from_file, next_node_id, ParseSess}; use opt_vec; @@ -270,6 +274,253 @@ impl Drop for Parser { } impl Parser { + // convert a token to a string using self's reader + pub fn token_to_str(&self, token: &token::Token) -> ~str { + token::to_str(get_ident_interner(), token) + } + + // convert the current token to a string using self's reader + pub fn this_token_to_str(&self) -> ~str { + self.token_to_str(self.token) + } + + pub fn unexpected_last(&self, t: &token::Token) -> ! { + self.span_fatal( + *self.last_span, + fmt!( + "unexpected token: `%s`", + self.token_to_str(t) + ) + ); + } + + pub fn unexpected(&self) -> ! { + self.fatal( + fmt!( + "unexpected token: `%s`", + self.this_token_to_str() + ) + ); + } + + // expect and consume the token t. Signal an error if + // the next token is not t. + pub fn expect(&self, t: &token::Token) { + if *self.token == *t { + self.bump(); + } else { + self.fatal( + fmt!( + "expected `%s` but found `%s`", + self.token_to_str(t), + self.this_token_to_str() + ) + ) + } + } + + pub fn parse_ident(&self) -> ast::ident { + self.check_strict_keywords(); + self.check_reserved_keywords(); + match *self.token { + token::IDENT(i, _) => { + self.bump(); + i + } + token::INTERPOLATED(token::nt_ident(*)) => { + self.bug("ident interpolation not converted to real token"); + } + _ => { + self.fatal( + fmt!( + "expected ident, found `%s`", + self.this_token_to_str() + ) + ); + } + } + } + + pub fn parse_path_list_ident(&self) -> ast::path_list_ident { + let lo = self.span.lo; + let ident = self.parse_ident(); + let hi = self.last_span.hi; + spanned(lo, hi, ast::path_list_ident_ { name: ident, + id: self.get_id() }) + } + + // consume token 'tok' if it exists. Returns true if the given + // token was present, false otherwise. + pub fn eat(&self, tok: &token::Token) -> bool { + return if *self.token == *tok { self.bump(); true } else { false }; + } + + pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { + token::is_keyword(kw, self.token) + } + + // if the next token is the given keyword, eat it and return + // true. Otherwise, return false. + pub fn eat_keyword(&self, kw: keywords::Keyword) -> bool { + let is_kw = match *self.token { + token::IDENT(sid, false) => kw.to_ident().name == sid.name, + _ => false + }; + if is_kw { self.bump() } + is_kw + } + + // if the given word is not a keyword, signal an error. + // if the next token is not the given word, signal an error. + // otherwise, eat it. + pub fn expect_keyword(&self, kw: keywords::Keyword) { + if !self.eat_keyword(kw) { + self.fatal( + fmt!( + "expected `%s`, found `%s`", + self.id_to_str(kw.to_ident()).to_str(), + self.this_token_to_str() + ) + ); + } + } + + // signal an error if the given string is a strict keyword + pub fn check_strict_keywords(&self) { + if token::is_strict_keyword(self.token) { + self.span_err(*self.last_span, + fmt!("found `%s` in ident position", self.this_token_to_str())); + } + } + + // signal an error if the current token is a reserved keyword + pub fn check_reserved_keywords(&self) { + if token::is_reserved_keyword(self.token) { + self.fatal(fmt!("`%s` is a reserved keyword", self.this_token_to_str())); + } + } + + // expect and consume a GT. if a >> is seen, replace it + // with a single > and continue. If a GT is not seen, + // signal an error. + pub fn expect_gt(&self) { + if *self.token == token::GT { + self.bump(); + } else if *self.token == token::BINOP(token::SHR) { + self.replace_token( + token::GT, + self.span.lo + BytePos(1u), + self.span.hi + ); + } else { + let mut s: ~str = ~"expected `"; + s.push_str(self.token_to_str(&token::GT)); + s.push_str("`, found `"); + s.push_str(self.this_token_to_str()); + s.push_str("`"); + self.fatal(s); + } + } + + // parse a sequence bracketed by '<' and '>', stopping + // before the '>'. + pub fn parse_seq_to_before_gt<T: Copy>(&self, + sep: Option<token::Token>, + f: &fn(&Parser) -> T) + -> OptVec<T> { + let mut first = true; + let mut v = opt_vec::Empty; + while *self.token != token::GT + && *self.token != token::BINOP(token::SHR) { + match sep { + Some(ref t) => { + if first { first = false; } + else { self.expect(t); } + } + _ => () + } + v.push(f(self)); + } + return v; + } + + pub fn parse_seq_to_gt<T: Copy>(&self, + sep: Option<token::Token>, + f: &fn(&Parser) -> T) + -> OptVec<T> { + let v = self.parse_seq_to_before_gt(sep, f); + self.expect_gt(); + return v; + } + + // parse a sequence, including the closing delimiter. The function + // f must consume tokens until reaching the next separator or + // closing bracket. + pub fn parse_seq_to_end<T: Copy>(&self, + ket: &token::Token, + sep: SeqSep, + f: &fn(&Parser) -> T) + -> ~[T] { + let val = self.parse_seq_to_before_end(ket, sep, f); + self.bump(); + val + } + + // parse a sequence, not including the closing delimiter. The function + // f must consume tokens until reaching the next separator or + // closing bracket. + pub fn parse_seq_to_before_end<T: Copy>(&self, + ket: &token::Token, + sep: SeqSep, + f: &fn(&Parser) -> T) + -> ~[T] { + let mut first: bool = true; + let mut v: ~[T] = ~[]; + while *self.token != *ket { + match sep.sep { + Some(ref t) => { + if first { first = false; } + else { self.expect(t); } + } + _ => () + } + if sep.trailing_sep_allowed && *self.token == *ket { break; } + v.push(f(self)); + } + return v; + } + + // parse a sequence, including the closing delimiter. The function + // f must consume tokens until reaching the next separator or + // closing bracket. + pub fn parse_unspanned_seq<T: Copy>(&self, + bra: &token::Token, + ket: &token::Token, + sep: SeqSep, + f: &fn(&Parser) -> T) + -> ~[T] { + self.expect(bra); + let result = self.parse_seq_to_before_end(ket, sep, f); + self.bump(); + result + } + + // NB: Do not use this function unless you actually plan to place the + // spanned list in the AST. + pub fn parse_seq<T: Copy>(&self, + bra: &token::Token, + ket: &token::Token, + sep: SeqSep, + f: &fn(&Parser) -> T) + -> spanned<~[T]> { + let lo = self.span.lo; + self.expect(bra); + let result = self.parse_seq_to_before_end(ket, sep, f); + let hi = self.span.hi; + self.bump(); + spanned(lo, hi, result) + } + // advance the parser by one token pub fn bump(&self) { *self.last_span = copy *self.span; @@ -821,6 +1072,11 @@ impl Parser { self.parse_arg_mode(); is_mutbl = self.eat_keyword(keywords::Mut); let pat = self.parse_pat(); + + if is_mutbl && !ast_util::pat_is_ident(pat) { + self.obsolete(*self.span, ObsoleteMutWithMultipleBindings) + } + self.expect(&token::COLON); pat } else { @@ -2437,8 +2693,7 @@ impl Parser { pat = self.parse_pat_ident(bind_by_ref(mutbl)); } else if self.eat_keyword(keywords::Copy) { // parse copy pat - self.warn("copy keyword in patterns no longer has any effect, \ - remove it"); + self.obsolete(*self.span, ObsoletePatternCopyKeyword); pat = self.parse_pat_ident(bind_infer); } else { let can_be_enum_or_struct; @@ -2560,6 +2815,11 @@ impl Parser { fn parse_local(&self, is_mutbl: bool) -> @local { let lo = self.span.lo; let pat = self.parse_pat(); + + if is_mutbl && !ast_util::pat_is_ident(pat) { + self.obsolete(*self.span, ObsoleteMutWithMultipleBindings) + } + let mut ty = @Ty { id: self.get_id(), node: ty_infer, @@ -4244,8 +4504,12 @@ impl Parser { // FAILURE TO PARSE ITEM if visibility != inherited { let mut s = ~"unmatched visibility `"; - s += if visibility == public { "pub" } else { "priv" }; - s += "`"; + if visibility == public { + s.push_str("pub") + } else { + s.push_str("priv") + } + s.push_char('`'); self.span_fatal(*self.last_span, s); } return iovi_none; @@ -4420,7 +4684,8 @@ impl Parser { let mut attrs = vec::append(first_item_attrs, self.parse_outer_attributes()); // First, parse view items. - let mut (view_items, items) = (~[], ~[]); + let mut view_items = ~[]; + let mut items = ~[]; let mut done = false; // I think this code would probably read better as a single // loop with a mutable three-state-variable (for extern mods, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 2ddae73a3fc..94147825da4 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -22,7 +22,7 @@ use std::local_data; use std::rand; use std::rand::RngUtil; -#[deriving(Encodable, Decodable, Eq)] +#[deriving(Encodable, Decodable, Eq, IterBytes)] pub enum binop { PLUS, MINUS, @@ -36,7 +36,7 @@ pub enum binop { SHR, } -#[deriving(Encodable, Decodable, Eq)] +#[deriving(Encodable, Decodable, Eq, IterBytes)] pub enum Token { /* Expression-operator symbols. */ EQ, @@ -97,7 +97,7 @@ pub enum Token { EOF, } -#[deriving(Encodable, Decodable, Eq)] +#[deriving(Encodable, Decodable, Eq, IterBytes)] /// For interpolation during macro expansion. pub enum nonterminal { nt_item(@ast::item), @@ -178,14 +178,14 @@ pub fn to_str(in: @ident_interner, t: &Token) -> ~str { LIT_FLOAT(ref s, t) => { let mut body = ident_to_str(s).to_owned(); if body.ends_with(".") { - body += "0"; // `10.f` is not a float literal + body.push_char('0'); // `10.f` is not a float literal } body + ast_util::float_ty_to_str(t) } LIT_FLOAT_UNSUFFIXED(ref s) => { let mut body = ident_to_str(s).to_owned(); if body.ends_with(".") { - body += "0"; // `10.f` is not a float literal + body.push_char('0'); // `10.f` is not a float literal } body } @@ -484,7 +484,7 @@ pub fn get_ident_interner() -> @ident_interner { unsafe { let key = (cast::transmute::<(uint, uint), - &fn(v: @@::parse::token::ident_interner)>( + &fn:Copy(v: @@::parse::token::ident_interner)>( (-3 as uint, 0u))); match local_data::local_data_get(key) { Some(interner) => *interner, diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 4e03d9bac70..7cd3faf9a90 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -122,12 +122,14 @@ pub fn buf_str(toks: ~[token], szs: ~[int], left: uint, right: uint, let mut s = ~"["; while i != right && L != 0u { L -= 1u; - if i != left { s += ", "; } - s += fmt!("%d=%s", szs[i], tok_str(toks[i])); + if i != left { + s.push_str(", "); + } + s.push_str(fmt!("%d=%s", szs[i], tok_str(toks[i]))); i += 1u; i %= n; } - s += "]"; + s.push_char(']'); return s; } diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index af37c1d27d8..3cdc4fd0fa1 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -21,7 +21,7 @@ pub struct Interner<T> { } // when traits can extend traits, we should extend index<uint,T> to get [] -impl<T:Eq + IterBytes + Hash + Const + Copy> Interner<T> { +impl<T:Eq + IterBytes + Hash + Freeze + Copy> Interner<T> { pub fn new() -> Interner<T> { Interner { map: @mut HashMap::new(), diff --git a/src/test/auxiliary/cci_capture_clause.rs b/src/test/auxiliary/cci_capture_clause.rs index e45bfc8ea5d..beca0adbe3c 100644 --- a/src/test/auxiliary/cci_capture_clause.rs +++ b/src/test/auxiliary/cci_capture_clause.rs @@ -11,7 +11,7 @@ use std::comm::*; use std::task; -pub fn foo<T:Owned + Copy>(x: T) -> Port<T> { +pub fn foo<T:Send + Copy>(x: T) -> Port<T> { let (p, c) = stream(); do task::spawn() { c.send(copy x); diff --git a/src/test/auxiliary/issue-2526.rs b/src/test/auxiliary/issue-2526.rs index d4f6a1ec404..8c491a4dfc8 100644 --- a/src/test/auxiliary/issue-2526.rs +++ b/src/test/auxiliary/issue-2526.rs @@ -20,17 +20,17 @@ struct arc_destruct<T> { } #[unsafe_destructor] -impl<T:Const> Drop for arc_destruct<T> { +impl<T:Freeze> Drop for arc_destruct<T> { fn drop(&self) {} } -fn arc_destruct<T:Const>(data: int) -> arc_destruct<T> { +fn arc_destruct<T:Freeze>(data: int) -> arc_destruct<T> { arc_destruct { _data: data } } -fn arc<T:Const>(_data: T) -> arc_destruct<T> { +fn arc<T:Freeze>(_data: T) -> arc_destruct<T> { arc_destruct(0) } diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 4b5880de8a5..c4d89a698c1 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -29,7 +29,7 @@ macro_rules! bench ( fn main() { let argv = os::args(); - let tests = vec::slice(argv, 1, argv.len()); + let tests = argv.slice(1, argv.len()); bench!(shift_push); bench!(read_line); @@ -87,9 +87,8 @@ fn vec_plus() { while i < 1500 { let rv = vec::from_elem(r.gen_uint_range(0, i + 1), i); if r.gen() { - v += rv; - } - else { + v.push_all_move(rv); + } else { v = rv + v; } i += 1; diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 25bdf7dc3fe..b65a6429f2c 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -118,10 +118,10 @@ fn main() { }; }; - /*for int::range(0, 256) |y| { + for int::range(0, 256) |y| { for int::range(0, 256) |x| { - io::print(symbols[pixels[y*256+x] / 0.2f32 as int]); + print(symbols[pixels[y*256+x] / 0.2f32 as int]); } - io::println(""); - }*/ + println(""); + } } diff --git a/src/test/bench/pingpong.rs b/src/test/bench/pingpong.rs index 63e4174a0fc..1d32a78303a 100644 --- a/src/test/bench/pingpong.rs +++ b/src/test/bench/pingpong.rs @@ -82,7 +82,7 @@ endpoint. The send endpoint is returned to the caller and the receive endpoint is passed to the new task. */ -pub fn spawn_service<T:Owned,Tb:Owned>( +pub fn spawn_service<T:Send,Tb:Send>( init: extern fn() -> (RecvPacketBuffered<T, Tb>, SendPacketBuffered<T, Tb>), service: ~fn(v: RecvPacketBuffered<T, Tb>)) @@ -103,7 +103,7 @@ pub fn spawn_service<T:Owned,Tb:Owned>( receive state. */ -pub fn spawn_service_recv<T:Owned,Tb:Owned>( +pub fn spawn_service_recv<T:Send,Tb:Send>( init: extern fn() -> (SendPacketBuffered<T, Tb>, RecvPacketBuffered<T, Tb>), service: ~fn(v: SendPacketBuffered<T, Tb>)) @@ -120,7 +120,7 @@ pub fn spawn_service_recv<T:Owned,Tb:Owned>( client } -fn switch<T:Owned,Tb:Owned,U>(endp: std::pipes::RecvPacketBuffered<T, Tb>, +fn switch<T:Send,Tb:Send,U>(endp: std::pipes::RecvPacketBuffered<T, Tb>, f: &fn(v: Option<T>) -> U) -> U { f(std::pipes::try_recv(endp)) diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 96c7e4e9b37..49a3a3ec5d7 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -50,8 +50,8 @@ fn show_color(cc: color) -> ~str { fn show_color_list(set: ~[color]) -> ~str { let mut out = ~""; for set.iter().advance |col| { - out += " "; - out += show_color(*col); + out.push_char(' '); + out.push_str(show_color(*col)); } return out; } diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index 670e77bc3a0..5ebcfe164ce 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -96,7 +96,7 @@ impl RepeatFasta { copy_memory(buf, alu, alu_len); let buf_len = buf.len(); - copy_memory(vec::mut_slice(buf, alu_len, buf_len), + copy_memory(buf.mut_slice(alu_len, buf_len), alu, LINE_LEN); diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index f3efcc21ea9..da8d65a1dcb 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -47,7 +47,7 @@ fn make_cumulative(aa: ~[AminoAcids]) -> ~[AminoAcids] { let mut ans: ~[AminoAcids] = ~[]; for aa.iter().advance |a| { cp += a.prob; - ans += [AminoAcids {ch: a.ch, prob: cp}]; + ans.push(AminoAcids {ch: a.ch, prob: cp}); } ans } diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 20042aa0e91..d26fe80e8a1 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -70,7 +70,7 @@ fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str { let b = str::raw::from_bytes(k); // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use // to_ascii_consume and to_str_consume to not do a unnecessary copy. - buffer += (fmt!("%s %0.3f\n", b.to_ascii().to_upper().to_str_ascii(), v)); + buffer.push_str(fmt!("%s %0.3f\n", b.to_ascii().to_upper().to_str_ascii(), v)); } } @@ -90,7 +90,7 @@ fn find(mm: &HashMap<~[u8], uint>, key: ~str) -> uint { // given a map, increment the counter for a key fn update_freq(mm: &mut HashMap<~[u8], uint>, key: &[u8]) { - let key = vec::slice(key, 0, key.len()).to_owned(); + let key = key.to_owned(); let newval = match mm.pop(&key) { Some(v) => v + 1, None => 1 @@ -107,11 +107,11 @@ fn windows_with_carry(bb: &[u8], nn: uint, let len = bb.len(); while ii < len - (nn - 1u) { - it(vec::slice(bb, ii, ii+nn)); + it(bb.slice(ii, ii+nn)); ii += 1u; } - return vec::slice(bb, len - (nn - 1u), len).to_owned(); + return bb.slice(len - (nn - 1u), len).to_owned(); } fn make_sequence_processor(sz: uint, diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index 646b9788f70..405aa68c483 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -8,7 +8,7 @@ use std::libc::{STDIN_FILENO, c_int, fdopen, fgets, fileno, fopen, fstat}; use std::libc::{stat, strlen}; use std::ptr::null; use std::unstable::intrinsics::init; -use std::vec::{reverse, slice}; +use std::vec::{reverse}; use extra::sort::quick_sort3; static LINE_LEN: uint = 80; @@ -194,7 +194,7 @@ fn unpack_symbol(c: u8) -> u8 { fn next_char<'a>(mut buf: &'a [u8]) -> &'a [u8] { loop { - buf = slice(buf, 1, buf.len()); + buf = buf.slice(1, buf.len()); if buf.len() == 0 { break; } @@ -226,7 +226,7 @@ fn read_stdin() -> ~[u8] { fgets(transmute(&mut window[0]), LINE_LEN as c_int, stdin); { - if vec::slice(window, 0, 6) == header { + if window.slice(0, 6) == header { break; } } @@ -235,9 +235,7 @@ fn read_stdin() -> ~[u8] { while fgets(transmute(&mut window[0]), LINE_LEN as c_int, stdin) != null() { - window = vec::mut_slice(window, - strlen(transmute(&window[0])) as uint, - window.len()); + window = window.mut_slice(strlen(transmute(&window[0])) as uint, window.len()); } } diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index 70f56f5c5a3..b79ecd03c0c 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -23,7 +23,10 @@ fn main() { for range(0, h) |y| { let y = y as f64; for range(0, w) |x| { - let mut (Zr, Zi, Tr, Ti) = (0f64, 0f64, 0f64, 0f64); + let mut Zr = 0f64; + let mut Zi = 0f64; + let mut Tr = 0f64; + let mut Ti = 0f64; let Cr = 2.0 * (x as f64) / (w as f64) - 1.5; let Ci = 2.0 * (y as f64) / (h as f64) - 1.0; diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index 01425d82db2..295211e03a1 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -32,7 +32,6 @@ use std::str; use std::task; use std::u64; use std::uint; -use std::vec; fn fib(n: int) -> int { fn pfib(c: &Chan<int>, n: int) { @@ -62,7 +61,7 @@ struct Config { fn parse_opts(argv: ~[~str]) -> Config { let opts = ~[getopts::optflag(~"stress")]; - let opt_args = vec::slice(argv, 1, argv.len()); + let opt_args = argv.slice(1, argv.len()); match getopts::getopts(opt_args, opts) { Ok(ref m) => { diff --git a/src/test/bench/shootout-reverse-complement.rs b/src/test/bench/shootout-reverse-complement.rs index 9893785ecfa..e57dee06c75 100644 --- a/src/test/bench/shootout-reverse-complement.rs +++ b/src/test/bench/shootout-reverse-complement.rs @@ -5,7 +5,6 @@ use std::cast::transmute; use std::libc::{STDOUT_FILENO, c_int, fdopen, fgets, fopen, fputc, fwrite}; use std::libc::{size_t}; use std::ptr::null; -use std::vec::{capacity, reserve, reserve_at_least}; use std::vec::raw::set_len; static LINE_LEN: u32 = 80; @@ -103,13 +102,13 @@ fn main() { let stdout = fdopen(STDOUT_FILENO as c_int, transmute(&mode[0])); let mut out: ~[u8] = ~[]; - reserve(&mut out, 12777888); + out.reserve(12777888); let mut pos = 0; loop { let needed = pos + (LINE_LEN as uint) + 1; - if capacity(&out) < needed { - reserve_at_least(&mut out, needed); + if out.capacity() < needed { + out.reserve_at_least(needed); } let mut ptr = out.unsafe_mut_ref(pos); diff --git a/src/test/bench/shootout-threadring.rs b/src/test/bench/shootout-threadring.rs index a67bbb05dfb..97168de5d43 100644 --- a/src/test/bench/shootout-threadring.rs +++ b/src/test/bench/shootout-threadring.rs @@ -13,7 +13,9 @@ use std::os; fn start(n_tasks: int, token: int) { - let mut (p, ch1) = stream(); + let (p, ch1) = stream(); + let mut p = p; + let mut ch1 = ch1; ch1.send(token); // XXX could not get this to work with a range closure let mut i = 2; diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index f66de385374..2396d6efc5c 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -103,7 +103,9 @@ impl Sudoku { for u8::range(0u8, 9u8) |row| { for u8::range(0u8, 9u8) |col| { let color = self.grid[row][col]; - if color == 0u8 { work += [(row, col)]; } + if color == 0u8 { + work.push((row, col)); + } } } diff --git a/src/test/compile-fail/closure-bounds-subtype.rs b/src/test/compile-fail/closure-bounds-subtype.rs index 887346e35e5..0c9220d18ab 100644 --- a/src/test/compile-fail/closure-bounds-subtype.rs +++ b/src/test/compile-fail/closure-bounds-subtype.rs @@ -5,35 +5,35 @@ fn take_any(_: &fn:()) { fn take_copyable(_: &fn:Copy()) { } -fn take_copyable_owned(_: &fn:Copy+Owned()) { +fn take_copyable_owned(_: &fn:Copy+Send()) { } -fn take_const_owned(_: &fn:Const+Owned()) { +fn take_const_owned(_: &fn:Freeze+Send()) { } fn give_any(f: &fn:()) { take_any(f); take_copyable(f); //~ ERROR expected bounds `Copy` but found no bounds - take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found no bounds + take_copyable_owned(f); //~ ERROR expected bounds `Copy+Send` but found no bounds } fn give_copyable(f: &fn:Copy()) { take_any(f); take_copyable(f); - take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found bounds `Copy` + take_copyable_owned(f); //~ ERROR expected bounds `Copy+Send` but found bounds `Copy` } -fn give_owned(f: &fn:Owned()) { +fn give_owned(f: &fn:Send()) { take_any(f); - take_copyable(f); //~ ERROR expected bounds `Copy` but found bounds `Owned` - take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found bounds `Owned` + take_copyable(f); //~ ERROR expected bounds `Copy` but found bounds `Send` + take_copyable_owned(f); //~ ERROR expected bounds `Copy+Send` but found bounds `Send` } -fn give_copyable_owned(f: &fn:Copy+Owned()) { +fn give_copyable_owned(f: &fn:Copy+Send()) { take_any(f); take_copyable(f); take_copyable_owned(f); - take_const_owned(f); //~ ERROR expected bounds `Owned+Const` but found bounds `Copy+Owned` + take_const_owned(f); //~ ERROR expected bounds `Send+Freeze` but found bounds `Copy+Send` } fn main() {} diff --git a/src/test/compile-fail/impl-bounds-checking.rs b/src/test/compile-fail/impl-bounds-checking.rs new file mode 100644 index 00000000000..00c415a860d --- /dev/null +++ b/src/test/compile-fail/impl-bounds-checking.rs @@ -0,0 +1,24 @@ +// 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. + +pub trait Clone2 { + fn clone(&self) -> Self; +} + + +trait Getter<T: Clone2> { + fn get(&self) -> T; +} + +impl Getter<int> for int { //~ ERROR failed to find an implementation of trait Clone2 for int + fn get(&self) -> int { *self } +} + +fn main() { } diff --git a/src/test/compile-fail/impl-duplicate-methods.rs b/src/test/compile-fail/impl-duplicate-methods.rs index ec766e5ce9b..c6ce4d04e10 100644 --- a/src/test/compile-fail/impl-duplicate-methods.rs +++ b/src/test/compile-fail/impl-duplicate-methods.rs @@ -11,7 +11,7 @@ struct Foo; impl Foo { fn orange(&self){} - fn orange(&self){} //~ ERROR error: duplicate definition of method `orange` + fn orange(&self){} //~ ERROR error: duplicate definition of value `orange` } fn main() {} diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index f7b9371df57..b5a5eed6a35 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -15,7 +15,7 @@ trait vec_monad<A> { impl<A> vec_monad<A> for ~[A] { fn bind<B>(&self, f: &fn(A) -> ~[B]) { let mut r = fail!(); - for self.iter().advance |elt| { r += f(*elt); } + for self.iter().advance |elt| { r = r + f(*elt); } //~^ WARNING unreachable expression //~^^ ERROR the type of this value must be known } diff --git a/src/test/compile-fail/issue-2611-4.rs b/src/test/compile-fail/issue-2611-4.rs index 2385be5723e..531d4eab535 100644 --- a/src/test/compile-fail/issue-2611-4.rs +++ b/src/test/compile-fail/issue-2611-4.rs @@ -20,7 +20,7 @@ struct E { } impl A for E { - fn b<F:Copy + Const,G>(_x: F) -> F { fail!() } //~ ERROR type parameter 0 requires `Const` + fn b<F:Copy + Freeze,G>(_x: F) -> F { fail!() } //~ ERROR type parameter 0 requires `Freeze` } fn main() {} diff --git a/src/test/compile-fail/issue-2766-a.rs b/src/test/compile-fail/issue-2766-a.rs index 91ae0e1c07a..c5d13c81b7c 100644 --- a/src/test/compile-fail/issue-2766-a.rs +++ b/src/test/compile-fail/issue-2766-a.rs @@ -9,12 +9,12 @@ // except according to those terms. pub mod stream { - pub enum Stream<T:Owned> { send(T, ::stream::server::Stream<T>), } + pub enum Stream<T:Send> { send(T, ::stream::server::Stream<T>), } pub mod server { use std::option; use std::pipes; - impl<T:Owned> Stream<T> { + impl<T:Send> Stream<T> { pub fn recv() -> extern fn(v: Stream<T>) -> ::stream::Stream<T> { // resolve really should report just one error here. // Change the test case when it changes. @@ -28,7 +28,7 @@ pub mod stream { } } - pub type Stream<T:Owned> = pipes::RecvPacket<::stream::Stream<T>>; + pub type Stream<T:Send> = pipes::RecvPacket<::stream::Stream<T>>; } } diff --git a/src/test/compile-fail/issue-3177-mutable-struct.rs b/src/test/compile-fail/issue-3177-mutable-struct.rs index 31c0dc7d9c4..180f13d0371 100644 --- a/src/test/compile-fail/issue-3177-mutable-struct.rs +++ b/src/test/compile-fail/issue-3177-mutable-struct.rs @@ -10,7 +10,7 @@ // xfail-test // error-pattern: instantiating a type parameter with an incompatible type -struct S<T:Const> { +struct S<T:Freeze> { s: T, cant_nest: () } diff --git a/src/test/compile-fail/kindck-destructor-owned.rs b/src/test/compile-fail/kindck-destructor-owned.rs index 551b50c94f2..07adc3d81e5 100644 --- a/src/test/compile-fail/kindck-destructor-owned.rs +++ b/src/test/compile-fail/kindck-destructor-owned.rs @@ -2,7 +2,7 @@ struct Foo { f: @mut int, } -impl Drop for Foo { //~ ERROR cannot implement a destructor on a struct that is not Owned +impl Drop for Foo { //~ ERROR cannot implement a destructor on a structure that does not satisfy Send fn drop(&self) { *self.f = 10; } diff --git a/src/test/compile-fail/kindck-nonsendable-1.rs b/src/test/compile-fail/kindck-nonsendable-1.rs index 38983a9aca6..99057ba940c 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 does not fulfill `Owned` - let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Owned` - let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Owned` + let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Send` + let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Send` + let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Send` } diff --git a/src/test/compile-fail/kindck-owned.rs b/src/test/compile-fail/kindck-owned.rs index 3f859b7dc84..848fd95a560 100644 --- a/src/test/compile-fail/kindck-owned.rs +++ b/src/test/compile-fail/kindck-owned.rs @@ -29,6 +29,6 @@ fn main() { copy2(boxed); let owned: ~fn() = || {}; copy2(owned); //~ ERROR does not fulfill `Copy` - let borrowed: &fn() = || {}; + let borrowed: &fn:Copy() = || {}; copy2(borrowed); //~ ERROR does not fulfill `'static` } diff --git a/src/test/compile-fail/liveness-use-after-send.rs b/src/test/compile-fail/liveness-use-after-send.rs index 23d3fff01cf..72555d7e851 100644 --- a/src/test/compile-fail/liveness-use-after-send.rs +++ b/src/test/compile-fail/liveness-use-after-send.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn send<T:Owned>(ch: _chan<T>, data: T) { +fn send<T:Send>(ch: _chan<T>, data: T) { debug!(ch); debug!(data); fail!(); diff --git a/src/test/compile-fail/mutable-enum.rs b/src/test/compile-fail/mutable-enum.rs index 2368e5eb5c5..35842a53a31 100644 --- a/src/test/compile-fail/mutable-enum.rs +++ b/src/test/compile-fail/mutable-enum.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[mutable] +#[no_freeze] enum Foo { A } -fn bar<T: Const>(_: T) {} +fn bar<T: Freeze>(_: T) {} fn main() { let x = A; - bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Const` + bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Freeze` } diff --git a/src/test/compile-fail/mutable-struct.rs b/src/test/compile-fail/mutable-struct.rs index ee040506c40..6f29fcfd96d 100644 --- a/src/test/compile-fail/mutable-struct.rs +++ b/src/test/compile-fail/mutable-struct.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[mutable] +#[no_freeze] struct Foo { a: int } -fn bar<T: Const>(_: T) {} +fn bar<T: Freeze>(_: T) {} fn main() { let x = Foo { a: 5 }; - bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Const` + bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Freeze` } diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs index 605e59d56c8..5f0d4bc60ac 100644 --- a/src/test/compile-fail/no-send-res-ports.rs +++ b/src/test/compile-fail/no-send-res-ports.rs @@ -32,7 +32,7 @@ fn main() { let x = Cell::new(foo(Port(@()))); do task::spawn { - let y = x.take(); //~ ERROR does not fulfill `Owned` + let y = x.take(); //~ ERROR does not fulfill `Send` error!(y); } } diff --git a/src/test/compile-fail/non_owned-enum.rs b/src/test/compile-fail/non_owned-enum.rs index 79c2be8183a..b436bfb8b0f 100644 --- a/src/test/compile-fail/non_owned-enum.rs +++ b/src/test/compile-fail/non_owned-enum.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[non_owned] +#[no_send] enum Foo { A } -fn bar<T: Owned>(_: T) {} +fn bar<T: Send>(_: T) {} fn main() { let x = A; - bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Owned` + bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Send` } diff --git a/src/test/compile-fail/non_owned-struct.rs b/src/test/compile-fail/non_owned-struct.rs index 2d0bc9a7e8e..542c3aa212b 100644 --- a/src/test/compile-fail/non_owned-struct.rs +++ b/src/test/compile-fail/non_owned-struct.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[non_owned] +#[no_send] struct Foo { a: int } -fn bar<T: Owned>(_: T) {} +fn bar<T: Send>(_: T) {} fn main() { let x = Foo { a: 5 }; - bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Owned` + bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Send` } diff --git a/src/test/compile-fail/once-cant-call-twice-on-heap.rs b/src/test/compile-fail/once-cant-call-twice-on-heap.rs new file mode 100644 index 00000000000..4436675d69a --- /dev/null +++ b/src/test/compile-fail/once-cant-call-twice-on-heap.rs @@ -0,0 +1,29 @@ +// 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. + +// Testing guarantees provided by once functions. +// This program would segfault if it were legal. + +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: ~once fn()) { + blk(); + blk(); //~ ERROR use of moved value +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); + } +} diff --git a/src/test/compile-fail/once-cant-call-twice-on-stack.rs b/src/test/compile-fail/once-cant-call-twice-on-stack.rs new file mode 100644 index 00000000000..10877be549e --- /dev/null +++ b/src/test/compile-fail/once-cant-call-twice-on-stack.rs @@ -0,0 +1,30 @@ +// 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. + +// Testing guarantees provided by once functions. +// This program would segfault if it were legal. + +// compile-flags:-Z once-fns +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: &once fn()) { + blk(); + blk(); //~ ERROR use of moved value +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); + } +} diff --git a/src/test/compile-fail/once-cant-copy-stack-once-fn-copy.rs b/src/test/compile-fail/once-cant-copy-stack-once-fn-copy.rs new file mode 100644 index 00000000000..6f524c0068b --- /dev/null +++ b/src/test/compile-fail/once-cant-copy-stack-once-fn-copy.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. + +// Though it should be legal to copy a heap-allocated "once fn:Copy", +// stack closures are not deep-copied, so (counterintuitively) it should be +// illegal to copy them. + +fn foo<'r>(blk: &'r once fn:Copy()) -> (&'r once fn:Copy(), &'r once fn:Copy()) { + (copy blk, blk) //~ ERROR copying a value of non-copyable type +} + +fn main() { +} diff --git a/src/test/compile-fail/once-cant-move-out-of-non-once-on-heap.rs b/src/test/compile-fail/once-cant-move-out-of-non-once-on-heap.rs new file mode 100644 index 00000000000..61f158cec27 --- /dev/null +++ b/src/test/compile-fail/once-cant-move-out-of-non-once-on-heap.rs @@ -0,0 +1,29 @@ +// 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. + +// Testing guarantees provided by once functions. +// This program would segfault if it were legal. + +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: ~fn()) { + blk(); + blk(); +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); //~ ERROR cannot move out of captured outer variable + } +} diff --git a/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs b/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs new file mode 100644 index 00000000000..42c8b9a9998 --- /dev/null +++ b/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs @@ -0,0 +1,29 @@ +// 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. + +// Testing guarantees provided by once functions. +// This program would segfault if it were legal. + +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: &fn()) { + blk(); + blk(); +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); //~ ERROR cannot move out of captured outer variable + } +} diff --git a/src/test/compile-fail/rcmut-not-const-and-not-owned.rs b/src/test/compile-fail/rcmut-not-const-and-not-owned.rs index 9e7236a67d9..45cb137b084 100644 --- a/src/test/compile-fail/rcmut-not-const-and-not-owned.rs +++ b/src/test/compile-fail/rcmut-not-const-and-not-owned.rs @@ -10,11 +10,11 @@ extern mod extra; -fn o<T: Owned>(_: &T) {} -fn c<T: Const>(_: &T) {} +fn o<T: Send>(_: &T) {} +fn c<T: Freeze>(_: &T) {} fn main() { let x = extra::rc::rc_mut_from_owned(0); - o(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Owned` - c(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Const` + o(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Send` + c(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Freeze` } diff --git a/src/test/compile-fail/regions-creating-enums.rs b/src/test/compile-fail/regions-creating-enums.rs index 2ab0c14b49b..c2d8427d5eb 100644 --- a/src/test/compile-fail/regions-creating-enums.rs +++ b/src/test/compile-fail/regions-creating-enums.rs @@ -33,8 +33,8 @@ fn map_nums(x: &ast, f: &fn(uint) -> uint) -> &ast { return &num(f(x)); //~ ERROR borrowed value does not live long enough } add(x, y) => { - let m_x = map_nums(x, f); - let m_y = map_nums(y, f); + let m_x = map_nums(x, |z| f(z)); + let m_y = map_nums(y, |z| f(z)); return &add(m_x, m_y); //~ ERROR borrowed value does not live long enough } } diff --git a/src/test/compile-fail/the-case-of-the-recurring-closure-2.rs b/src/test/compile-fail/the-case-of-the-recurring-closure-2.rs new file mode 100644 index 00000000000..bfb1e910495 --- /dev/null +++ b/src/test/compile-fail/the-case-of-the-recurring-closure-2.rs @@ -0,0 +1,44 @@ +// 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. + +// Tests correct kind-checking of the reason stack closures without the :Copy +// bound must be noncopyable. For details see +// http://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closure/ + +struct R<'self> { + // This struct is needed to create the + // otherwise infinite type of a fn that + // accepts itself as argument: + c: &'self fn:Copy(&R, bool) +} + +fn innocent_looking_victim() { + let mut x = Some(~"hello"); + do conspirator |f, writer| { + if writer { + x = None; //~ ERROR cannot implicitly borrow + } else { + match x { + Some(ref msg) => { + (f.c)(f, true); + println(fmt!("%?", msg)); + }, + None => fail!("oops"), + } + } + } +} + +fn conspirator(f: &fn:Copy(&R, bool)) { + let r = R {c: f}; + f(&r, false) +} + +fn main() { innocent_looking_victim() } diff --git a/src/test/compile-fail/the-case-of-the-recurring-closure.rs b/src/test/compile-fail/the-case-of-the-recurring-closure.rs new file mode 100644 index 00000000000..f05c30c3355 --- /dev/null +++ b/src/test/compile-fail/the-case-of-the-recurring-closure.rs @@ -0,0 +1,44 @@ +// 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. + +// Tests correct kind-checking of the reason stack closures without the :Copy +// bound must be noncopyable. For details see +// http://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closure/ + +struct R<'self> { + // This struct is needed to create the + // otherwise infinite type of a fn that + // accepts itself as argument: + c: &'self fn(&R, bool) +} + +fn innocent_looking_victim() { + let mut x = Some(~"hello"); + do conspirator |f, writer| { + if writer { + x = None; + } else { + match x { + Some(ref msg) => { + (f.c)(f, true); + println(fmt!("%?", msg)); + }, + None => fail!("oops"), + } + } + } +} + +fn conspirator(f: &fn(&R, bool)) { + let r = R {c: f}; + f(&r, false) //~ ERROR use of moved value +} + +fn main() { innocent_looking_victim() } diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs index adaea1de9bd..a96da398f5a 100644 --- a/src/test/compile-fail/trait-bounds-cant-coerce.rs +++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs @@ -11,14 +11,14 @@ trait Foo { } -fn a(_x: ~Foo:Owned) { +fn a(_x: ~Foo:Send) { } -fn b(_x: ~Foo:Owned+Copy) { +fn b(_x: ~Foo:Send+Copy) { } -fn c(x: ~Foo:Const+Owned) { - b(x); //~ ERROR expected bounds `Copy+Owned` +fn c(x: ~Foo:Freeze+Send) { + b(x); //~ ERROR expected bounds `Copy+Send` } fn d(x: ~Foo:) { 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 index e9cc9575003..d7c98ec4e9d 100644 --- a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -13,7 +13,7 @@ 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 foo(_x: Foo:Send) { //~ERROR reference to trait `Foo` where a type is expected } 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 index 45bb5e29a88..ebffd0303e0 100644 --- a/src/test/compile-fail/trait-bounds-not-on-struct.rs +++ b/src/test/compile-fail/trait-bounds-not-on-struct.rs @@ -10,6 +10,6 @@ struct Foo; -fn foo(_x: ~Foo:Owned) { } //~ ERROR kind bounds can only be used on trait types +fn foo(_x: ~Foo:Send) { } //~ ERROR kind bounds can only be used on trait types fn main() { } diff --git a/src/test/compile-fail/trait-bounds-sugar.rs b/src/test/compile-fail/trait-bounds-sugar.rs index 8c641f4c850..68a0ae90014 100644 --- a/src/test/compile-fail/trait-bounds-sugar.rs +++ b/src/test/compile-fail/trait-bounds-sugar.rs @@ -13,7 +13,7 @@ trait Foo { } -fn a(_x: ~Foo) { // should be same as ~Foo:Owned +fn a(_x: ~Foo) { // should be same as ~Foo:Send } fn b(_x: @Foo) { // should be same as ~Foo:'static @@ -22,15 +22,15 @@ fn b(_x: @Foo) { // should be same as ~Foo:'static fn c(_x: &'static Foo) { // should be same as &'static Foo:'static } -fn d(x: ~Foo:Const) { - a(x); //~ ERROR expected bounds `Owned` +fn d(x: ~Foo:Freeze) { + a(x); //~ ERROR expected bounds `Send` } -fn e(x: @Foo:Const) { +fn e(x: @Foo:Freeze) { b(x); //~ ERROR expected bounds `'static` } -fn f(x: &'static Foo:Const) { +fn f(x: &'static Foo:Freeze) { c(x); //~ ERROR expected bounds `'static` } diff --git a/src/test/compile-fail/trait-duplicate-methods.rs b/src/test/compile-fail/trait-duplicate-methods.rs index e2ba5267eba..ba8101d16ab 100644 --- a/src/test/compile-fail/trait-duplicate-methods.rs +++ b/src/test/compile-fail/trait-duplicate-methods.rs @@ -10,7 +10,7 @@ trait Foo { fn orange(&self); - fn orange(&self); //~ ERROR error: duplicate definition of method `orange` + fn orange(&self); //~ ERROR error: duplicate definition of value `orange` } fn main() {} diff --git a/src/test/compile-fail/trait-or-new-type-instead.rs b/src/test/compile-fail/trait-or-new-type-instead.rs index f687a6f9702..c44887593ab 100644 --- a/src/test/compile-fail/trait-or-new-type-instead.rs +++ b/src/test/compile-fail/trait-or-new-type-instead.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: implement a trait or new type instead +// error-pattern: found value name used as a type impl<T> Option<T> { pub fn foo(&self) { } } diff --git a/src/test/compile-fail/unique-unique-kind.rs b/src/test/compile-fail/unique-unique-kind.rs index 26058bf89ca..d51df4979e3 100644 --- a/src/test/compile-fail/unique-unique-kind.rs +++ b/src/test/compile-fail/unique-unique-kind.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f<T:Owned>(_i: T) { +fn f<T:Send>(_i: T) { } fn main() { let i = ~@100; - f(i); //~ ERROR does not fulfill `Owned` + f(i); //~ ERROR does not fulfill `Send` } diff --git a/src/test/compile-fail/unsendable-class.rs b/src/test/compile-fail/unsendable-class.rs index 58de0926f7c..de089dcf914 100644 --- a/src/test/compile-fail/unsendable-class.rs +++ b/src/test/compile-fail/unsendable-class.rs @@ -27,6 +27,6 @@ fn foo(i:int, j: @~str) -> foo { fn main() { let cat = ~"kitty"; - let (_, ch) = comm::stream(); //~ ERROR does not fulfill `Owned` - ch.send(foo(42, @(cat))); //~ ERROR does not fulfill `Owned` + let (_, ch) = comm::stream(); //~ ERROR does not fulfill `Send` + ch.send(foo(42, @(cat))); //~ ERROR does not fulfill `Send` } diff --git a/src/test/debug-info/basic-types.rs b/src/test/debug-info/basic-types.rs index 616740c850c..7125ebe8d56 100644 --- a/src/test/debug-info/basic-types.rs +++ b/src/test/debug-info/basic-types.rs @@ -26,8 +26,8 @@ // check:$2 = -1 // debugger:print c // check:$3 = 97 -// debugger:print i8 -// check:$4 = 68 'D' +// debugger:print/d i8 +// check:$4 = 68 // debugger:print i16 // check:$5 = -16 // debugger:print i32 @@ -36,8 +36,8 @@ // check:$7 = -64 // debugger:print u // check:$8 = 1 -// debugger:print u8 -// check:$9 = 100 'd' +// debugger:print/d u8 +// check:$9 = 100 // debugger:print u16 // check:$10 = 16 // debugger:print u32 diff --git a/src/test/debug-info/tuple.rs b/src/test/debug-info/destructured-local.rs index a50996871ce..bf53d95b588 100644 --- a/src/test/debug-info/tuple.rs +++ b/src/test/debug-info/destructured-local.rs @@ -8,19 +8,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 +// xfail-test + +// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical +// value. // compile-flags:-Z extra-debug-info -// debugger:set print pretty off -// debugger:break _zzz +// debugger:break zzz // debugger:run // debugger:finish -// debugger:print t -// check:$1 = {4, 5.5, true} + +// debugger:print a +// check:$1 = 9898 + +// debugger:print b +// check:$2 = false fn main() { - let t = (4, 5.5, true); - _zzz(); + let (a, b) : (int, bool) = (9898, false); + + zzz(); } -fn _zzz() {()} \ No newline at end of file +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/function-arguments.rs b/src/test/debug-info/function-arguments.rs new file mode 100644 index 00000000000..f5563cda259 --- /dev/null +++ b/src/test/debug-info/function-arguments.rs @@ -0,0 +1,51 @@ +// 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-test + +// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical +// value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print x +// check:$1 = 111102 +// debugger:print y +// check:$2 = true + +// debugger:continue +// debugger:finish + +// debugger:print a +// check:$3 = 2000 +// debugger:print b +// check:$4 = 3000 + +fn main() { + + fun(111102, true); + nested(2000, 3000); + + fn nested(a: i32, b: i64) -> (i32, i64) { + zzz() + (a, b) + } +} + +fn fun(x: int, y: bool) -> (int, bool) { + zzz(); + + (x, y) +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-basic.rs b/src/test/debug-info/reference-to-basic.rs new file mode 100644 index 00000000000..dfd0fbf8655 --- /dev/null +++ b/src/test/debug-info/reference-to-basic.rs @@ -0,0 +1,116 @@ +// 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-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// Caveats - gdb prints any 8-bit value (meaning rust i8 and u8 values) +// as its numerical value along with its associated ASCII char, there +// doesn't seem to be any way around this. Also, gdb doesn't know +// about UTF-32 character encoding and will print a rust char as only +// its numerical value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish +// debugger:print *bool_ref +// check:$1 = true + +// debugger:print *int_ref +// check:$2 = -1 + +// debugger:print *char_ref +// check:$3 = 97 + +// debugger:print *i8_ref +// check:$4 = 68 'D' + +// debugger:print *i16_ref +// check:$5 = -16 + +// debugger:print *i32_ref +// check:$6 = -32 + +// debugger:print *i64_ref +// check:$7 = -64 + +// debugger:print *uint_ref +// check:$8 = 1 + +// debugger:print *u8_ref +// check:$9 = 100 'd' + +// debugger:print *u16_ref +// check:$10 = 16 + +// debugger:print *u32_ref +// check:$11 = 32 + +// debugger:print *u64_ref +// check:$12 = 64 + +// debugger:print *float_ref +// check:$13 = 1.5 + +// debugger:print *f32_ref +// check:$14 = 2.5 + +// debugger:print *f64_ref +// check:$15 = 3.5 + +fn main() { + let bool_val: bool = true; + let bool_ref : &bool = &bool_val; + + let int_val: int = -1; + let int_ref : &int = &int_val; + + let char_val: char = 'a'; + let char_ref : &char = &char_val; + + let i8_val: i8 = 68; + let i8_ref : &i8 = &i8_val; + + let i16_val: i16 = -16; + let i16_ref : &i16 = &i16_val; + + let i32_val: i32 = -32; + let i32_ref : &i32 = &i32_val; + + let uint_val: i64 = -64; + let i64_ref : &i64 = &uint_val; + + let uint_val: uint = 1; + let uint_ref : &uint = &uint_val; + + let u8_val: u8 = 100; + let u8_ref : &u8 = &u8_val; + + let u16_val: u16 = 16; + let u16_ref : &u16 = &u16_val; + + let u32_val: u32 = 32; + let u32_ref : &u32 = &u32_val; + + let u64_val: u64 = 64; + let u64_ref : &u64 = &u64_val; + + let float_val: float = 1.5; + let float_ref : &float = &float_val; + + let f32_val: f32 = 2.5; + let f32_ref : &f32 = &f32_val; + + let f64_val: f64 = 3.5; + let f64_ref : &f64 = &f64_val; + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-managed-basic.rs b/src/test/debug-info/reference-to-managed-basic.rs new file mode 100644 index 00000000000..e3951c94b6f --- /dev/null +++ b/src/test/debug-info/reference-to-managed-basic.rs @@ -0,0 +1,114 @@ +// 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-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// Gdb doesn't know about UTF-32 character encoding and will print a rust char as only +// its numerical value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish +// debugger:print *bool_ref +// check:$1 = true + +// debugger:print *int_ref +// check:$2 = -1 + +// debugger:print *char_ref +// check:$3 = 97 + +// debugger:print/d *i8_ref +// check:$4 = 68 + +// debugger:print *i16_ref +// check:$5 = -16 + +// debugger:print *i32_ref +// check:$6 = -32 + +// debugger:print *i64_ref +// check:$7 = -64 + +// debugger:print *uint_ref +// check:$8 = 1 + +// debugger:print/d *u8_ref +// check:$9 = 100 + +// debugger:print *u16_ref +// check:$10 = 16 + +// debugger:print *u32_ref +// check:$11 = 32 + +// debugger:print *u64_ref +// check:$12 = 64 + +// debugger:print *float_ref +// check:$13 = 1.5 + +// debugger:print *f32_ref +// check:$14 = 2.5 + +// debugger:print *f64_ref +// check:$15 = 3.5 + + +fn main() { + let bool_box: @bool = @true; + let bool_ref : &bool = bool_box; + + let int_box: @int = @-1; + let int_ref : &int = int_box; + + let char_box: @char = @'a'; + let char_ref : &char = char_box; + + let i8_box: @i8 = @68; + let i8_ref : &i8 = i8_box; + + let i16_box: @i16 = @-16; + let i16_ref : &i16 = i16_box; + + let i32_box: @i32 = @-32; + let i32_ref : &i32 = i32_box; + + let i64_box: @i64 = @-64; + let i64_ref : &i64 = i64_box; + + let uint_box: @uint = @1; + let uint_ref : &uint = uint_box; + + let u8_box: @u8 = @100; + let u8_ref : &u8 = u8_box; + + let u16_box: @u16 = @16; + let u16_ref : &u16 = u16_box; + + let u32_box: @u32 = @32; + let u32_ref : &u32 = u32_box; + + let u64_box: @u64 = @64; + let u64_ref : &u64 = u64_box; + + let float_box: @float = @1.5; + let float_ref : &float = float_box; + + let f32_box: @f32 = @2.5; + let f32_ref : &f32 = f32_box; + + let f64_box: @f64 = @3.5; + let f64_ref : &f64 = f64_box; + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-struct.rs b/src/test/debug-info/reference-to-struct.rs new file mode 100644 index 00000000000..f00872c00b0 --- /dev/null +++ b/src/test/debug-info/reference-to-struct.rs @@ -0,0 +1,78 @@ +// 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-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical +// value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print *stack_val_ref +// check:$1 = {x = 10, y = 23.5} + +// debugger:print *stack_val_interior_ref_1 +// check:$2 = 10 + +// debugger:print *stack_val_interior_ref_2 +// check:$3 = 23.5 + +// debugger:print *ref_to_unnamed +// check:$4 = {x = 11, y = 24.5} + +// debugger:print *managed_val_ref +// check:$5 = {x = 12, y = 25.5} + +// debugger:print *managed_val_interior_ref_1 +// check:$6 = 12 + +// debugger:print *managed_val_interior_ref_2 +// check:$7 = 25.5 + +// debugger:print *unique_val_ref +// check:$8 = {x = 13, y = 26.5} + +// debugger:print *unique_val_interior_ref_1 +// check:$9 = 13 + +// debugger:print *unique_val_interior_ref_2 +// check:$10 = 26.5 + + + +struct SomeStruct { + x: int, + y: f64 +} + +fn main() { + let stack_val: SomeStruct = SomeStruct { x: 10, y: 23.5 }; + let stack_val_ref : &SomeStruct = &stack_val; + let stack_val_interior_ref_1 : &int = &stack_val.x; + let stack_val_interior_ref_2 : &f64 = &stack_val.y; + let ref_to_unnamed : &SomeStruct = &SomeStruct { x: 11, y: 24.5 }; + + let managed_val = @SomeStruct { x: 12, y: 25.5 }; + let managed_val_ref : &SomeStruct = managed_val; + let managed_val_interior_ref_1 : &int = &managed_val.x; + let managed_val_interior_ref_2 : &f64 = &managed_val.y; + + let unique_val = ~SomeStruct { x: 13, y: 26.5 }; + let unique_val_ref : &SomeStruct = unique_val; + let unique_val_interior_ref_1 : &int = &unique_val.x; + let unique_val_interior_ref_2 : &f64 = &unique_val.y; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-tuple.rs b/src/test/debug-info/reference-to-tuple.rs new file mode 100644 index 00000000000..86d02185bda --- /dev/null +++ b/src/test/debug-info/reference-to-tuple.rs @@ -0,0 +1,47 @@ +// 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-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical +// value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print *stack_val_ref +// check:$1 = {-14, -19} + +// debugger:print *ref_to_unnamed +// check:$2 = {-15, -20} + +// debugger:print *managed_val_ref +// check:$3 = {-16, -21} + +// debugger:print *unique_val_ref +// check:$4 = {-17, -22} + +fn main() { + let stack_val: (i16, f32) = (-14, -19f32); + let stack_val_ref : &(i16, f32) = &stack_val; + let ref_to_unnamed : &(i16, f32) = &(-15, -20f32); + + let managed_val : @(i16, f32) = @(-16, -21f32); + let managed_val_ref : &(i16, f32) = managed_val; + + let unique_val: ~(i16, f32) = ~(-17, -22f32); + let unique_val_ref : &(i16, f32) = unique_val; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-unique-basic.rs b/src/test/debug-info/reference-to-unique-basic.rs new file mode 100644 index 00000000000..ce5b50459f6 --- /dev/null +++ b/src/test/debug-info/reference-to-unique-basic.rs @@ -0,0 +1,115 @@ +// 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-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// Gdb doesn't know +// about UTF-32 character encoding and will print a rust char as only +// its numerical value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish +// debugger:print *bool_ref +// check:$1 = true + +// debugger:print *int_ref +// check:$2 = -1 + +// debugger:print *char_ref +// check:$3 = 97 + +// debugger:print/d *i8_ref +// check:$4 = 68 + +// debugger:print *i16_ref +// check:$5 = -16 + +// debugger:print *i32_ref +// check:$6 = -32 + +// debugger:print *i64_ref +// check:$7 = -64 + +// debugger:print *uint_ref +// check:$8 = 1 + +// debugger:print/d *u8_ref +// check:$9 = 100 + +// debugger:print *u16_ref +// check:$10 = 16 + +// debugger:print *u32_ref +// check:$11 = 32 + +// debugger:print *u64_ref +// check:$12 = 64 + +// debugger:print *float_ref +// check:$13 = 1.5 + +// debugger:print *f32_ref +// check:$14 = 2.5 + +// debugger:print *f64_ref +// check:$15 = 3.5 + + +fn main() { + let bool_box: ~bool = ~true; + let bool_ref : &bool = bool_box; + + let int_box: ~int = ~-1; + let int_ref : &int = int_box; + + let char_box: ~char = ~'a'; + let char_ref : &char = char_box; + + let i8_box: ~i8 = ~68; + let i8_ref : &i8 = i8_box; + + let i16_box: ~i16 = ~-16; + let i16_ref : &i16 = i16_box; + + let i32_box: ~i32 = ~-32; + let i32_ref : &i32 = i32_box; + + let i64_box: ~i64 = ~-64; + let i64_ref : &i64 = i64_box; + + let uint_box: ~uint = ~1; + let uint_ref : &uint = uint_box; + + let u8_box: ~u8 = ~100; + let u8_ref : &u8 = u8_box; + + let u16_box: ~u16 = ~16; + let u16_ref : &u16 = u16_box; + + let u32_box: ~u32 = ~32; + let u32_ref : &u32 = u32_box; + + let u64_box: ~u64 = ~64; + let u64_ref : &u64 = u64_box; + + let float_box: ~float = ~1.5; + let float_ref : &float = float_box; + + let f32_box: ~f32 = ~2.5; + let f32_ref : &f32 = f32_box; + + let f64_box: ~f64 = ~3.5; + let f64_ref : &f64 = f64_box; + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/simple-struct.rs b/src/test/debug-info/simple-struct.rs new file mode 100644 index 00000000000..49e7bc255c1 --- /dev/null +++ b/src/test/debug-info/simple-struct.rs @@ -0,0 +1,84 @@ +// 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-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print no_padding16 +// check:$1 = {x = 10000, y = -10001} + +// debugger:print no_padding32 +// check:$2 = {x = -10002, y = -10003.5, z = 10004} + +// debugger:print no_padding64 +// check:$3 = {x = -10005.5, y = 10006, z = 10007} + +// debugger:print no_padding163264 +// check:$4 = {a = -10008, b = 10009, c = 10010, d = 10011} + +// debugger:print internal_padding +// check:$5 = {x = 10012, y = -10013} + +// debugger:print padding_at_end +// check:$6 = {x = -10014, y = 10015} + + +struct NoPadding16 { + x: u16, + y: i16 +} + +struct NoPadding32 { + x: i32, + y: f32, + z: u32 +} + +struct NoPadding64 { + x: f64, + y: i64, + z: u64 +} + +struct NoPadding163264 { + a: i16, + b: u16, + c: i32, + d: u64 +} + +struct InternalPadding { + x: u16, + y: i64 +} + +struct PaddingAtEnd { + x: i64, + y: u16 +} + +fn main() { + let no_padding16 = NoPadding16 { x: 10000, y: -10001 }; + let no_padding32 = NoPadding32 { x: -10002, y: -10003.5, z: 10004 }; + let no_padding64 = NoPadding64 { x: -10005.5, y: 10006, z: 10007 }; + let no_padding163264 = NoPadding163264 { a: -10008, b: 10009, c: 10010, d: 10011 }; + + let internal_padding = InternalPadding { x: 10012, y: -10013 }; + let padding_at_end = PaddingAtEnd { x: -10014, y: 10015 }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/simple-tuple.rs b/src/test/debug-info/simple-tuple.rs new file mode 100644 index 00000000000..84c736fab6b --- /dev/null +++ b/src/test/debug-info/simple-tuple.rs @@ -0,0 +1,51 @@ +// 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-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print/d noPadding8 +// check:$1 = {-100, 100} +// debugger:print noPadding16 +// check:$2 = {0, 1, 2} +// debugger:print noPadding32 +// check:$3 = {3, 4.5, 5} +// debugger:print noPadding64 +// check:$4 = {6, 7.5, 8} + +// debugger:print internalPadding1 +// check:$5 = {9, 10} +// debugger:print internalPadding2 +// check:$6 = {11, 12, 13, 14} + +// debugger:print paddingAtEnd +// check:$7 = {15, 16} + + +fn main() { + let noPadding8 : (i8, u8) = (-100, 100); + let noPadding16 : (i16, i16, u16) = (0, 1, 2); + let noPadding32 : (i32, f32, u32) = (3, 4.5, 5); + let noPadding64 : (i64, f64, u64) = (6, 7.5, 8); + + let internalPadding1 : (i16, i32) = (9, 10); + let internalPadding2 : (i16, i32, u32, u64) = (11, 12, 13, 14); + + let paddingAtEnd : (i32, i16) = (15, 16); + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/struct-in-struct.rs b/src/test/debug-info/struct-in-struct.rs new file mode 100644 index 00000000000..04c5eec610b --- /dev/null +++ b/src/test/debug-info/struct-in-struct.rs @@ -0,0 +1,145 @@ +// 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-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print three_simple_structs +// check:$1 = {x = {x = 1}, y = {x = 2}, z = {x = 3}} + +// debugger:print internal_padding_parent +// check:$2 = {x = {x = 4, y = 5}, y = {x = 6, y = 7}, z = {x = 8, y = 9}} + +// debugger:print padding_at_end_parent +// check:$3 = {x = {x = 10, y = 11}, y = {x = 12, y = 13}, z = {x = 14, y = 15}} + + +struct Simple { + x: i32 +} + +struct InternalPadding { + x: i32, + y: i64 +} + +struct PaddingAtEnd { + x: i64, + y: i32 +} + +struct ThreeSimpleStructs { + x: Simple, + y: Simple, + z: Simple +} + +struct InternalPaddingParent { + x: InternalPadding, + y: InternalPadding, + z: InternalPadding +} + +struct PaddingAtEndParent { + x: PaddingAtEnd, + y: PaddingAtEnd, + z: PaddingAtEnd +} + +struct Mixed { + x: PaddingAtEnd, + y: InternalPadding, + z: Simple, + w: i16 +} + +struct Bag { + x: Simple +} + +struct BagInBag { + x: Bag +} + +struct ThatsJustOverkill { + x: BagInBag +} + +struct Tree { + x: Simple, + y: InternalPaddingParent, + z: BagInBag +} + +fn main() { + + let three_simple_structs = ThreeSimpleStructs { + x: Simple { x: 1 }, + y: Simple { x: 2 }, + z: Simple { x: 3 } + }; + + let internal_padding_parent = InternalPaddingParent { + x: InternalPadding { x: 4, y: 5 }, + y: InternalPadding { x: 6, y: 7 }, + z: InternalPadding { x: 8, y: 9 } + }; + + let padding_at_end_parent = PaddingAtEndParent { + x: PaddingAtEnd { x: 10, y: 11 }, + y: PaddingAtEnd { x: 12, y: 13 }, + z: PaddingAtEnd { x: 14, y: 15 } + }; + + let mixed = Mixed { + x: PaddingAtEnd { x: 16, y: 17 }, + y: InternalPadding { x: 18, y: 19 }, + z: Simple { x: 20 }, + w: 21 + }; + + let bag = Bag { x: Simple { x: 22 } }; + let bag_in_bag = BagInBag { + x: Bag { + x: Simple { x: 23 } + } + }; + + let tjo = ThatsJustOverkill { + x: BagInBag { + x: Bag { + x: Simple { x: 24 } + } + } + }; + + let tree = Tree { + x: Simple { x: 25 }, + y: InternalPaddingParent { + x: InternalPadding { x: 26, y: 27 }, + y: InternalPadding { x: 28, y: 29 }, + z: InternalPadding { x: 30, y: 31 } + }, + z: BagInBag { + x: Bag { + x: Simple { x: 32 } + } + } + }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/struct-with-destructor.rs b/src/test/debug-info/struct-with-destructor.rs new file mode 100644 index 00000000000..f8281bba49e --- /dev/null +++ b/src/test/debug-info/struct-with-destructor.rs @@ -0,0 +1,88 @@ +// 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-test + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish +// debugger:print simple +// check:$1 = {x = 10, y = 20} + +// debugger:print noDestructor +// check:$2 = {a = {x = 10, y = 20}, guard = -1} + +// debugger:print withDestructor +// check:$3 = {a = {x = 10, y = 20}, guard = -1} + +struct NoDestructor { + x : i32, + y : i64 +} + +struct WithDestructor { + x : i32, + y : i64 +} + +impl Drop for WithDestructor { + fn finalize(&self) {} +} + +struct NoDestructorGuarded { + a: NoDestructor, + guard: i64 +} + +struct WithDestructorGuarded { + a: WithDestructor, + guard: i64 +} + + +// The compiler adds a 'destructed' boolean field to structs implementing Drop. This field is used +// at runtime to prevent drop() to be executed more than once (see middle::trans::adt). +// This field must be incorporated by the debug info generation. Otherwise the debugger assumes a +// wrong size/layout for the struct. +fn main() { + + let simple = WithDestructor { x: 10, y: 20 }; + + let noDestructor = NoDestructorGuarded { + a: NoDestructor { x: 10, y: 20 }, + guard: -1 + }; + + // If the destructor flag field is not incorporated into the debug info for 'WithDestructor' + // then the debugger will have an invalid offset for the field 'guard' and thus should not be + // able to read its value correctly (dots are padding bytes, D is the boolean destructor flag): + // + // NoDestructorGuarded = 0000....00000000FFFFFFFF + // <--------------><------> + // NoDestructor guard + // + // + // withDestructorGuarded = 0000....00000000D.......FFFFFFFF + // <--------------><------> // How debug info says it is + // WithDestructor guard + // + // <----------------------><------> // How it actually is + // WithDestructor guard + // + let withDestructor = WithDestructorGuarded { + a: WithDestructor { x: 10, y: 20 }, + guard: -1 + }; + + zzz(); +} + +fn zzz() {()} diff --git a/src/test/debug-info/tuple-in-struct.rs b/src/test/debug-info/tuple-in-struct.rs new file mode 100644 index 00000000000..369c9fd28cc --- /dev/null +++ b/src/test/debug-info/tuple-in-struct.rs @@ -0,0 +1,151 @@ +// 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-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print no_padding1 +// check:$1 = {x = {0, 1}, y = 2, z = {3, 4, 5}} +// debugger:print no_padding2 +// check:$2 = {x = {6, 7}, y = {{8, 9}, 10}} + +// debugger:print tuple_internal_padding +// check:$3 = {x = {11, 12}, y = {13, 14}} +// debugger:print struct_internal_padding +// check:$4 = {x = {15, 16}, y = {17, 18}} +// debugger:print both_internally_padded +// check:$5 = {x = {19, 20, 21}, y = {22, 23}} + +// debugger:print single_tuple +// check:$6 = {x = {24, 25, 26}} + +// debugger:print tuple_padded_at_end +// check:$7 = {x = {27, 28}, y = {29, 30}} +// debugger:print struct_padded_at_end +// check:$8 = {x = {31, 32}, y = {33, 34}} +// debugger:print both_padded_at_end +// check:$9 = {x = {35, 36, 37}, y = {38, 39}} + +// debugger:print mixed_padding +// check:$10 = {x = {{40, 41, 42}, {43, 44}}, y = {45, 46, 47, 48}} + +struct NoPadding1 { + x: (i32, i32), + y: i32, + z: (i32, i32, i32) +} + +struct NoPadding2 { + x: (i32, i32), + y: ((i32, i32), i32) +} + +struct TupleInternalPadding { + x: (i16, i32), + y: (i32, i64) +} + +struct StructInternalPadding { + x: (i16, i16), + y: (i64, i64) +} + +struct BothInternallyPadded { + x: (i16, i32, i32), + y: (i32, i64) +} + +struct SingleTuple { + x: (i16, i32, i64) +} + +struct TuplePaddedAtEnd { + x: (i32, i16), + y: (i64, i32) +} + +struct StructPaddedAtEnd { + x: (i64, i64), + y: (i16, i16) +} + +struct BothPaddedAtEnd { + x: (i32, i32, i16), + y: (i64, i32) +} + +// Data-layout (padding signified by dots, one column = 2 bytes): +// [a.bbc...ddddee..ffffg.hhi...] +struct MixedPadding { + x: ((i16, i32, i16), (i64, i32)), + y: (i64, i16, i32, i16) +} + + +fn main() { + let no_padding1 = NoPadding1 { + x: (0, 1), + y: 2, + z: (3, 4, 5) + }; + + let no_padding2 = NoPadding2 { + x: (6, 7), + y: ((8, 9), 10) + }; + + let tuple_internal_padding = TupleInternalPadding { + x: (11, 12), + y: (13, 14) + }; + + let struct_internal_padding = StructInternalPadding { + x: (15, 16), + y: (17, 18) + }; + + let both_internally_padded = BothInternallyPadded { + x: (19, 20, 21), + y: (22, 23) + }; + + let single_tuple = SingleTuple { + x: (24, 25, 26) + }; + + let tuple_padded_at_end = TuplePaddedAtEnd { + x: (27, 28), + y: (29, 30) + }; + + let struct_padded_at_end = StructPaddedAtEnd { + x: (31, 32), + y: (33, 34) + }; + + let both_padded_at_end = BothPaddedAtEnd { + x: (35, 36, 37), + y: (38, 39) + }; + + let mixed_padding = MixedPadding { + x: ((40, 41, 42), (43, 44)), + y: (45, 46, 47, 48) + }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/tuple-in-tuple.rs b/src/test/debug-info/tuple-in-tuple.rs new file mode 100644 index 00000000000..13f8719694e --- /dev/null +++ b/src/test/debug-info/tuple-in-tuple.rs @@ -0,0 +1,50 @@ +// 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-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print no_padding1 +// check:$1 = {{0, 1}, 2, 3} +// debugger:print no_padding2 +// check:$2 = {4, {5, 6}, 7} +// debugger:print no_padding3 +// check:$3 = {8, 9, {10, 11}} + +// debugger:print internal_padding1 +// check:$4 = {12, {13, 14}} +// debugger:print internal_padding2 +// check:$5 = {15, {16, 17}} + +// debugger:print padding_at_end1 +// check:$6 = {18, {19, 20}} +// debugger:print padding_at_end2 +// check:$7 = {{21, 22}, 23} + +fn main() { + let no_padding1 : ((u32, u32), u32, u32) = ((0, 1), 2, 3); + let no_padding2 : (u32, (u32, u32), u32) = (4, (5, 6), 7); + let no_padding3 : (u32, u32, (u32, u32)) = (8, 9, (10, 11)); + + let internal_padding1 : (i16, (i32, i32)) = (12, (13, 14)); + let internal_padding2 : (i16, (i16, i32)) = (15, (16, 17)); + + let padding_at_end1 : (i32, (i32, i16)) = (18, (19, 20)); + let padding_at_end2 : ((i32, i16), i32) = ((21, 22), 23); + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/struct.rs b/src/test/debug-info/variable-scope.rs index ddfac9cbeea..dd3a1671b78 100644 --- a/src/test/debug-info/struct.rs +++ b/src/test/debug-info/variable-scope.rs @@ -8,28 +8,42 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 +// xfail-test // compile-flags:-Z extra-debug-info -// debugger:set print pretty off -// debugger:break _zzz +// debugger:break zzz // debugger:run // debugger:finish -// debugger:print pair -// check:$1 = {x = 1, y = 2} -// debugger:print pair.x -// check:$2 = 1 -// debugger:print pair.y -// check:$3 = 2 - -struct Pair { - x: int, - y: int -} +// debugger:print x +// check:$1 = false +// debugger:print y +// check:$2 = true + +// debugger:continue +// debugger:finish +// debugger:print x +// check:$3 = 10 + +// debugger:continue +// debugger:finish +// debugger:print x +// check:$4 = false +// debugger:print y +// check:$5 = 11 fn main() { - let pair = Pair { x: 1, y: 2 }; - _zzz(); + let x = false; + let y = true; + + zzz(); + + { + let x = 10; + zzz(); + } + + let y = 11; + zzz(); } -fn _zzz() {()} \ No newline at end of file +fn zzz() {()} diff --git a/src/test/run-fail/bug-811.rs b/src/test/run-fail/bug-811.rs index b497b0224b9..992747187f6 100644 --- a/src/test/run-fail/bug-811.rs +++ b/src/test/run-fail/bug-811.rs @@ -19,6 +19,6 @@ struct chan_t<T> { port: port_id, } -fn send<T:Owned>(ch: chan_t<T>, data: T) { fail!(); } +fn send<T:Send>(ch: chan_t<T>, data: T) { fail!(); } fn main() { fail!("quux"); } diff --git a/src/test/run-fail/issue-3029.rs b/src/test/run-fail/issue-3029.rs index 6f4a3f5ab1d..caee0002788 100644 --- a/src/test/run-fail/issue-3029.rs +++ b/src/test/run-fail/issue-3029.rs @@ -10,9 +10,9 @@ // error-pattern:so long fn main() { - let x = ~[]; + let mut x = ~[]; let y = ~[3]; fail!("so long"); - x += y; + x.push_all_move(y); ~"good" + ~"bye"; } diff --git a/src/test/run-pass/alignment-gep-tup-like-2.rs b/src/test/run-pass/alignment-gep-tup-like-2.rs index 753e5339de9..24709fb2974 100644 --- a/src/test/run-pass/alignment-gep-tup-like-2.rs +++ b/src/test/run-pass/alignment-gep-tup-like-2.rs @@ -23,7 +23,7 @@ fn make_cycle<A:Copy>(a: A) { g.rec = Some(g); } -fn f<A:Owned + Copy,B:Owned + Copy>(a: A, b: B) -> @fn() -> (A, B) { +fn f<A:Send + Copy,B:Send + Copy>(a: A, b: B) -> @fn() -> (A, B) { let result: @fn() -> (A, B) = || (copy a, copy b); result } diff --git a/src/test/run-pass/attr-no-drop-flag-size.rs b/src/test/run-pass/attr-no-drop-flag-size.rs index 00a7955d834..87c476d781e 100644 --- a/src/test/run-pass/attr-no-drop-flag-size.rs +++ b/src/test/run-pass/attr-no-drop-flag-size.rs @@ -10,7 +10,7 @@ use std::sys::size_of; -#[no_drop_flag] +#[unsafe_no_drop_flag] struct Test<T> { a: T } diff --git a/src/test/run-pass/bug-7183-generics.rs b/src/test/run-pass/bug-7183-generics.rs new file mode 100644 index 00000000000..4fc5587e7f3 --- /dev/null +++ b/src/test/run-pass/bug-7183-generics.rs @@ -0,0 +1,45 @@ +// 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. + +#[allow(default_methods)] +trait Speak { + fn say(&self, s:&str) -> ~str; + fn hi(&self) -> ~str { hello(self) } +} + +fn hello<S:Speak>(s:&S) -> ~str{ + s.say("hello") +} + +impl Speak for int { + fn say(&self, s:&str) -> ~str { + fmt!("%s: %d", s, *self) + } +} + +impl<T: Speak> Speak for Option<T> { + fn say(&self, s:&str) -> ~str { + match *self { + None => fmt!("%s - none", s), + Some(ref x) => { ~"something!" + x.say(s) } + } + } +} + + +fn main() { + assert_eq!(3.hi(), ~"hello: 3"); + assert_eq!(Some(Some(3)).hi(), ~"something!something!hello: 3"); + assert_eq!(None::<int>.hi(), ~"hello - none"); + + // These fail because of a bug in monomorphization's ID generation. + //assert_eq!(Some(None::<int>).hi(), ~"something!hello - none"); + //assert_eq!(Some(3).hi(), ~"something!hello: 3"); +} diff --git a/src/test/run-pass/closure-bounds-can-capture-chan.rs b/src/test/run-pass/closure-bounds-can-capture-chan.rs index 26bea0e5141..95b0c9d79b7 100644 --- a/src/test/run-pass/closure-bounds-can-capture-chan.rs +++ b/src/test/run-pass/closure-bounds-can-capture-chan.rs @@ -10,7 +10,7 @@ use std::comm; -fn foo(blk: ~fn:Owned()) { +fn foo(blk: ~fn:Send()) { blk(); } diff --git a/src/test/run-pass/const-bound.rs b/src/test/run-pass/const-bound.rs index 685d86c740d..05f586f76e9 100644 --- a/src/test/run-pass/const-bound.rs +++ b/src/test/run-pass/const-bound.rs @@ -12,7 +12,7 @@ // are const. -fn foo<T:Copy + Const>(x: T) -> T { x } +fn foo<T:Copy + Freeze>(x: T) -> T { x } struct F { field: int } diff --git a/src/test/run-pass/fixed-point-bind-unique.rs b/src/test/run-pass/fixed-point-bind-unique.rs index 53f9c723a47..c7b64fde3fd 100644 --- a/src/test/run-pass/fixed-point-bind-unique.rs +++ b/src/test/run-pass/fixed-point-bind-unique.rs @@ -10,11 +10,11 @@ // xfail-fast -fn fix_help<A:'static,B:Owned>(f: extern fn(@fn(A) -> B, A) -> B, x: A) -> B { +fn fix_help<A:'static,B:Send>(f: extern fn(@fn(A) -> B, A) -> B, x: A) -> B { return f(|a| fix_help(f, a), x); } -fn fix<A:'static,B:Owned>(f: extern fn(@fn(A) -> B, A) -> B) -> @fn(A) -> B { +fn fix<A:'static,B:Send>(f: extern fn(@fn(A) -> B, A) -> B) -> @fn(A) -> B { return |a| fix_help(f, a); } diff --git a/src/test/run-pass/fn-bare-spawn.rs b/src/test/run-pass/fn-bare-spawn.rs index 4f0f451a08c..e9954be9357 100644 --- a/src/test/run-pass/fn-bare-spawn.rs +++ b/src/test/run-pass/fn-bare-spawn.rs @@ -10,7 +10,7 @@ // This is what the signature to spawn should look like with bare functions -fn spawn<T:Owned>(val: T, f: extern fn(T)) { +fn spawn<T:Send>(val: T, f: extern fn(T)) { f(val); } diff --git a/src/test/run-pass/generic-alias-unique.rs b/src/test/run-pass/generic-alias-unique.rs index ad271186639..815cc1bc79b 100644 --- a/src/test/run-pass/generic-alias-unique.rs +++ b/src/test/run-pass/generic-alias-unique.rs @@ -10,7 +10,7 @@ -fn id<T:Copy + Owned>(t: T) -> T { return t; } +fn id<T:Copy + Send>(t: T) -> T { return t; } pub fn main() { let expected = ~100; diff --git a/src/test/run-pass/issue-2611-3.rs b/src/test/run-pass/issue-2611-3.rs index acc6ffd0dd1..7f653552631 100644 --- a/src/test/run-pass/issue-2611-3.rs +++ b/src/test/run-pass/issue-2611-3.rs @@ -12,7 +12,7 @@ // than the traits require. trait A { - fn b<C:Copy + Const,D>(x: C) -> C; + fn b<C:Copy + Freeze,D>(x: C) -> C; } struct E { diff --git a/src/test/run-pass/issue-2718.rs b/src/test/run-pass/issue-2718.rs index 9fbca7d0572..14915555889 100644 --- a/src/test/run-pass/issue-2718.rs +++ b/src/test/run-pass/issue-2718.rs @@ -39,7 +39,7 @@ pub mod pipes { payload: Option<T> } - pub fn packet<T:Owned>() -> *packet<T> { + pub fn packet<T:Send>() -> *packet<T> { unsafe { let p: *packet<T> = cast::transmute(~Stuff{ state: empty, @@ -74,7 +74,7 @@ pub mod pipes { } } - pub fn send<T:Owned>(mut p: send_packet<T>, payload: T) { + pub fn send<T:Send>(mut p: send_packet<T>, payload: T) { let mut p = p.unwrap(); let mut p = unsafe { uniquify(p) }; assert!((*p).payload.is_none()); @@ -100,7 +100,7 @@ pub mod pipes { } } - pub fn recv<T:Owned>(mut p: recv_packet<T>) -> Option<T> { + pub fn recv<T:Send>(mut p: recv_packet<T>) -> Option<T> { let mut p = p.unwrap(); let mut p = unsafe { uniquify(p) }; loop { @@ -120,7 +120,7 @@ pub mod pipes { } } - pub fn sender_terminate<T:Owned>(mut p: *packet<T>) { + pub fn sender_terminate<T:Send>(mut p: *packet<T>) { let mut p = unsafe { uniquify(p) }; match swap_state_rel(&mut (*p).state, terminated) { empty | blocked => { @@ -137,7 +137,7 @@ pub mod pipes { } } - pub fn receiver_terminate<T:Owned>(mut p: *packet<T>) { + pub fn receiver_terminate<T:Send>(mut p: *packet<T>) { let mut p = unsafe { uniquify(p) }; match swap_state_rel(&mut (*p).state, terminated) { empty => { @@ -159,7 +159,7 @@ pub mod pipes { } #[unsafe_destructor] - impl<T:Owned> Drop for send_packet<T> { + impl<T:Send> Drop for send_packet<T> { fn drop(&self) { unsafe { if self.p != None { @@ -172,13 +172,13 @@ pub mod pipes { } } - impl<T:Owned> send_packet<T> { + impl<T:Send> send_packet<T> { pub fn unwrap(&mut self) -> *packet<T> { util::replace(&mut self.p, None).unwrap() } } - pub fn send_packet<T:Owned>(p: *packet<T>) -> send_packet<T> { + pub fn send_packet<T:Send>(p: *packet<T>) -> send_packet<T> { send_packet { p: Some(p) } @@ -189,7 +189,7 @@ pub mod pipes { } #[unsafe_destructor] - impl<T:Owned> Drop for recv_packet<T> { + impl<T:Send> Drop for recv_packet<T> { fn drop(&self) { unsafe { if self.p != None { @@ -202,19 +202,19 @@ pub mod pipes { } } - impl<T:Owned> recv_packet<T> { + impl<T:Send> recv_packet<T> { pub fn unwrap(&mut self) -> *packet<T> { util::replace(&mut self.p, None).unwrap() } } - pub fn recv_packet<T:Owned>(p: *packet<T>) -> recv_packet<T> { + pub fn recv_packet<T:Send>(p: *packet<T>) -> recv_packet<T> { recv_packet { p: Some(p) } } - pub fn entangle<T:Owned>() -> (send_packet<T>, recv_packet<T>) { + pub fn entangle<T:Send>() -> (send_packet<T>, recv_packet<T>) { let p = packet(); (send_packet(p), recv_packet(p)) } diff --git a/src/test/run-pass/issue-2834.rs b/src/test/run-pass/issue-2834.rs index 5d3a2d2331c..b0ddccf2894 100644 --- a/src/test/run-pass/issue-2834.rs +++ b/src/test/run-pass/issue-2834.rs @@ -12,7 +12,7 @@ // proto! streamp ( - open:send<T:Owned> { + open:send<T:Send> { data(T) -> open<T> } ) diff --git a/src/test/run-pass/issue-2930.rs b/src/test/run-pass/issue-2930.rs index cfce19826d7..10a19d62bd9 100644 --- a/src/test/run-pass/issue-2930.rs +++ b/src/test/run-pass/issue-2930.rs @@ -9,7 +9,7 @@ // except according to those terms. proto! stream ( - Stream:send<T:Owned> { + Stream:send<T:Send> { send(T) -> Stream<T> } ) diff --git a/src/test/run-pass/issue-3888-2.rs b/src/test/run-pass/issue-3888-2.rs index 60c50624435..c9f6733fa25 100644 --- a/src/test/run-pass/issue-3888-2.rs +++ b/src/test/run-pass/issue-3888-2.rs @@ -8,12 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::vec; - fn vec_peek<'r, T>(v: &'r [T]) -> &'r [T] { -// This doesn't work, and should. -// v.slice(1, 5) - vec::slice(v, 1, 5) + v.slice(1, 5) } pub fn main() {} diff --git a/src/test/run-pass/issue-5321-immediates-with-bare-self.rs b/src/test/run-pass/issue-5321-immediates-with-bare-self.rs new file mode 100644 index 00000000000..7b809c39cb8 --- /dev/null +++ b/src/test/run-pass/issue-5321-immediates-with-bare-self.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. + +trait Fooable { + fn yes(self); +} + +impl Fooable for uint { + fn yes(self) { + for self.times { + println("yes"); + } + } +} + +fn main() { + 2.yes(); +} diff --git a/src/test/run-pass/istr.rs b/src/test/run-pass/istr.rs index a82b2639449..ab89a357d34 100644 --- a/src/test/run-pass/istr.rs +++ b/src/test/run-pass/istr.rs @@ -44,19 +44,19 @@ fn test_heap_add() { fn test_append() { let mut s = ~""; - s += ~"a"; + s.push_str(~"a"); assert_eq!(s, ~"a"); let mut s = ~"a"; - s += ~"b"; + s.push_str(~"b"); debug!(s.clone()); assert_eq!(s, ~"ab"); let mut s = ~"c"; - s += ~"offee"; + s.push_str(~"offee"); assert!(s == ~"coffee"); - s += ~"&tea"; + s.push_str(~"&tea"); assert!(s == ~"coffee&tea"); } diff --git a/src/test/run-pass/let-destruct-fresh-mem.rs b/src/test/run-pass/let-destruct-fresh-mem.rs index 500502320df..2615396653d 100644 --- a/src/test/run-pass/let-destruct-fresh-mem.rs +++ b/src/test/run-pass/let-destruct-fresh-mem.rs @@ -13,7 +13,9 @@ struct A { a: int } pub fn main() { let u = X {x: 10, y: @A {a: 20}}; - let mut X {x: x, y: @A {a: a}} = u; + let X {x: x, y: @A {a: a}} = u; + let mut x = x; + let mut a = a; x = 100; a = 100; assert_eq!(x, 100); diff --git a/src/test/run-pass/liveness-move-in-loop.rs b/src/test/run-pass/liveness-move-in-loop.rs index acdf388a8ff..d910ac9a4e7 100644 --- a/src/test/run-pass/liveness-move-in-loop.rs +++ b/src/test/run-pass/liveness-move-in-loop.rs @@ -15,7 +15,7 @@ fn the_loop() { loop { let x = 5; if x > 3 { - list += ~[take(x)]; + list.push(take(x)); } else { break; } diff --git a/src/test/run-pass/match-join.rs b/src/test/run-pass/match-join.rs index 66b64768060..5ac62bae392 100644 --- a/src/test/run-pass/match-join.rs +++ b/src/test/run-pass/match-join.rs @@ -23,7 +23,7 @@ fn foo<T>(y: Option<T>) { None::<T> => x = 17, _ => x = 42 } - rs += ~[x]; + rs.push(x); } return; } diff --git a/src/test/run-pass/monad.rs b/src/test/run-pass/monad.rs index 3f3cf5e5aaa..fe06c973dbf 100644 --- a/src/test/run-pass/monad.rs +++ b/src/test/run-pass/monad.rs @@ -19,7 +19,9 @@ trait vec_monad<A> { impl<A> vec_monad<A> for ~[A] { fn bind<B:Copy>(&self, f: &fn(&A) -> ~[B]) -> ~[B] { let mut r = ~[]; - for self.iter().advance |elt| { r += f(elt); } + for self.iter().advance |elt| { + r.push_all_move(f(elt)); + } r } } diff --git a/src/test/run-pass/mutable-alias-vec.rs b/src/test/run-pass/mutable-alias-vec.rs index 1d9e7d3c649..538aedcf7c8 100644 --- a/src/test/run-pass/mutable-alias-vec.rs +++ b/src/test/run-pass/mutable-alias-vec.rs @@ -13,7 +13,9 @@ extern mod extra; use std::vec; -fn grow(v: &mut ~[int]) { *v += ~[1]; } +fn grow(v: &mut ~[int]) { + v.push(1); +} pub fn main() { let mut v: ~[int] = ~[]; diff --git a/src/test/run-pass/once-move-out-on-heap.rs b/src/test/run-pass/once-move-out-on-heap.rs new file mode 100644 index 00000000000..38b23fd128d --- /dev/null +++ b/src/test/run-pass/once-move-out-on-heap.rs @@ -0,0 +1,29 @@ +// 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. + +// Testing guarantees provided by once functions. + +// xfail-fast + +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: ~once fn()) { + blk(); +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); + } +} diff --git a/src/test/run-pass/once-move-out-on-stack.rs b/src/test/run-pass/once-move-out-on-stack.rs new file mode 100644 index 00000000000..e881f576673 --- /dev/null +++ b/src/test/run-pass/once-move-out-on-stack.rs @@ -0,0 +1,30 @@ +// 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. + +// Testing guarantees provided by once functions. + +// xfail-fast + +// compile-flags:-Z once-fns +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: &once fn()) { + blk(); +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); + } +} diff --git a/src/test/run-pass/operator-overloading.rs b/src/test/run-pass/operator-overloading.rs index e75af5729d5..05aa1e74608 100644 --- a/src/test/run-pass/operator-overloading.rs +++ b/src/test/run-pass/operator-overloading.rs @@ -57,7 +57,7 @@ impl cmp::Eq for Point { pub fn main() { let mut p = Point {x: 10, y: 20}; - p += Point {x: 101, y: 102}; + p = p + Point {x: 101, y: 102}; p = p - Point {x: 100, y: 100}; assert_eq!(p + Point {x: 5, y: 5}, Point {x: 16, y: 27}); assert_eq!(-p, Point {x: -11, y: -22}); diff --git a/src/test/run-pass/pipe-bank-proto.rs b/src/test/run-pass/pipe-bank-proto.rs index 7ac38966faa..11c43b93901 100644 --- a/src/test/run-pass/pipe-bank-proto.rs +++ b/src/test/run-pass/pipe-bank-proto.rs @@ -45,8 +45,8 @@ proto! bank ( } ) -fn switch<T:Owned,U>(endp: pipes::RecvPacket<T>, - f: &fn(v: Option<T>) -> U) -> U { +fn switch<T:Send,U>(endp: pipes::RecvPacket<T>, + f: &fn(v: Option<T>) -> U) -> U { f(pipes::try_recv(endp)) } diff --git a/src/test/run-pass/pipe-peek.rs b/src/test/run-pass/pipe-peek.rs index 8d8c96c6f51..cbc822060ce 100644 --- a/src/test/run-pass/pipe-peek.rs +++ b/src/test/run-pass/pipe-peek.rs @@ -22,7 +22,9 @@ proto! oneshot ( ) pub fn main() { - let mut (p, c) = oneshot::init(); + let (p, c) = oneshot::init(); + let mut p = p; + let mut c = c; assert!(!pipes::peek(&mut p)); diff --git a/src/test/run-pass/pipe-select.rs b/src/test/run-pass/pipe-select.rs index 0a860d0a1e2..36f144152f2 100644 --- a/src/test/run-pass/pipe-select.rs +++ b/src/test/run-pass/pipe-select.rs @@ -29,12 +29,12 @@ proto! oneshot ( ) proto! stream ( - Stream:send<T:Owned> { + Stream:send<T:Send> { send(T) -> Stream<T> } ) -pub fn spawn_service<T:Owned,Tb:Owned>( +pub fn spawn_service<T:Send,Tb:Send>( init: extern fn() -> (RecvPacketBuffered<T, Tb>, SendPacketBuffered<T, Tb>), service: ~fn(v: RecvPacketBuffered<T, Tb>)) diff --git a/src/test/run-pass/pipe-sleep.rs b/src/test/run-pass/pipe-sleep.rs index dc88f36ba11..dbf860cd040 100644 --- a/src/test/run-pass/pipe-sleep.rs +++ b/src/test/run-pass/pipe-sleep.rs @@ -33,7 +33,7 @@ endpoint. The send endpoint is returned to the caller and the receive endpoint is passed to the new task. */ -pub fn spawn_service<T:Owned,Tb:Owned>( +pub fn spawn_service<T:Send,Tb:Send>( init: extern fn() -> (RecvPacketBuffered<T, Tb>, SendPacketBuffered<T, Tb>), service: ~fn(v: RecvPacketBuffered<T, Tb>)) diff --git a/src/test/run-pass/send-type-inference.rs b/src/test/run-pass/send-type-inference.rs index bdb1fbaf422..4fcbc789f57 100644 --- a/src/test/run-pass/send-type-inference.rs +++ b/src/test/run-pass/send-type-inference.rs @@ -16,7 +16,7 @@ struct Command<K, V> { val: V } -fn cache_server<K:Owned,V:Owned>(c: Chan<Chan<Command<K, V>>>) { +fn cache_server<K:Send,V:Send>(c: Chan<Chan<Command<K, V>>>) { let (ctrl_port, ctrl_chan) = stream(); c.send(ctrl_chan); } diff --git a/src/test/run-pass/shadow.rs b/src/test/run-pass/shadow.rs index 85575b2ea8b..d0c58b50e2c 100644 --- a/src/test/run-pass/shadow.rs +++ b/src/test/run-pass/shadow.rs @@ -19,7 +19,7 @@ fn foo(c: ~[int]) { for c.iter().advance |i| { debug!(a); let a = 17; - b += ~[a]; + b.push(a); } } _ => { } diff --git a/src/test/run-pass/static-impl.rs b/src/test/run-pass/static-impl.rs index 421cd1d4d0b..0ddc39d6b18 100644 --- a/src/test/run-pass/static-impl.rs +++ b/src/test/run-pass/static-impl.rs @@ -51,7 +51,9 @@ impl<T> vec_utils<T> for ~[T] { fn iter_(&self, f: &fn(&T)) { for self.iter().advance |x| { f(x); } } fn map_<U:Copy>(&self, f: &fn(&T) -> U) -> ~[U] { let mut r = ~[]; - for self.iter().advance |elt| { r += ~[f(elt)]; } + for self.iter().advance |elt| { + r.push(f(elt)); + } r } } diff --git a/src/test/run-pass/str-append.rs b/src/test/run-pass/str-append.rs index 4fdf7dde031..556247eb426 100644 --- a/src/test/run-pass/str-append.rs +++ b/src/test/run-pass/str-append.rs @@ -15,7 +15,7 @@ extern mod extra; fn test1() { let mut s: ~str = ~"hello"; - s += ~"world"; + s.push_str("world"); debug!(s.clone()); assert_eq!(s[9], 'd' as u8); } diff --git a/src/test/run-pass/str-growth.rs b/src/test/run-pass/str-growth.rs index 6938b52eee8..0cdf1841331 100644 --- a/src/test/run-pass/str-growth.rs +++ b/src/test/run-pass/str-growth.rs @@ -12,11 +12,11 @@ pub fn main() { let mut s = ~"a"; - s += ~"b"; + s.push_char('b'); assert_eq!(s[0], 'a' as u8); assert_eq!(s[1], 'b' as u8); - s += ~"c"; - s += ~"d"; + s.push_char('c'); + s.push_char('d'); assert_eq!(s[0], 'a' as u8); assert_eq!(s[1], 'b' as u8); assert_eq!(s[2], 'c' as u8); diff --git a/src/test/run-pass/trait-bounds-basic.rs b/src/test/run-pass/trait-bounds-basic.rs index 5bfbf84d8ac..e0d60d62bb5 100644 --- a/src/test/run-pass/trait-bounds-basic.rs +++ b/src/test/run-pass/trait-bounds-basic.rs @@ -14,14 +14,14 @@ trait Foo { fn a(_x: ~Foo:) { } -fn b(_x: ~Foo:Owned) { +fn b(_x: ~Foo:Send) { } -fn c(x: ~Foo:Const+Owned) { +fn c(x: ~Foo:Freeze+Send) { a(x); } -fn d(x: ~Foo:Owned+Copy) { +fn d(x: ~Foo:Send+Copy) { b(x); } diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 585c2185a7e..a3b2ea02db3 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -9,7 +9,7 @@ // except according to those terms. // Tests that a heterogeneous list of existential types can be put inside an ARC -// and shared between tasks as long as all types fulfill Const+Owned. +// and shared between tasks as long as all types fulfill Freeze+Send. // xfail-fast @@ -64,10 +64,10 @@ fn main() { let dogge1 = Dogge { bark_decibels: 100, tricks_known: 42, name: ~"alan_turing" }; let dogge2 = Dogge { bark_decibels: 55, tricks_known: 11, name: ~"albert_einstein" }; let fishe = Goldfyshe { swim_speed: 998, name: ~"alec_guinness" }; - let arc = arc::ARC(~[~catte as ~Pet:Const+Owned, - ~dogge1 as ~Pet:Const+Owned, - ~fishe as ~Pet:Const+Owned, - ~dogge2 as ~Pet:Const+Owned]); + let arc = arc::ARC(~[~catte as ~Pet:Freeze+Send, + ~dogge1 as ~Pet:Freeze+Send, + ~fishe as ~Pet:Freeze+Send, + ~dogge2 as ~Pet:Freeze+Send]); let (p1,c1) = comm::stream(); let arc1 = cell::Cell::new(arc.clone()); do task::spawn { check_legs(arc1.take()); c1.send(()); } @@ -82,21 +82,21 @@ fn main() { p3.recv(); } -fn check_legs(arc: arc::ARC<~[~Pet:Const+Owned]>) { +fn check_legs(arc: arc::ARC<~[~Pet:Freeze+Send]>) { let mut legs = 0; for arc.get().iter().advance |pet| { legs += pet.num_legs(); } assert!(legs == 12); } -fn check_names(arc: arc::ARC<~[~Pet:Const+Owned]>) { +fn check_names(arc: arc::ARC<~[~Pet:Freeze+Send]>) { for arc.get().iter().advance |pet| { do pet.name |name| { assert!(name[0] == 'a' as u8 && name[1] == 'l' as u8); } } } -fn check_pedigree(arc: arc::ARC<~[~Pet:Const+Owned]>) { +fn check_pedigree(arc: arc::ARC<~[~Pet:Freeze+Send]>) { for arc.get().iter().advance |pet| { assert!(pet.of_good_pedigree()); } diff --git a/src/test/run-pass/trait-default-method-xc.rs b/src/test/run-pass/trait-default-method-xc.rs index e6e5b8605a1..f6c119c4fae 100644 --- a/src/test/run-pass/trait-default-method-xc.rs +++ b/src/test/run-pass/trait-default-method-xc.rs @@ -44,12 +44,12 @@ fn main () { let a = thing { x: 0 }; let b = thing { x: 1 }; - assert_eq!(0i.g(), 10); + //assert_eq!(0i.g(), 10); assert_eq!(a.g(), 10); assert_eq!(a.h(), 10); - assert_eq!(0i.thing(3.14, 1), (3.14, 1)); + //assert_eq!(0i.thing(3.14, 1), (3.14, 1)); assert_eq!(g(0i, 3.14, 1), (3.14, 1)); assert_eq!(g(false, 3.14, 1), (3.14, 1)); @@ -59,8 +59,8 @@ fn main () { // Trying out a real one - assert!(12.test_neq(&10)); - assert!(!10.test_neq(&10)); + //assert!(12.test_neq(&10)); + //assert!(!10.test_neq(&10)); assert!(a.test_neq(&b)); assert!(!a.test_neq(&a)); diff --git a/src/test/run-pass/trait-generic.rs b/src/test/run-pass/trait-generic.rs index dc6bdbf5c1a..5952afa6676 100644 --- a/src/test/run-pass/trait-generic.rs +++ b/src/test/run-pass/trait-generic.rs @@ -33,7 +33,7 @@ impl<T> map<T> for ~[T] { let mut r = ~[]; // FIXME: #7355 generates bad code with Iterator for std::uint::range(0, self.len()) |i| { - r += ~[f(&self[i])]; + r.push(f(&self[i])); } r } diff --git a/src/test/run-pass/trait-with-bounds-default.rs b/src/test/run-pass/trait-with-bounds-default.rs new file mode 100644 index 00000000000..b3ddbbb9dc1 --- /dev/null +++ b/src/test/run-pass/trait-with-bounds-default.rs @@ -0,0 +1,41 @@ +// 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. + +pub trait Clone2 { + /// Returns a copy of the value. The contents of owned pointers + /// are copied to maintain uniqueness, while the contents of + /// managed pointers are not copied. + fn clone(&self) -> Self; +} + +#[allow(default_methods)] +trait Getter<T: Clone> { + fn do_get(&self) -> T; + + fn do_get2(&self) -> (T, T) { + let x = self.do_get(); + (x.clone(), x.clone()) + } + +} + +impl Getter<int> for int { + fn do_get(&self) -> int { *self } +} + +impl<T: Clone> Getter<T> for Option<T> { + fn do_get(&self) -> T { self.get_ref().clone() } +} + + +fn main() { + assert_eq!(3.do_get2(), (3, 3)); + assert_eq!(Some(~"hi").do_get2(), (~"hi", ~"hi")); +} diff --git a/src/test/run-pass/type-param-constraints.rs b/src/test/run-pass/type-param-constraints.rs index 416e7bf82bb..216a7a939fe 100644 --- a/src/test/run-pass/type-param-constraints.rs +++ b/src/test/run-pass/type-param-constraints.rs @@ -12,7 +12,7 @@ fn p_foo<T>(pinned: T) { } fn s_foo<T:Copy>(shared: T) { } -fn u_foo<T:Owned>(unique: T) { } +fn u_foo<T:Send>(unique: T) { } struct r { i: int, diff --git a/src/test/run-pass/unfoldr-cross-crate.rs b/src/test/run-pass/unfoldr-cross-crate.rs index 4e98543ae82..7fcae90a8d1 100644 --- a/src/test/run-pass/unfoldr-cross-crate.rs +++ b/src/test/run-pass/unfoldr-cross-crate.rs @@ -24,7 +24,7 @@ fn main() { } } - let mut it = UnfoldrIterator::new(count, 0); + let mut it = UnfoldrIterator::new(0, count); let mut i = 0; for it.advance |counted| { assert_eq!(counted, i); diff --git a/src/test/run-pass/uniq-cc-generic.rs b/src/test/run-pass/uniq-cc-generic.rs index b54b3b52692..2c3424d1f06 100644 --- a/src/test/run-pass/uniq-cc-generic.rs +++ b/src/test/run-pass/uniq-cc-generic.rs @@ -20,7 +20,7 @@ struct Pointy { d : ~fn() -> uint, } -fn make_uniq_closure<A:Owned + Copy>(a: A) -> ~fn() -> uint { +fn make_uniq_closure<A:Send + Copy>(a: A) -> ~fn() -> uint { let result: ~fn() -> uint = || ptr::to_unsafe_ptr(&a) as uint; result } diff --git a/src/test/run-pass/unique-kinds.rs b/src/test/run-pass/unique-kinds.rs index b3ce71dcbff..391881deff6 100644 --- a/src/test/run-pass/unique-kinds.rs +++ b/src/test/run-pass/unique-kinds.rs @@ -12,11 +12,11 @@ use std::cmp::Eq; fn sendable() { - fn f<T:Owned + Eq>(i: T, j: T) { + fn f<T:Send + Eq>(i: T, j: T) { assert_eq!(i, j); } - fn g<T:Owned + Eq>(i: T, j: T) { + fn g<T:Send + Eq>(i: T, j: T) { assert!(i != j); } diff --git a/src/test/run-pass/vec-growth.rs b/src/test/run-pass/vec-growth.rs index 816228b62c6..c9a4c57cc9d 100644 --- a/src/test/run-pass/vec-growth.rs +++ b/src/test/run-pass/vec-growth.rs @@ -12,10 +12,10 @@ pub fn main() { let mut v = ~[1]; - v += ~[2]; - v += ~[3]; - v += ~[4]; - v += ~[5]; + v.push(2); + v.push(3); + v.push(4); + v.push(5); assert_eq!(v[0], 1); assert_eq!(v[1], 2); assert_eq!(v[2], 3); diff --git a/src/test/run-pass/vec-slice.rs b/src/test/run-pass/vec-slice.rs index 8448e4e0532..e3012b08621 100644 --- a/src/test/run-pass/vec-slice.rs +++ b/src/test/run-pass/vec-slice.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::vec; - pub fn main() { let v = ~[1,2,3,4,5]; - let v2 = vec::slice(v, 1, 3); + let v2 = v.slice(1, 3); assert_eq!(v2[0], 2); assert_eq!(v2[1], 3); } diff --git a/src/test/run-pass/while-prelude-drop.rs b/src/test/run-pass/while-prelude-drop.rs index 082f2db259a..503e37fcd76 100644 --- a/src/test/run-pass/while-prelude-drop.rs +++ b/src/test/run-pass/while-prelude-drop.rs @@ -17,7 +17,7 @@ fn make(i: int) -> t { let mut s = ~"hello"; // Ensure s is non-const. - s += ~"there"; + s.push_str("there"); return b(s); } |
